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

tfry at users.sourceforge.net tfry at users.sourceforge.net
Fri May 25 15:34:42 UTC 2012


Revision: 4264
          http://rkward.svn.sourceforge.net/rkward/?rev=4264&view=rev
Author:   tfry
Date:     2012-05-25 15:34:41 +0000 (Fri, 25 May 2012)
Log Message:
-----------
Sigh... RKOptionset needs more complexity to handle embedded plugins. Work in progress.
The problem is that embedded plugins are not 'ready' immediately.

Modified Paths:
--------------
    trunk/rkward/rkward/plugin/rkoptionset.cpp
    trunk/rkward/rkward/plugin/rkoptionset.h

Modified: trunk/rkward/rkward/plugin/rkoptionset.cpp
===================================================================
--- trunk/rkward/rkward/plugin/rkoptionset.cpp	2012-05-25 15:34:23 UTC (rev 4263)
+++ trunk/rkward/rkward/plugin/rkoptionset.cpp	2012-05-25 15:34:41 UTC (rev 4264)
@@ -37,7 +37,7 @@
 
 	XMLHelper *xml = XMLHelper::getStaticHelper ();
 	updating_from_contents = updating_from_storage = false;
-	connect (&update_timer, SIGNAL (timeout()), this, SLOT (updateContents()));
+	connect (&update_timer, SIGNAL (timeout()), this, SLOT (updateStatusAndDisplay()));
 	update_timer.setSingleShot (true);
 	update_timer.setInterval (0);
 
@@ -160,6 +160,7 @@
 
 RKOptionSet::~RKOptionSet () {
 	RK_TRACE (PLUGIN);
+qDebug ("Optionset deleted");
 }
 
 RKComponent *RKOptionSet::createDisplay (bool show_index, QWidget *parent) {
@@ -248,13 +249,14 @@
 		RK_ASSERT (false);
 		return;
 	}
+	unfinished_rows.insert (row);
 
 	QList<RKComponentPropertyStringList *> cols = columns_to_update.values (property);
 	QTreeWidgetItem *display_item = 0;
 	if (display) display_item = display->topLevelItem (row);
 	for (int i = 0; i < cols.size (); ++i) {
 		RKComponentPropertyStringList *target = cols.at (i);
-		const ColumnInfo &inf = column_map[target];
+		ColumnInfo &inf = column_map[target];
 		QString value = property->value (inf.governor_modifier);
 		target->setValueAt (row, value);
 
@@ -262,7 +264,7 @@
 			display_item->setText (inf.display_index, value);
 		}
 
-		if (target == keycolumn) old_keys = keycolumn->values ();
+		inf.old_values = target->values ();
 	}
 
 	updating_from_contents = false;
@@ -273,114 +275,113 @@
 	RK_TRACE (PLUGIN);
 
 	if (updating_from_contents) return;
-	int activate_row = current_row->intValue ();
-	
+
 	RKComponentPropertyStringList *target = static_cast<RKComponentPropertyStringList *> (property);
 	RK_ASSERT (column_map.contains (target));
-	const ColumnInfo &inf = column_map[target];
-	if (display && (inf.display_index >= 0)) {
-		QStringList values = target->values ();
-		while (display->topLevelItemCount () != values.size ()) {
-			// row count has changed. Ultimately, this means, all values will be updated, so a crude adjustment
-			// of row count is good enough, here
-			if (values.size () > display->topLevelItemCount ()) {
-				display->addTopLevelItem (new QTreeWidgetItem (QStringList ()));
-				activate_row = values.size () - 1;
-			} else {
-				delete (display->takeTopLevelItem (0));
-				activate_row = qMax (values.size (), activate_row);
-			}
-		}
-		for (int row = 0; row < values.size (); ++row) {
-			QTreeWidgetItem *item = display->topLevelItem (row);
-			if (item) item->setText (inf.display_index, values[row]);
-			else RK_ASSERT (false);
-		}
-	}
-	if (inf.restorable) update_timer.start ();
+	update_timer.start ();
 
 	if (target == keycolumn) {
-		QStringList new_keys = target->values ();;
-		QMap<int, int> position_changes;
+		handleKeycolumnUpdate ();
+	} else {
+		columns_which_have_been_updated_externally.insert (target);
+	}
+}
 
