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

tfry at users.sourceforge.net tfry at users.sourceforge.net
Fri Nov 9 18:37:30 UTC 2012


Revision: 4427
          http://rkward.svn.sourceforge.net/rkward/?rev=4427&view=rev
Author:   tfry
Date:     2012-11-09 18:37:30 +0000 (Fri, 09 Nov 2012)
Log Message:
-----------
Trying to simplify optionset code (work in progress). Two main changes:
- Split out display related code (to be provided by RKOptionSetDisplayModel)
- Specific columns can either be controlled externally (currently this is still mis-labelled "restorable"), or driven by the option set's contents. Never both at once.

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

Modified: trunk/rkward/rkward/plugin/rkcomponent.h
===================================================================
--- trunk/rkward/rkward/plugin/rkcomponent.h	2012-11-09 14:40:32 UTC (rev 4426)
+++ trunk/rkward/rkward/plugin/rkcomponent.h	2012-11-09 18:37:30 UTC (rev 4427)
@@ -117,6 +117,7 @@
 	void setInternal (bool internal) { is_internal = internal; };
 	bool isInternal () const { return is_internal; };
 protected:
+friend class RKOptionSet;
 	QHash<QString, RKComponentBase*> child_map;
 	bool required;
 /** recursively fetch the current values of all properties present as direct or indirect children of this component. Used to transfer values e.g. when switching interfaces (or to store settings per plugin in the future). Values are placed in the dictionary provided (be sure to create one first!). Internal properties are ignored (@see RKComponentPropertyBase::isInternal ());

Modified: trunk/rkward/rkward/plugin/rkoptionset.cpp
===================================================================
--- trunk/rkward/rkward/plugin/rkoptionset.cpp	2012-11-09 14:40:32 UTC (rev 4426)
+++ trunk/rkward/rkward/plugin/rkoptionset.cpp	2012-11-09 18:37:30 UTC (rev 4427)
@@ -37,9 +37,7 @@
 
 	XMLHelper *xml = XMLHelper::getStaticHelper ();
 	updating_from_contents = updating_from_storage = false;
-	connect (&update_timer, SIGNAL (timeout()), this, SLOT (updateStatusAndDisplay()));
-	update_timer.setSingleShot (true);
-	update_timer.setInterval (0);
+	last_known_status = Processing;
 
 	min_rows = xml->getIntAttribute (element, "min_rows", 0, DL_INFO);
 	min_rows_if_any = xml->getIntAttribute (element, "min_rows_if_any", 1, DL_INFO);
@@ -66,6 +64,7 @@
 	builder->buildElement (xml->getChildElement (element, "content", DL_ERROR), contents_box, false);	// NOTE that parent widget != parent component, here, by intention. The point is that the display should not be disabled along with the contents
 	builder->makeConnections ();
 	addChild ("contents", contents_container);
+	contents_container->fetchPropertyValuesRecursive (&default_row_state);
 
 	// create columns
 	XMLChildList options = xml->getChildElements (element, "option", DL_WARNING);
@@ -88,6 +87,7 @@
 		col_inf.restorable = restorable;
 		col_inf.governor = governor;
 #warning TODO: Do we have to wait for the parent component to settle before (re-)fetching defaults?
+#warning -------------- TODO ------------- Don't store defaults per column. Use only implicit defaults, instead.
 		if (e.hasAttribute ("default")) col_inf.default_value = xml->getStringAttribute (e, "default", QString (), DL_ERROR);
 		else if (!governor.isEmpty ()) col_inf.default_value = contents_container->fetchStringValue (governor);
 		if (!label.isEmpty ()) {
@@ -111,6 +111,9 @@
 		if (!column_map.contains (keycolumn)) {
 			RK_DO (qDebug ("optionset does not contain a column named %s. Falling back to manual insertion mode", qPrintable (keycol)), PLUGIN, DL_ERROR);
 			keycolumn = 0;
+		} else if (!column_map[keycolumn].restorable) {
+			RK_DO (qDebug ("keycolumn (%s) is not marked as restorable. Falling back to manual insertion mode", qPrintable (keycol)), PLUGIN, DL_ERROR);
+			keycolumn = 0;
 		}
 	}
 
@@ -141,13 +144,14 @@
 	}
 
 	if (display) {		// may or may not have been created
-		display->setColumnCount (visible_column_labels.size ());
-		display->setHeaderLabels (visible_column_labels);
+		model->column_labels = visible_column_labels;
 		display->setItemsExpandable (false);
 		display->setRootIsDecorated (false);
 		if (display_show_index) display->resizeColumnToContents (0);
 		else display->setColumnHidden (0, true);
-		connect (display, SIGNAL (currentItemChanged (QTreeWidgetItem*, QTreeWidgetItem*)), this, SLOT (currentRowChanged (QTreeWidgetItem*)));
+		model = new RKOptionSetDisplayModel (this);
+		display->setModel (model);
+		connect (display, SIGNAL (rowChanged(int)), this, SLOT (currentRowChanged (int)));
 
 		if (keycolumn) display_buttons->setVisible (false);
 		else {
@@ -157,7 +161,7 @@
 	}
 
 	n_invalid_rows = n_unfinished_rows = 0;
-	update_timer.start ();
+	updateVisuals ();
 }
 
 RKOptionSet::~RKOptionSet () {
@@ -176,7 +180,7 @@
 	if (display) {
 		RK_DO (qDebug ("cannot create more than one optiondisplay per optionset"), PLUGIN, DL_ERROR);
 	} else {
-		display = new QTreeWidget (box);
+		display = new QTreeView (box);
 		display_show_index = show_index;
 	}
 
@@ -196,7 +200,9 @@
 	int row = active_row + 1;	// append feels more natural than insert, here
 	int nrows = rowCount ();
 	if (row <= 0) row = nrows;
+	RK_ASSERT (!keycolumn);
 
+	if (display) model->beginInsertRows (QModelIndex (), row, row);
 	// adjust values
 	QMap<RKComponentPropertyStringList *, ColumnInfo>::iterator it = column_map.begin ();
 	for (; it != column_map.end (); ++it) {
@@ -205,10 +211,10 @@
 		QStringList values = col->values ();
 		values.insert (row, getDefaultValue (column, row));
 		col->setValues (values);
-		column.old_values = values;
 	}
+
 	// adjust status info
-	RowInfo ri;
+	RowInfo ri (default_row_state);
 	ri.valid = false;
 	ri.finished = false;
 	rows.insert (row, ri);
@@ -217,6 +223,7 @@
 
 	row_count->setIntValue (nrows + 1);
 	current_row->setIntValue (active_row = row);
+	if (display) model->endInsertRows ();
 }
 
 void RKOptionSet::removeRow () {
@@ -228,7 +235,9 @@
 		RK_ASSERT (false);
 		return;
 	}
+	RK_ASSERT (!keycolumn);
 
+	if (display) model->beginRemoveRows (QModelIndex (), row, row);
 	// adjust values
 	QMap<RKComponentPropertyStringList *, ColumnInfo>::iterator it = column_map.begin ();
 	for (; it != column_map.end (); ++it) {
@@ -237,7 +246,6 @@
 		QStringList values = col->values ();
 		values.removeAt (row);
 		col->setValues (values);
-		column.old_values = values;
 	}
 
 	// adjust status info
@@ -249,6 +257,7 @@
 	if ((row < 0) && (nrows > 1)) row = 0;
 	row_count->setIntValue (nrows - 1);
 	current_row->setIntValue (active_row = row);
+	if (display) model->endRemoveRows ();
 }
 
 QString getDefaultValue (const RKOptionSet::ColumnInfo& ci, int row) {
@@ -274,9 +283,15 @@
 	int row = active_row;
 
 	rows[row].full_row_serialization.clear ();
-	ComponentStatus s = RKComponent::recursiveStatus ();
-	setRowState (row, s != Processing, s == Satisfied);
+	ComponentStatus cs = contents_container->recursiveStatus ();
+	setRowState (row, cs != Processing, cs == Satisfied);
 
+	ComponentStatus s = recursiveStatus ();
+	if (s != last_known_status) {
+		last_known_status = s;
+		updateVisuals ();
+	}
+
 	RKComponent::changed ();
 }
 
@@ -294,19 +309,15 @@
 	}
 
 	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);
 		ColumnInfo &inf = column_map[target];
 		QString value = property->value (inf.governor_modifier);
 		target->setValueAt (row, value);
 
-		if (display_item && (inf.display_index >= 0)) {
-			display_item->setText (inf.display_index, value);
+		if (model && (inf.display_index >= 0)) {
+			model->dataChanged (model->index (inf.display_index, row), model->index (inf.display_index, row));
 		}
-
-		inf.old_values = target->values ();
 	}
 
 	updating_from_contents = false;
@@ -320,13 +331,14 @@
 
 	RKComponentPropertyStringList *target = static_cast<RKComponentPropertyStringList *> (property);
 	RK_ASSERT (column_map.contains (target));
-	update_timer.start ();
-
-	if (target == keycolumn) {
-		handleKeycolumnUpdate ();
-	} else {
-		columns_which_have_been_updated_externally.insert (target);
+	ColumnInfo& ci = column_map[target];
+	if (!ci.restorable) {
+		RK_ASSERT (false);
+		return;
 	}
+
+	if (target == keycolumn) handleKeycolumnUpdate ();
+	else if (model) model->dataChanged (model->index (ci.display_index, 0), model->index (ci.display_index, model->rowCount ()));
 }
 
 void RKOptionSet::handleKeycolumnUpdate () {
@@ -334,7 +346,6 @@
 
 	int activate_row = activate_row;
 	QStringList new_keys = keycolumn->values ();
-	QStringList old_keys = column_map[keycolumn].old_values;
 	QMap<int, int> position_changes;
 
 	int pos;
@@ -347,7 +358,6 @@
 	}
 
 	if (position_changes.isEmpty () && (old_keys.size () == new_keys.size ())) {
-		columns_which_have_been_updated_externally.clear ();
 		return;	// no change
 	}
 
@@ -356,11 +366,11 @@
 	for (; it != column_map.end (); ++it) {
 		RKComponentPropertyStringList* col = it.key ();
 		ColumnInfo &column = it.value ();
-		if (col == keycolumn) continue;
+		if (column.restorable) continue;
 
 		// 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 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 ());
 
@@ -380,19 +390,18 @@
 
 		// 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);
+		col->setValues (new_values);
 	}
 
 	// update status info
 	QList<RowInfo> new_row_info = rows;
-	for (int i = (new_keys.size () - new_row_info.size ()); i > 0; --i) new_row_info.append (RowInfo ());
+	for (int i = (new_keys.size () - new_row_info.size ()); i > 0; --i) new_row_info.append (RowInfo (default_row_state));
 	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_row_info.insert (pos, RowInfo ());
+				new_row_info.insert (pos, RowInfo (default_row_state));
 			} else {	// old key changed position
 				new_row_info[pos] = rows[old_pos];
 			} // NOTE: not visible: old key is gone without replacement
@@ -405,13 +414,14 @@
 		if (!rows[i].valid) ++n_invalid_rows;
 	}
 
-	columns_which_have_been_updated_externally.clear ();
-	column_map[keycolumn].old_values = new_keys;
+	old_keys = new_keys;
 
 	int nrows = new_keys.size ();
 	row_count->setIntValue (nrows);
-	activate_row = qMax (new_keys.size () - 1, activate_row);
+	activate_row = qMin (nrows - 1, activate_row);
 	current_row->setIntValue (active_row = activate_row);
+	if (model) model->triggerReset ();
+	changed ();
 }
 
 void RKOptionSet::setContentsForRow (int row) {
@@ -443,76 +453,11 @@
 	}
 }
 
-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 = active_row;
-	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)) {
-				setRowState (row, false, false);
-			}
-		}
-		ci.old_values = values;
-	}
-
-#warning TODO: duplicate update
-	current_row->setIntValue (active_row = activate_row);
-	setContentsForRow (activate_row);
-
-	row_count->setIntValue (count);
-	contents_container->enablednessProperty ()->setBoolValue (activate_row >= 0);
-	updateVisuals ();
-	changed ();	// needed, for the unlikely case that no change notification was triggered above, since recursiveStatus() returns Processing while updating
-
-	updating_from_storage = false;
-}
-
 void RKOptionSet::updateVisuals () {
 	RK_TRACE (PLUGIN);
 
 	if (!display) return;
 
-	if (display_show_index) {
-		for (int row = display->topLevelItemCount () - 1; row >= 0; --row) {
-			display->topLevelItem (row)->setText (0, QString::number (row + 1));
-		}
-	}
-
 	QPalette palette = display->header ()->palette ();
 	if (isInactive ()) {
 		palette.setColor (QPalette::Window, QColor (200, 200, 200));
@@ -532,15 +477,12 @@
 	if (row != active_row) {	// May or may not be the case. True, e.g. if a row was removed
 		storeRowSerialization (active_row);
 		active_row = row;
+		contents_container->enablednessProperty ()->setBoolValue (active_row >= 0);
 	}
 
 	if (display) {
-		QTreeWidgetItem *item = 0;
-		if (row >= 0) item = display->topLevelItem (row);
-		if (item != display->currentItem ()) display->setCurrentItem (item);
+		if (row >= 0) display->setCurrentIndex (model->index (1, row));
 	}
-
-	update_timer.start ();
 }
 
 void RKOptionSet::storeRowSerialization (int row) {
@@ -550,11 +492,11 @@
 #warning ---------------- TODO ----------------------
 }
 
-void RKOptionSet::currentRowChanged (QTreeWidgetItem *new_row) {
+void RKOptionSet::currentRowChanged (int new_row) {
 	RK_TRACE (PLUGIN);
 
 	RK_ASSERT (display);
-	current_row->setIntValue (display->indexOfTopLevelItem (new_row));
+	current_row->setIntValue (new_row);
 	// --> currentRowPropertyChanged ()
 }
 
@@ -565,7 +507,6 @@
 	ComponentStatus s = RKComponent::recursiveStatus ();
 	if (s == Dead) return s;
 	if (n_unfinished_rows > 0) return Processing;
-	if (update_timer.isActive ()) return Processing;
 	return s;
 }
 
@@ -578,4 +519,40 @@
 	return true;
 }
 
+RKOptionSetDisplayModel::RKOptionSetDisplayModel ( QObject* parent ) : QAbstractTableModel ( parent ) {
+#warning ------------ TODO ------------------
+}
+
+RKOptionSetDisplayModel::~RKOptionSetDisplayModel() {
+#warning ------------ TODO ------------------
+}
+
+int RKOptionSetDisplayModel::columnCount (const QModelIndex& parent) const {
+	return column_labels.size ();
+}
+
+int RKOptionSetDisplayModel::rowCount ( const QModelIndex& parent ) const {
+#warning ------------ TODO ------------------
+	return 0;
+}
+
+QVariant RKOptionSetDisplayModel::data ( const QModelIndex& index, int role ) const {
+#warning ------------ TODO ------------------
+	return QVariant ();
+}
+
+void RKOptionSetDisplayModel::doResetNow() {
+#warning ------------ TODO ------------------
+}
+
+QVariant RKOptionSetDisplayModel::headerData ( int section, Qt::Orientation orientation, int role ) const {
+#warning ------------ TODO ------------------
+    return QAbstractItemModel::headerData ( section, orientation, role );
+}
+
+void RKOptionSetDisplayModel::triggerReset() {
+#warning ------------ TODO ------------------
+}
+
+
 #include "rkoptionset.moc"

Modified: trunk/rkward/rkward/plugin/rkoptionset.h
===================================================================
--- trunk/rkward/rkward/plugin/rkoptionset.h	2012-11-09 14:40:32 UTC (rev 4426)
+++ trunk/rkward/rkward/plugin/rkoptionset.h	2012-11-09 18:37:30 UTC (rev 4427)
@@ -25,14 +25,15 @@
 #include <QTimer>
 #include <QSet>
 
-class QTreeWidget;
-class QTreeWidgetItem;
+class QTreeView;
 class QPushButton;
+class RKOptionSetDisplayModel;
 
 /** An RKOptionSet provides a group of options for an arbitrary number of "rows". E.g. different line colors for each of a group of variables.
  * 
  * TODO
  * - serialization / de-serialization. We will need to make RKComponentBase::fetchPropertyValuesRecursive() and RKComponent::setPropertyValues() virtual, and reimplement them.
+ * - clear all compiler TODO warnings
  * 
   *@author Thomas Friedrichsmeier
   */
