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

tfry at users.sourceforge.net tfry at users.sourceforge.net
Tue Jun 15 12:05:25 UTC 2010


Revision: 2877
          http://rkward.svn.sourceforge.net/rkward/?rev=2877&view=rev
Author:   tfry
Date:     2010-06-15 12:05:24 +0000 (Tue, 15 Jun 2010)

Log Message:
-----------
Inserting / removing rows seems to work ok with respect to row.names, now.
Changed the storage of RKVariable to be QList based, which allows removal of a bunch of complex code.

Modified Paths:
--------------
    trunk/rkward/rkward/core/rkrownames.cpp
    trunk/rkward/rkward/core/rkrownames.h
    trunk/rkward/rkward/core/rkvariable.cpp
    trunk/rkward/rkward/core/rkvariable.h
    trunk/rkward/rkward/dataeditor/rkvareditmodel.cpp
    trunk/rkward/rkward/main.cpp

Modified: trunk/rkward/rkward/core/rkrownames.cpp
===================================================================
--- trunk/rkward/rkward/core/rkrownames.cpp	2010-06-14 16:31:10 UTC (rev 2876)
+++ trunk/rkward/rkward/core/rkrownames.cpp	2010-06-15 12:05:24 UTC (rev 2877)
@@ -51,7 +51,7 @@
 void RKRowNames::writeData (int from_row, int to_row, RCommandChain *chain) {
 	RK_TRACE (OBJECTS);
 
-	if (is_sequential_up_to_row == getLength ()) {
+	if (isSequential ()) {
 		RKGlobals::rInterface ()->issueCommand (getFullName () + " <- NULL", RCommand::App | RCommand::Sync, QString::null, 0,0, chain);
 
 		ChangeSet *set = new ChangeSet;
@@ -59,32 +59,49 @@
 		set->to_index = to_row;
 		RKGlobals::tracker ()->objectDataChanged (this, set);
 	} else {
-		RKVariable::writeData (from_row, to_row, chain);
+		// unfortunately, we always need to write the whole data, as row.names<- does not support indexing.
+		QString data_string = "c (";
+		for (int row = 0; row < getLength (); ++row) {
+			// TODO: use getCharacter and direct setting of vectors.
+			data_string.append (getRText (row));
+			if (row != (getLength () - 1)) {
+				data_string.append (", ");
+			}
+		}
+		data_string.append (")");
+		RKGlobals::rInterface ()->issueCommand (getFullName () + " <- " + data_string, RCommand::App | RCommand::Sync, QString::null, 0, 0, chain);
 	}
 }
 
 void RKRowNames::setText (int row, const QString &text) {
 	RK_TRACE (OBJECTS);
 
+	lockSyncing (true);
+
 	RKVariable::setText (row, QString());	// don't get in the way of duplicate checking!
 	QString real_text = text;
-	if (real_text.isEmpty ()) real_text = i18n ("new.row");		// empty row names are forbidden
+	if (real_text.isEmpty ()) {
+		if (isSequential ()) {
+			real_text = QString::number (row + 1);
+		} else {
+			real_text = i18n ("new.row");		// empty row names are forbidden
+		}
+	}
 
-	bool is_sequential_number = false;
 	if (is_sequential_up_to_row >= (row - 1)) {
-		bool ok;
-		long num = text.toInt(&ok);
-		if (ok && (QString::number (num) == text)) {
-			is_sequential_number = true;
+		if (real_text == QString::number (row + 1)) {
 			if (makeUnique (&real_text, true)) {
-				is_sequential_up_to_row = row;
+				is_sequential_up_to_row = qMax (row, is_sequential_up_to_row);
 			}
 		}
 	}
 
-	makeUnique (&real_text, false);
+	if (is_sequential_up_to_row < row) {
+		makeUnique (&real_text, false);
+	}
+	RKVariable::setText (row, real_text);
 
-	RKVariable::setText (row, real_text);
+	lockSyncing (false);
 }
 
 bool RKRowNames::makeUnique (QString *text, bool non_sequentials_only) {
@@ -97,7 +114,7 @@
 	for (long i = 0; i < INT_MAX; ++i) {
 		// check whether the text is unique on this iteration
 		bool is_unique = true;
-		for (int row = from_index; row <= getLength (); ++i) {
+		for (int row = from_index; row <= getLength (); ++row) {
 			if (dummy == data->cell_strings[row]) {
 				is_unique = false;
 				break;
@@ -113,16 +130,66 @@
 		}
 
 		// try adjusted text on next iteration
-		QString dummy = *text + '.' + QString::number (i);
+		dummy = *text + '.' + QString::number (i);
 	}
 
 	RK_ASSERT (false);
 	return false;
 }
 
+void RKRowNames::insertRows (int row, int count) {
+	RK_TRACE (OBJECTS);
+
+	lockSyncing (true);
+
+	bool was_sequential = isSequential ();
+	RKVariable::insertRows (row, count);
+
+	if (was_sequential) {	// length just increased
+		is_sequential_up_to_row += count;
+		for (int i = row; i < getLength (); ++i) {
+			data->cell_strings[i] = QString::number (i + 1);
+			data->cell_states[i] = RKVarEditData::Valid;	// was set to NA by RKVariable::insertRows
+		}
+	} else {
+		is_sequential_up_to_row = qMin (is_sequential_up_to_row, row - 1);
+		for (int i = row; i < row + count; ++i) {
+			setText (i, QString ());
+		}
+	}
+	// always need to update. If sequential, rows have just changed. If non-sequential, data needs to be written to backend
+	cellsChanged (row, getLength () - 1);
+
+	lockSyncing (false);
+}
+
+void RKRowNames::removeRows (int from_row, int to_row) {
+	RK_TRACE (OBJECTS);
+
+	lockSyncing (true);
+
+	bool was_sequential = isSequential ();
+	RKVariable::removeRows (from_row, to_row);
+
+	if (was_sequential) {	// length just decreased
+		is_sequential_up_to_row -= (to_row - from_row + 1);
+		for (int i = from_row; i < getLength (); ++i) {
+			data->cell_strings[i] = QString::number (i + 1);
+		}
+	} else {
+		is_sequential_up_to_row = qMin (is_sequential_up_to_row, from_row - 1);
+	}
+
+	// always need to update. If sequential, rows have just changed. If non-sequential, data needs to be written to backend
+	cellsChanged (from_row, getLength () - 1);
+
+	lockSyncing (false);
+}
+
 void RKRowNames::setCharacterFromR (int from_row, int to_row, QString *data) {
 	RK_TRACE (OBJECTS);
 
+	is_sequential_up_to_row = -1;
 	check_duplicates = false;
 	RKVariable::setCharacterFromR (from_row, to_row, data);
 	check_duplicates = true;

Modified: trunk/rkward/rkward/core/rkrownames.h
===================================================================
--- trunk/rkward/rkward/core/rkrownames.h	2010-06-14 16:31:10 UTC (rev 2876)
+++ trunk/rkward/rkward/core/rkrownames.h	2010-06-15 12:05:24 UTC (rev 2877)
@@ -37,6 +37,10 @@
 	void writeData (int from_row, int to_row, RCommandChain *chain=0);
 /** Reimplemented to check, whether the values are all 1:n, custom, or invalid. */
 	void setText (int row, const QString &text);
+/** Reimplemented to also adjust the subsequent row names, if, and only if rownames are 1:n */
+	void removeRows (int from_row, int to_row);
+/** Reimplemented to give the new row and appropriate default name, and to adjust the subsequent row names, if, and only if rownames are 1:n */
+	void insertRows (int row, int count);
 protected:
 /** Reimplemented to disable duplicate checks during the setText() calls within */
 	void setCharacterFromR (int from_row, int to_row, QString *data);
@@ -45,6 +49,7 @@
 	bool makeUnique (QString *text, bool non_sequentials_only);
 	int is_sequential_up_to_row;
 	bool check_duplicates;
+	bool isSequential () { return (is_sequential_up_to_row == (getLength () - 1)); };
 };
 
 #endif

Modified: trunk/rkward/rkward/core/rkvariable.cpp
===================================================================
--- trunk/rkward/rkward/core/rkvariable.cpp	2010-06-14 16:31:10 UTC (rev 2876)
+++ trunk/rkward/rkward/core/rkvariable.cpp	2010-06-15 12:05:24 UTC (rev 2877)
@@ -60,17 +60,14 @@
 
 	// if the variable is currently opened for editing, all values need to be rechecked / resynced
 	if (data) {
-		bool internal_sync = data->immediate_sync;
 		// quick and dirty approach! TODO: make more efficient
 		QStringList list;
 		for (int i=0; i < getLength (); ++i) {
 			list.append (getText (i));
 		}
 
-		if (data->changes) {	// all pending changes are moot
-			delete data->changes;
-			data->changes = 0;
-		}
+		// all pending changes are moot
+		discardUnsyncedChanges ();
 
 		// store what we want to keep of the edit data
 		int num_listeners = data->num_listeners;
@@ -90,7 +87,7 @@
 		data->num_listeners = num_listeners;
 
 		// re-set all data
-		setSyncing (false);
+		lockSyncing (true);
 		int i = 0;
 		for (QStringList::const_iterator it = list.constBegin (); it != list.constEnd (); ++it) {
 			setText (i, *it);
@@ -107,7 +104,7 @@
 
 			syncDataToR ();
 		}
-		setSyncing (internal_sync);
+		lockSyncing (false);
 	} else {
 		setDataType (new_type);
 	}
@@ -128,7 +125,7 @@
 	} else if (command->getFlags () == GET_DATA_COMMAND) {
 		RK_ASSERT (data);
 		// prevent resyncing of data
-		setSyncing (false);
+		lockSyncing (true);
 
 		RK_ASSERT (command->getDataType () == RData::StructureVector);
 		RK_ASSERT (command->getDataLength () == 3);
@@ -152,7 +149,7 @@
 		}
 
 		// now set the data
-		RK_ASSERT (cdata->getDataLength () == (unsigned int) getLength ()); // not a problem due to the line below, I'd still like to know if / when this happens.
+		RK_ASSERT (cdata->getDataLength () == (unsigned int) getLength ()); // not really a problem due to the line below, I'd still like to know if / when this happens.
 		extendToLength (cdata->getDataLength ());
 		if (cdata->getDataType () == RData::StringVector) {
 			setCharacterFromR (0, getLength () - 1, cdata->getStringVector ());
@@ -193,7 +190,8 @@
 		RKGlobals::tracker ()->objectDataChanged (this, set);
 		RKGlobals::tracker ()->objectMetaChanged (this);
 		type -= (type & NeedDataUpdate);
-		setSyncing (true);
+		discardUnsyncedChanges ();
+		lockSyncing (false);
 	} else {
 		RK_ASSERT (false);
 	}
@@ -255,20 +253,20 @@
 	RK_ASSERT (!data);
 	
 	data = new RKVarEditData;
-	data->cell_strings = 0;
-	data->cell_doubles = 0;
-	data->cell_states = 0;
-	data->allocated_length = 0;
-	data->immediate_sync = true;
-	data->changes = 0;
+	data->sync_locks = 0;
 	data->value_labels = 0;
 	data->formatting_options.alignment = FormattingOptions::AlignDefault;
 	data->formatting_options.precision_mode = FormattingOptions::PrecisionDefault;
 	data->formatting_options.precision = 0;
 	data->previously_valid = true;
 	data->num_listeners = 0;
+	discardUnsyncedChanges ();		// initialize
 
-	extendToLength (getLength ());
+	// initialization hack
+	int length = getLength ();
+	dimensions[0] = -1;
+	extendToLength (length);
+	RK_ASSERT (data->cell_states.size () >= getLength ());
 
 	for (int i = 0; i < getLength (); ++i) {
 		data->cell_states[i] = RKVarEditData::NA;
@@ -280,17 +278,8 @@
 
 	RK_ASSERT (data);
 	RK_ASSERT (!(data->num_listeners));
+	RK_ASSERT (data->changes.from_index == -1);
 
-	if (getDataType () == RObject::DataCharacter) {
-		delete [] data->cell_strings;
-		RK_ASSERT (data->cell_doubles == 0);
-	} else {
-		delete [] data->cell_doubles;
-		RK_ASSERT (data->cell_strings == 0);
-	}
-	delete [] data->cell_states;
-
-	RK_ASSERT (!(data->changes));
 	delete data->value_labels;
 	delete data;
 	data = 0;
@@ -305,31 +294,34 @@
 	RKGlobals::rInterface ()->issueCommand (".rk.get.vector.data (" + getFullName () + ')', RCommand::App | RCommand::Sync | RCommand::GetStructuredData, QString::null, this, GET_DATA_COMMAND, chain);
 }
 
-void RKVariable::setSyncing (bool immediate) {
+void RKVariable::lockSyncing (bool lock) {
 	RK_TRACE (OBJECTS);
 	RK_ASSERT (data);
-	
-	data->immediate_sync = immediate;
-	if (!immediate) {
-		if (!data->changes) {
-			data->changes = new ChangeSet;
-			data->changes->from_index = -1;
-			data->changes->to_index = -1;
-		}
-	} else {
-		delete data->changes;
-		data->changes = 0;
+
+	if (lock) data->sync_locks++;
+	else data->sync_locks--;
+	RK_ASSERT (data->sync_locks >= 0);
+
+	if (!(data->sync_locks)) {
+		syncDataToR ();
+		discardUnsyncedChanges ();
 	}
 }
 
+void RKVariable::discardUnsyncedChanges () {
+	RK_TRACE (OBJECTS);
+
+	RK_ASSERT (data);
+	data->changes.from_index = data->changes.to_index = -1;
+}
+
 void RKVariable::syncDataToR () {
 	RK_TRACE (OBJECTS);
-	if (!(data->changes)) return;
+	if (data->changes.from_index == -1) return;
 	
 	// TODO
-	writeData (data->changes->from_index, data->changes->to_index);
-	data->changes->from_index = -1;
-	data->changes->to_index = -1;
+	writeData (data->changes.from_index, data->changes.to_index);
+	discardUnsyncedChanges ();
 }
 
 void RKVariable::restore (RCommandChain *chain) {
@@ -337,7 +329,7 @@
 	RK_ASSERT (data);
 
 	writeData (0, getLength () - 1, chain);
-	delete data->changes;
+	discardUnsyncedChanges ();
 	writeMetaData (chain);
 }
 
@@ -382,12 +374,11 @@
 
 void RKVariable::cellsChanged (int from_row, int to_row) {
 	RK_TRACE (OBJECTS);
-	if (data->immediate_sync) {
+	if (!data->sync_locks) {
 		writeData (from_row, to_row);
 	} else {
-		RK_ASSERT (data->changes);
-		if ((data->changes->from_index > from_row) || (data->changes->from_index == -1)) data->changes->from_index = from_row;
-		if (data->changes->to_index < to_row) data->changes->to_index = to_row;
+		if ((data->changes.from_index > from_row) || (data->changes.from_index == -1)) data->changes.from_index = from_row;
+		if (data->changes.to_index < to_row) data->changes.to_index = to_row;
 	}
 }
 
@@ -395,65 +386,19 @@
 	RK_TRACE (OBJECTS);
 
 	if (length <= 0) length = 1;
-	if (length < (data->allocated_length - 1)) {
-		dimensions[0] = length;
-		return;
-	}
+	int old_length = getLength ();
+	if (length <= old_length) return;
 
-	int ilength = length + 1;		// be a little generous
-	int target = data->allocated_length;
-	if (!target) target = INITIAL_ALLOC;
-	while (target <= ilength) target = target * ALLOC_STEP;
-	RK_DO (qDebug ("resizing from %d to %d", data->allocated_length, target), OBJECTS, DL_DEBUG);
-
-	// allocate new memory and copy
-	if (getDataType () == RObject::DataCharacter) {
-		RK_ASSERT (data->cell_doubles == 0);
-		QString *new_data = new QString[target];
-		if (data->allocated_length) {		// if not yet allocated, don't mem-move
-			memMoveQStrings (new_data, data->cell_strings, data->allocated_length);
-		}
-		delete [] (data->cell_strings);
-		data->cell_strings = new_data;
-	} else {
-		RK_ASSERT (data->cell_strings == 0);
-		double *new_data = new double[target];
-		if (data->allocated_length) {		// if not yet allocated, don't mem-move
-			memmove (new_data, data->cell_doubles, data->allocated_length * sizeof (double));
-		}
-		delete [] (data->cell_doubles);
-		data->cell_doubles = new_data;
+	// pad storage to required list with "unknown" data
+	for (int i=old_length; i < length; ++i) {
+		if (getDataType () == DataCharacter) data->cell_strings.append (QString ());
+		else data->cell_doubles.append (0.0);
+		data->cell_states.append (RKVarEditData::Unknown);
 	}
-	int *new_states = new int[target];
-	if (data->allocated_length) {		// if not yet allocated, don't mem-move
-		memmove (new_states, data->cell_states, data->allocated_length * sizeof (int));
-	}
-	delete [] (data->cell_states);
-	data->cell_states = new_states;
 
-	// set allocated but unused rows to Unknown
-	for (int i=data->allocated_length; i < target; ++i) {
-		data->cell_states[i] = RKVarEditData::Unknown;
-	}
-
-	data->allocated_length = target;
 	dimensions[0] = length;
 }
 
-void RKVariable::downSize () {
-	RK_TRACE (OBJECTS);
-
-	// TODO: downsizing to values other than 0
-	if (getLength () <= 0) {
-		delete [] data->cell_doubles;
-		data->cell_doubles = 0;
-		delete [] data->cell_strings;
-		data->cell_strings = 0;
-		delete [] data->cell_states;
-		data->cell_states = 0;
-	}
-}
-
 QString RKVariable::getText (int row, bool pretty) const {
 	if (row >= getLength ()) {
 		RK_ASSERT (false);
@@ -477,10 +422,10 @@
 	}
 
 	if (getDataType () == DataCharacter) {
-		RK_ASSERT (data->cell_strings != 0);
+		RK_ASSERT (!data->cell_strings.isEmpty ());
 		return (data->cell_strings[row]);
 	} else {
-		RK_ASSERT (data->cell_doubles != 0);
+		RK_ASSERT (!data->cell_doubles.isEmpty ());
 		if (pretty && (data->formatting_options.precision_mode != FormattingOptions::PrecisionDefault)) {
 			if (data->formatting_options.precision_mode == FormattingOptions::PrecisionRequired) {
 				return QString::number (data->cell_doubles[row], 'g', MAX_PRECISION);
@@ -503,11 +448,11 @@
 	} else if (getDataType () == DataCharacter) {
 		return (rQuote (getText (row)));
 	} else if (getDataType () == DataLogical) {
-		RK_ASSERT (data->cell_doubles != 0);
+		RK_ASSERT (!data->cell_doubles.isEmpty ());
 		if (data->cell_doubles[row] == 0) return ("FALSE");
 		else return ("TRUE");
 	} else {
-		RK_ASSERT (data->cell_doubles != 0);
+		RK_ASSERT (!data->cell_doubles.isEmpty ());
 		return (QString::number (data->cell_doubles[row], 'g', MAX_PRECISION));
 	}
 }
@@ -528,11 +473,9 @@
 		data->cell_states[row] |= RKVarEditData::NA;
 	} else {
 		if (getDataType () == DataCharacter) {
-			RK_ASSERT (data->cell_strings != 0);
 			data->cell_strings[row] = text;
 			data->cell_states[row] |= RKVarEditData::Valid;
 		} else if (getDataType () == DataFactor) {
-			RK_ASSERT (data->cell_doubles != 0);
 			if (text.isEmpty ()) {
 				data->cell_states[row] |= RKVarEditData::NA;
 			} else if (data->value_labels && data->value_labels->contains (text)) {
@@ -543,7 +486,6 @@
 				data->cell_states[row] |= RKVarEditData::Invalid | RKVarEditData::UnsyncedInvalidState;
 			}
 		} else {
-			RK_ASSERT (data->cell_doubles != 0);
 			bool ok;
 			if (text.isEmpty ()) {
 				data->cell_states[row] |= RKVarEditData::NA;
@@ -636,19 +578,16 @@
 	RK_TRACE (OBJECTS);
 	RK_ASSERT (to_row < getLength ());
 
-	bool old_sync = data->immediate_sync;
-	setSyncing (false);
+	lockSyncing (true);
 	int i=0;
 	for (int row=from_row; row <= to_row; ++row) {
 		setText (row, txtdata[i++]);
 	}
-	if (old_sync) {
-		syncDataToR ();
-		setSyncing (true);
-	}
+	lockSyncing (false);
 }
 
 RKVariable::Status RKVariable::cellStatus (int row) const {
+	if (row >= getLength ()) return ValueUnknown;
 	if (data->cell_states[row] == RKVarEditData::Unknown) return ValueUnknown;
 	if (data->cell_states[row] & RKVarEditData::NA) return ValueUnused;
 	if (data->cell_states[row] & RKVarEditData::Invalid) return ValueInvalid;
@@ -672,38 +611,30 @@
 		}
 	}
 
-	if (to_row < (data->allocated_length - 1)) {	// not the last rows
-		if (data->cell_strings) {
-			memMoveQStrings (&(data->cell_strings[from_row]), &(data->cell_strings[to_row+1]), (data->allocated_length - to_row - 1));
-		} else {
-			memmove (&(data->cell_doubles[from_row]), &(data->cell_doubles[to_row+1]), (data->allocated_length - to_row - 1) * sizeof (double));
-		}
-		memmove (&(data->cell_states[from_row]), &(data->cell_states[to_row+1]), (data->allocated_length - to_row - 1) * sizeof (int));
+	for (int row = to_row; row >= from_row; --row) {
+		data->cell_states.removeAt (row);
+		if (getDataType () == DataCharacter) data->cell_strings.removeAt (row);
+		else data->cell_doubles.removeAt (row);
 	}
 
-	for (int row = (data->allocated_length - offset); row < data->allocated_length; ++row) {
-		data->cell_states[row] = RKVarEditData::Unknown;
-	}
-
 	for (int i = 0; i < changed_invalids.size (); ++i) {
 		writeInvalidField (changed_invalids[i], 0);
 	}
 
-	dimensions[0] -= offset;	
-	downSize ();
+	dimensions[0] -= offset;
 }
 
 void RKVariable::insertRows (int row, int count) {
 	RK_TRACE (OBJECTS);
-	int old_len = getLength ();
-	extendToLength (getLength () + count);		// getLength is the new length after this!
 
-	for (int i=old_len; i < getLength(); ++i) {
-		data->cell_states[i] = RKVarEditData::NA;
+	for (int i=row; i < row+count; ++i) {
+		data->cell_states.insert (i, RKVarEditData::NA);
+		if (getDataType () == DataCharacter) data->cell_strings.insert (i, QString ());
+		else data->cell_doubles.insert (i, 0.0);
 	}
 
 	QList<int> changed_invalids;
-	for (int i = getLength () - count - 1; i >= row; --i) {
+	for (int i = getLength () - 1; i >= row; --i) {
 		if (data->invalid_fields.contains (i)) {
 			QString dummy = data->invalid_fields.take (i);
 			changed_invalids.append (i);
@@ -712,25 +643,11 @@
 		}
 	}
 
-	if (row >= getLength () && (count == 1)) {		// important special case
-		if (data->cell_strings) data->cell_strings[row+count] = QString::null;
-		if (data->cell_doubles) data->cell_doubles[row+count] = 0.0;
-		data->cell_states[row+count] = RKVarEditData::NA;
-	} else {
-		if (data->cell_strings) {
-			memMoveQStrings (&(data->cell_strings[row+count]), &(data->cell_strings[row]), (data->allocated_length - (row + count) - 1));
-		}
-		if (data->cell_doubles) memmove (&(data->cell_doubles[row+count]), &(data->cell_doubles[row]), (data->allocated_length - (row + count) - 1) * sizeof (double));
-		memmove (&(data->cell_states[row+count]), &(data->cell_states[row]), (data->allocated_length - (row + count) - 1) * sizeof (int));
-	}
-	
-	for (int i=row+count-1; i >= row; --i) {
-		data->cell_states[i] = RKVarEditData::NA;
-	}
-
 	for (int i = 0; i < changed_invalids.size (); ++i) {
 		writeInvalidField (changed_invalids[i], 0);
 	}
+
+	dimensions[0] += count;
 }
 
 RObject::ValueLabels RKVariable::getValueLabels () const {

Modified: trunk/rkward/rkward/core/rkvariable.h
===================================================================
--- trunk/rkward/rkward/core/rkvariable.h	2010-06-14 16:31:10 UTC (rev 2876)
+++ trunk/rkward/rkward/core/rkvariable.h	2010-06-15 12:05:24 UTC (rev 2877)
@@ -17,7 +17,7 @@
 #ifndef RKVARIABLE_H
 #define RKVARIABLE_H
 
-#include <qstring.h>
+#include <QStringList>
 #include <QHash>
 
 #include "robject.h"
@@ -54,7 +54,7 @@
 	enum Status { ValueUnused=0, ValueValid=1, ValueInvalid=2, ValueUnknown=4 };
 
 /** 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);
+	void lockSyncing (bool lock);
 /** syncs pending data changes to the backend */
 	void syncDataToR ();
 /** reimplemented from RObject */
@@ -75,9 +75,9 @@
 	Status cellStatus (int row) const;
 
 /** entirely remove the given rows (i.e. the cells). Will also take care of updating the state (are there any invalid cells left?). Does not sync with the backend for technical reasons! You have to remove the row in the backend explicitly. */
-	void removeRows (int from_row, int to_row);
+	virtual void removeRows (int from_row, int to_row);
 /** inserts count rows (with empty values) just above the given index. Does not sync with the backend for technical reasons! You have to insert the row in the backend explicitly. */
-	void insertRows (int row, int count);
+	virtual void insertRows (int row, int count);
 /** Tells the object it has (data) length len. Usually this will only be called directly after creating a new object */
 	void setLength (int len);
 
@@ -127,6 +127,8 @@
 /** inverse of parseFormattingOptionsString () */
 	static QString formattingOptionsToString (const FormattingOptions& options);
 protected:
+/** Discards pending unsynced changes. */
+	void discardUnsyncedChanges ();
 /** 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. Code may assume that all data comes directly from R, is entirely valid in R. */
 	virtual void setCharacterFromR (int from_row, int to_row, QString *data);
 /** 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. Code may assume that all data comes directly from R, is entirely valid in R. */
@@ -135,8 +137,8 @@
 	bool updateType (RData *new_data);
 /** Extended from RObject::EditData to actually contain data. */
 	struct RKVarEditData {
-		QString *cell_strings;
-		double *cell_doubles;
+		QStringList cell_strings;
+		QList<double> cell_doubles;
 		enum CellState {
 			Unknown=0,
 			Invalid=1,
@@ -144,14 +146,12 @@
 			Valid=4,
 			UnsyncedInvalidState=8
 		};
-		int *cell_states;
+		QList<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;
 /// see setSyncing
-		bool immediate_sync;
+		int sync_locks;
 /// stores changes if syncing is not immediate
-		ChangeSet *changes;
+		ChangeSet changes;
 /// 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. TODO: Should this be made a regular (non-pointer) member, or is the saved mem really worth the trouble? */
@@ -177,7 +177,7 @@
 /** takes care of syncing the given range of cells */
 	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);
+	virtual void writeData (int from_row, int to_row, RCommandChain *chain=0);
 	void writeInvalidField (int row, RCommandChain *chain=0);
 /** writes the values labels to the backend */
 	void writeValueLabels (RCommandChain *chain) const;
@@ -188,19 +188,6 @@
 	void allocateEditData ();
 /** discard edit data */
 	void discardEditData ();
-
-/** TODO: QStrings can't be memmoved. We should use QVector/QList instead. */
-	void memMoveQStrings (QString *dst, QString *src, int count) {
-		if (dst > src) {
-			for (int i = count - 1; i >= 0; --i) {
-				dst[i] = src[i];
-			}
-		} else {
-			for (int i = 0; i < count; ++i) {
-				dst[i] = src[i];
-			}
-		}
-	};
 /////////////////// END: data-handling //////////////////////
 };
 

Modified: trunk/rkward/rkward/dataeditor/rkvareditmodel.cpp
===================================================================
--- trunk/rkward/rkward/dataeditor/rkvareditmodel.cpp	2010-06-14 16:31:10 UTC (rev 2876)
+++ trunk/rkward/rkward/dataeditor/rkvareditmodel.cpp	2010-06-15 12:05:24 UTC (rev 2877)
@@ -140,12 +140,12 @@
 	RK_ASSERT (lastrow >= row);
 
 	beginInsertRows (QModelIndex (), row, row+count-1);
+	doInsertRowsInBackend (row, count);
 	for (int i=0; i < objects.size (); ++i) {
 // TODO: this does not emit any data change notifications to other editors
 		objects[i]->insertRows (row, count);
 	}
 	rownames->insertRows (row, count);
-	doInsertRowsInBackend (row, count);
 	endInsertRows ();
 
 	return true;
@@ -164,11 +164,12 @@
 	RK_ASSERT (lastrow >= row);
 
 	beginRemoveRows (QModelIndex (), row, lastrow);
+	doRemoveRowsInBackend (row, lastrow - row + 1);
 	for (int i=0; i < objects.size (); ++i) {
 // TODO: this does not emit any data change notifications to other editors
 		objects[i]->removeRows (row, lastrow);
 	}
-	doRemoveRowsInBackend (row, lastrow - row + 1);
+	rownames->removeRows (row, lastrow);
 	endRemoveRows ();
 
 	return true;
@@ -639,11 +640,11 @@
 
 	for (int col = left; col <= right; ++col) {
 		RKVariable* var = data_model->objects[col];
-		var->setSyncing (false);
+		var->lockSyncing (true);
 		for (int row = top; row <= bottom; ++row) {
 			setData (createIndex (row, col), QString (), Qt::EditRole);
 		}
-		var->setSyncing (true);
+		var->lockSyncing (false);
 	}
 }
 
@@ -672,13 +673,12 @@
 	for (int col = left; col <= right; ++col) {
 		int trow = 0;
 		RKVariable* var = data_model->objects[col];
-		var->setSyncing (false);
+		var->lockSyncing (true);
 		for (int row = top; row <= bottom; ++row) {
 			setData (index (row, col), text.getText (trow, tcol), Qt::EditRole);
 			++trow;
 		}
-		var->syncDataToR ();
-		var->setSyncing (true);
+		var->lockSyncing (false);
 		++tcol;
 	}
 }
@@ -705,6 +705,7 @@
 		RObject* child = df->createPendingChild (df->validizeName (QString ()), -1, false, false);
 		RK_ASSERT (child->isVariable ());
 	}
+#warning: TODO: properly initialize the rownames!
 
 	init (df);
 

Modified: trunk/rkward/rkward/main.cpp
===================================================================
--- trunk/rkward/rkward/main.cpp	2010-06-14 16:31:10 UTC (rev 2876)
+++ trunk/rkward/rkward/main.cpp	2010-06-15 12:05:24 UTC (rev 2877)
@@ -86,6 +86,7 @@
 	}
 	RKSettingsModuleDebug::debug_file->write (msg);
 	RKSettingsModuleDebug::debug_file->write ("\n");
+	RKSettingsModuleDebug::debug_file->flush ();
 }
 
 int main(int argc, char *argv[]) {


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