-		for (int new_pos = 0; new_pos < new_keys.size (); ++new_pos) {
-			QString key = new_keys[new_pos];
-			if (old_keys.value (new_pos) != key) {	// NOTE: old_keys could be shorter than new_keys!
-				int old_pos = old_keys.indexOf (key);	// NOTE: -1 for key no longer present
-				position_changes.insert (new_pos, old_pos);
-			}
-		}
+void RKOptionSet::handleKeycolumnUpdate () {
+	RK_TRACE (PLUGIN);
 
-		if (position_changes.isEmpty () && (old_keys.size () == new_keys.size ())) {
-			columns_which_have_been_updated_externally.clear ();
-			return;	// no change
+	int activate_row = current_row->intValue ();
+	QStringList new_keys = keycolumn->values ();
+	QStringList old_keys = column_map[keycolumn].old_values;
+	QMap<int, int> position_changes;
+
+	int pos;
+	for (pos = 0; pos < new_keys.size (); ++pos) {
+		QString key = new_keys[pos];
+		if (old_keys.value (pos) != key) {	// NOTE: old_keys could be shorter than new_keys!
+			int old_pos = old_keys.indexOf (key);	// NOTE: -1 for key no longer present
+			position_changes.insert (pos, old_pos);
 		}
+	}
+	for (; pos < old_keys.size (); ++pos) {
+		invalid_rows.remove (pos);
+		unfinished_rows.remove (pos);
+	}
 
-		QMap<RKComponentPropertyStringList *, ColumnInfo>::const_iterator it = column_map.constBegin ();
-		for (; it != column_map.constEnd (); ++it) {
-			RKComponentPropertyStringList* col = it.key ();
-			const ColumnInfo &column = it.value ();
-			if (columns_which_have_been_updated_externally.contains (col) || col == keycolumn) {
-				continue;
-			}
+	if (position_changes.isEmpty () && (old_keys.size () == new_keys.size ())) {
+		columns_which_have_been_updated_externally.clear ();
+		return;	// no change
+	}
 
-			// Ok, we'll have to adjust this column. We start by copying the old values, and padding to the
-			// new length (if that is greater than the old).
-			QStringList old_values = col->values ();
-			QStringList new_values = old_values;
-			for (int i = (new_keys.size () - new_values.size ()); i > 0; --i) new_values.append (QString ());
+	// update all columns
+	QMap<RKComponentPropertyStringList *, ColumnInfo>::iterator it = column_map.begin ();
+	for (; it != column_map.end (); ++it) {
+		RKComponentPropertyStringList* col = it.key ();
+		ColumnInfo &column = it.value ();
+		if (col == keycolumn) continue;
 
-			// adjust all positions that have changed
-			for (int pos = 0; pos < new_keys.size (); ++pos) {
-				QMap<int, int>::const_iterator pit = position_changes.find (pos);
-				if (pit != position_changes.constEnd ()) {	// some change
-					int old_pos = pit.value ();
-					if (old_pos < 0) {	// a new key
-						new_values[pos] = getDefaultValue (column, pos);
-						activate_row = pos;
-					} else {	// old key changed position
-						new_values[pos] = old_values[old_pos];
-					}
-				}
+		// Ok, we'll have to adjust this column. We start by copying the old values, and padding to the
+		// new length (if that is greater than the old).
+		QStringList old_values = column.old_values;
+		QStringList new_values = old_values;
+		for (int i = (new_keys.size () - new_values.size ()); i > 0; --i) new_values.append (QString ());
+
+		// adjust all positions that have changed
+		for (int pos = 0; pos < new_keys.size (); ++pos) {
+			QMap<int, int>::const_iterator pit = position_changes.find (pos);
+			if (pit != position_changes.constEnd ()) {	// some change
+				int old_pos = pit.value ();
+				if (old_pos < 0) {	// a new key
+					new_values[pos] = getDefaultValue (column, pos);
+					activate_row = pos;
+				} else {	// old key changed position
+					new_values[pos] = old_values[old_pos];
+				} // NOTE: not visible: old key is gone without replacement
 			}
-
-			// strip excess length (if any), and apply
-			new_values = new_values.mid (0, new_keys.size ());
-			col->setValues (new_values);
-			// NOTE: this will recurse into the current function, triggering an update of display and contents
 		}
 
-		columns_which_have_been_updated_externally.clear ();
-		old_keys = new_keys;
+		// strip excess length (if any), and apply
+		new_values = new_values.mid (0, new_keys.size ());
+		column.old_values = new_values;		// Because these were not actually changed, but merely re-sorted!
+		if (!columns_which_have_been_updated_externally.contains (col)) col->setValues (new_values);
+	}
 
-		int nrows = new_keys.size ();
-		row_count->setIntValue (nrows);
-	} else {
-		if (!columns_which_have_been_updated_externally.isEmpty ()) {	// add clearing timer for the first entry, only
-			update_timer.start ();		 // NOTE: only has an effect, if column is neither restorable nor shown in the display. Otherwise, an update has already been triggered
+	// update status info
+	QSet<int> new_unfinished_rows;
+	QSet<int> new_invalid_rows;
+	for (int pos = 0; pos < new_keys.size (); ++pos) {
+		QMap<int, int>::const_iterator pit = position_changes.find (pos);
+		if (pit != position_changes.constEnd ()) {	// some change
+			int old_pos = pit.value ();
+			if (old_pos < 0) {	// a new key
+				new_unfinished_rows.insert (pos);
+			} else {	// old key changed position
+				if (unfinished_rows.contains (old_pos)) new_unfinished_rows.insert (pos);
+				if (invalid_rows.contains (old_pos)) new_invalid_rows.insert (pos);
+			} // NOTE: not visible: old key is gone without replacement
 		}
-		columns_which_have_been_updated_externally.insert (target);
 	}
+	unfinished_rows = new_unfinished_rows;
+	invalid_rows = new_invalid_rows;
 
+	columns_which_have_been_updated_externally.clear ();
+	column_map[keycolumn].old_values = new_keys;
+
+	int nrows = new_keys.size ();
+	row_count->setIntValue (nrows);
+	activate_row = qMax (new_keys.size () - 1, activate_row);
 	current_row->setIntValue (activate_row);
 }
 
-void RKOptionSet::updateContents () {
+void RKOptionSet::setContentsForRow (int row) {
 	RK_TRACE (PLUGIN);
-	columns_which_have_been_updated_externally.clear ();
 
-	RK_ASSERT (!updating_from_contents);
-	RK_ASSERT (!updating_from_storage);
-	updating_from_storage = true;
-
-	int count = -1;
-	int row = current_row->intValue ();
 	QMap<RKComponentPropertyStringList *, ColumnInfo>::const_iterator it = column_map.constBegin ();
-	if (it != column_map.constEnd ()) count = it.key ()->values ().size ();
 	for (; it != column_map.constEnd (); ++it) {
 		RKComponentPropertyStringList* col = it.key ();
 		const ColumnInfo &ci = it.value ();
 		if (!ci.restorable) continue;
+
 		QString dummy;
 		RKComponentBase *governor = contents_container->lookupComponent (ci.governor, &dummy);
 		if (governor && governor->isProperty ()) {
@@ -392,15 +393,67 @@
 
 			static_cast<RKComponentPropertyBase*> (governor)->setValue (value);
 		} else {
-			RK_DO (qDebug ("Lookup error with trying to restore row %d of optionset: %s. Remainder: %s", row, qPrintable (ci.governor), qPrintable (dummy)), PLUGIN, DL_WARNING);
+			RK_DO (qDebug ("Lookup error while trying to restore row %d of optionset: %s. Remainder: %s", row, qPrintable (ci.governor), qPrintable (dummy)), PLUGIN, DL_WARNING);
 			RK_ASSERT (false);
 		}
 	}
+}
 
+void RKOptionSet::updateStatusAndDisplay () {
+	RK_TRACE (PLUGIN);
+#warning TODO: way too many updates are going on
+qDebug ("Optionset update");
+	columns_which_have_been_updated_externally.clear ();
+
+	RK_ASSERT (!updating_from_contents);
+	RK_ASSERT (!updating_from_storage);
+	updating_from_storage = true;
+
+	int count = -1;
+	int activate_row = current_row->intValue ();
+	QMap<RKComponentPropertyStringList *, ColumnInfo>::iterator it = column_map.begin ();
+
+	// first make sure the display has correct number of rows
+	if (it != column_map.end ()) count = it.key ()->values ().size ();
+	if (display) {
+		while (display->topLevelItemCount () != count) {
+			if (count > display->topLevelItemCount ()) {
+				display->addTopLevelItem (new QTreeWidgetItem (QStringList ()));
+				activate_row = count - 1;
+			} else {
+				delete (display->takeTopLevelItem (0));
+				activate_row = qMax (count - 1, activate_row);
+			}
+		}
+	}
+
+	// now check for any changed values, updating display and row status
+	for (; it != column_map.end (); ++it) {
+		RKComponentPropertyStringList* col = it.key ();
+		ColumnInfo &ci = it.value ();
+
+		QStringList values = col->values ();
+		for (int row = values.size () - 1; row >= 0; --row) {
+			if (display && (ci.display_index >= 0)) {	// NOTE: Updating the display is done for all rows, even seemingly unchanged ones. Rows may still have been shuffled to a new position, and we did not keep track of that.
+				display->topLevelItem (row)->setText (ci.display_index, values[row]);
+			}
+
+			// NOTE: However, internal status info should have been adjusted to the new indices, already
+			if (values[row] != ci.old_values.value (row)) {
+				unfinished_rows.insert (row);
+			}
+		}
+		ci.old_values = values;
+	}
+
+#warning TODO: duplicate update
+	current_row->setIntValue (activate_row);
+	setContentsForRow (activate_row);
+
 	row_count->setIntValue (count);
-	contents_container->enablednessProperty ()->setBoolValue (row >= 0);
+	contents_container->enablednessProperty ()->setBoolValue (activate_row >= 0);
 	updateVisuals ();
-	changed ();	// needed, for the unlikely case that no change notification was triggered above, since isValid() returns false while updating
+	changed ();	// needed, for the unlikely case that no change notification was triggered above, since recursiveStatus() returns Processing while updating
 
 	updating_from_storage = false;
 }
@@ -451,8 +504,20 @@
 	// --> currentRowPropertyChanged ()
 }
 
+/** reimplemented from RKComponent */
+RKComponent::ComponentStatus RKOptionSet::recursiveStatus () {
+	RK_TRACE (PLUGIN);
+
+	ComponentStatus s = RKComponent::recursiveStatus ();
+	if (s == Dead) return s;
+#warning TODO
+//	if (!unfinished_rows.isEmpty ()) return Processing;
+//	if (update_timer.isActive ()) return Processing;
+	return s;
+}
+
 bool RKOptionSet::isValid () {
-	if (update_timer.isActive ()) return (false);	// actually, this signifies "processing" state
+	if (!invalid_rows.isEmpty ()) return false;
 	int count = row_count->intValue ();
 	if (count < min_rows) return false;
 	if ((count > 0) && (count < min_rows_if_any)) return false;

Modified: trunk/rkward/rkward/plugin/rkoptionset.h
===================================================================
--- trunk/rkward/rkward/plugin/rkoptionset.h	2012-05-25 15:34:23 UTC (rev 4263)
+++ trunk/rkward/rkward/plugin/rkoptionset.h	2012-05-25 15:34:41 UTC (rev 4264)
@@ -40,22 +40,28 @@
 	int type () { return ComponentOptionSet; };
 	RKComponent *createDisplay (bool show_index, QWidget *parent);
 	bool isValid ();
+	/** reimplemented from RKComponent */
+	ComponentStatus recursiveStatus ();
 private slots:
 	void governingPropertyChanged (RKComponentPropertyBase *property);
 	void columnPropertyChanged (RKComponentPropertyBase *property);
 	void currentRowPropertyChanged (RKComponentPropertyBase *property);
 	void addRow ();
 	void removeRow ();
-	void updateContents ();
+	void updateStatusAndDisplay ();
 	void currentRowChanged (QTreeWidgetItem *item);
 private:
 	void initDisplay ();
 	void updateVisuals ();
 
+	RKComponentPropertyInt *current_row;
+	RKComponentPropertyInt *row_count;
+
 /** for option sets which are "driven" (i.e. the user cannot simply add / remove rows, directly), this holds the key column, controlling addition / removal of rows in the set.
   * if this length (or order) is changed in this row, it will also be changed in the other rows. */
 	RKComponentPropertyStringList *keycolumn;
-	QStringList old_keys;
+
+	/** Map of properties (in the contents region) to columns which need to be updated, when the property changes. */
 	QMultiMap<RKComponentPropertyBase *, RKComponentPropertyStringList *> columns_to_update;
 	struct ColumnInfo {
 		QString column_name;
@@ -65,16 +71,21 @@
 		QString default_value;
 		int display_index;
 		bool restorable;
+		QStringList old_values;
 	};
+	/** Map of all columns to their meta info */
 	QMap<RKComponentPropertyStringList *, ColumnInfo> column_map;
+	/** Rows which have been not yet been processed, fully */
+	QSet<int> unfinished_rows;
+	/** Rows which have been fully processed but were invalid (contents component was not satisfied) */
+	QSet<int> invalid_rows;
+
 	RKComponent *contents_container;
 	QTreeWidget *display;
 	QWidget *display_buttons;
 	QPushButton *remove_button;
 	QPushButton *add_button;
 	bool display_show_index;
-	RKComponentPropertyInt *current_row;
-	RKComponentPropertyInt *row_count;
 	QTimer update_timer;
 
 	int min_rows;
@@ -83,8 +94,14 @@
 
 	bool updating_from_contents;
 	bool updating_from_storage;
+/** When keys in the key column change, all other columns have to be updated, accordingly. */
+	void handleKeycolumnUpdate ();
+/** Sets the contents from the values in given row */
+	void setContentsForRow (int row);
+/** Columns which have already been updated before an update of the keycolumn, and thus do not need re-sorting, if the keycolumn is updated */
 	QSet<RKComponentPropertyStringList *> columns_which_have_been_updated_externally;
 
+/** get the default value for the given column, row. */
 	friend QString getDefaultValue (const ColumnInfo& ci, int row);
 };
 

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