@@ -54,10 +55,8 @@
 	void currentRowPropertyChanged (RKComponentPropertyBase *property);
 	void addRow ();
 	void removeRow ();
-	void updateStatusAndDisplay ();
-	void currentRowChanged (QTreeWidgetItem *item);
+	void currentRowChanged (int new_row);
 private:
-	void initDisplay ();
 	void updateVisuals ();
 	int rowCount () const { return row_count->intValue (); };
 	void setRowState (int row, bool finished, bool valid);
@@ -69,6 +68,7 @@
 /** 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;
@@ -80,12 +80,11 @@
 		QString default_value;
 		int display_index;
 		bool restorable;
-		QStringList old_values;
 	};
 	/** Map of all columns to their meta info */
 	QMap<RKComponentPropertyStringList *, ColumnInfo> column_map;
 	struct RowInfo {
-		RowInfo () : valid (false), finished (false) {};
+		RowInfo (QMap<QString, QString> initial_values) : valid (false), finished (false), full_row_serialization (initial_values) {};
 		bool valid;		/**< has finished processing and is known to be valid */
 		bool finished;	/**< has finished processing */
 		QMap<QString, QString> full_row_serialization;	/**< complete serialization of this row, (see RKComponent::fetchPropertyValuesRecursive()) */
@@ -96,13 +95,15 @@
 	int active_row;
 
 	RKComponent *contents_container;
-	QTreeWidget *display;
 	QWidget *display_buttons;
 	QPushButton *remove_button;
 	QPushButton *add_button;
 	bool display_show_index;
-	QTimer update_timer;
+	ComponentStatus last_known_status;
 
+	RKOptionSetDisplayModel* model;
+	QTreeView *display;
+
 	int min_rows;
 	int min_rows_if_any;
 	int max_rows;
@@ -113,11 +114,29 @@
 	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);
 };
 
+class RKOptionSetDisplayModel : QAbstractTableModel {
+	Q_OBJECT
+private:
+friend class RKOptionSet;
+	RKOptionSetDisplayModel (QObject* parent);
+	virtual ~RKOptionSetDisplayModel ();
+	int rowCount (const QModelIndex & parent = QModelIndex()) const;
+	int columnCount (const QModelIndex & parent = QModelIndex()) const;
+	QVariant data (const QModelIndex& index, int role = Qt::DisplayRole) const;
+	QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+	void currentChanged (const QModelIndex& current, const QModelIndex& previous);
+	void triggerReset ();
+	QTimer reset_timer;
+	QStringList column_labels;
+private slots:
+	void doResetNow ();
+signals:
+	void rowChanged (int new_row);
+};
+
 #endif

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