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

tfry at users.sourceforge.net tfry at users.sourceforge.net
Wed Nov 21 18:57:37 UTC 2012


Revision: 4440
          http://rkward.svn.sourceforge.net/rkward/?rev=4440&view=rev
Author:   tfry
Date:     2012-11-21 18:57:37 +0000 (Wed, 21 Nov 2012)
Log Message:
-----------
Ok, this will need a solid round of debugging, but this is _roughly_ the first implementation of optionset serialization / deserialization

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-21 15:24:26 UTC (rev 4439)
+++ trunk/rkward/rkward/plugin/rkcomponent.h	2012-11-21 18:57:37 UTC (rev 4440)
@@ -128,7 +128,7 @@
 	friend class RKComponentBuilder;
 /** counterpart to fetchPropertyValuesRecursive (). Tries to apply all values from the list to properties of the given names. If some keys can not be found, or do not resolve to properties, the are ignored.
 @param list a list of id->value such as generated by fetchPropertyValuesRecursive () */
-	virtual void setPropertyValues (QMap<QString, QString> *list, bool warn_internal=false);
+	void setPropertyValues (QMap<QString, QString> *list, bool warn_internal=false);
 private:
 	bool is_internal;
 };

Modified: trunk/rkward/rkward/plugin/rkoptionset.cpp
===================================================================
--- trunk/rkward/rkward/plugin/rkoptionset.cpp	2012-11-21 15:24:26 UTC (rev 4439)
+++ trunk/rkward/rkward/plugin/rkoptionset.cpp	2012-11-21 18:57:37 UTC (rev 4440)
@@ -46,6 +46,10 @@
 	max_rows = xml->getIntAttribute (element, "max", INT_MAX, DL_INFO);
 
 	// create some meta properties
+	serialization_of_set = new RKComponentPropertyBase (this, false);
+	addChild ("serialized", serialization_of_set);
+	connect (serialization_of_set, SIGNAL (valueChanged(RKComponentPropertyBase*)), this, SLOT (serializationPropertyChanged(RKComponentPropertyBase*)));
+
 	active_row = -1;
 	current_row = new RKComponentPropertyInt (this, false, -1);
 	current_row->setInternal (true);
@@ -210,58 +214,135 @@
 QString serializeList (const QStringList &list) {
 	QString ret;
 	for (int i = 0; i < list.size (); ++i) {
-		if (i > 0) ret.append ('\n');
+		if (i > 0) ret.append ('\t');
 		ret.append (RKCommonFunctions::escape (list[i]));
 	}
 	return ret;
 }
 
 QStringList unserializeList  (const QString &serial) {
-	QStringList ret = serial.split ('\n', QString::KeepEmptyParts);
+	QStringList ret = serial.split ('\t', QString::KeepEmptyParts);
 	for (int i = 0; i < ret.size (); ++i) {
 		ret[i] = RKCommonFunctions::unescape (ret[i]);
 	}
 	return ret;
 }
 
-void RKOptionSet::fetchPropertyValuesRecursive (QMap <QString, QString>* list, bool include_top_level, const QString& prefix) const {
+QString serializeMap (const QMap<QString, QString> &map) {
+	QString ret;
+
+	QMap<QString, QString>::const_iterator it;
+	for (it = map.constBegin (); it != map.constEnd (); ++it) {
+		if (!ret.isEmpty ()) ret.append ('\t');
+		ret.append (RKCommonFunctions::escape (it.key ()) + '=' + RKCommonFunctions::escape (it.value ()));
+	}
+	return ret;
+}
+
+QMap<QString, QString> unserializeMap (const QString &serial) {
+	QMap<QString, QString> ret;
+	QStringList l = serial.split ('\t', QString::KeepEmptyParts);
+	for (int i = 0; i < l.size (); ++i) {
+		QString &line = l[i];
+		int sep = line.indexOf ('=');
+		ret.insert (RKCommonFunctions::unescape (line.left (sep)), RKCommonFunctions::unescape (line.mid (sep+1)));
+	}
+	return ret;
+}
+
+void RKOptionSet::fetchPropertyValuesRecursive (QMap<QString, QString> *list, bool include_top_level, const QString &prefix) const {
 	RK_TRACE (PLUGIN);
 	RK_ASSERT (include_top_level);
 
+	QString serialization;
+
 	if (keycolumn) {
-		list->insert (prefix + "keys", serializeList (old_keys));
+		serialization.append ("keys=" + RKCommonFunctions::escape (serializeList (old_keys)));
 	}
 
-	QMap<RKComponentPropertyStringList *, ColumnInfo>::const_iterator it;
-	for (it = column_map.constBegin (); it != column_map.constEnd (); ++it) {
-		if (it.value ().external) continue;
-		list->insert (prefix + it.value ().column_name, serializeList (it.key ()->values ()));
+	for (int r = 0; r < rows.size (); ++r) {
+		if (!serialization.isEmpty ()) serialization.append ("\n");
+		serialization.append ("_row=" + serializeMap (rows[r].full_row_map));
 	}
 
-// NOTE: *Not* fetching any other properties. Esp. not from the contents_container!
+	list->insert (prefix + "serialized", serialization);
 }
 
-void RKOptionSet::setPropertyValues (QMap <QString, QString>* list, bool warn_internal) {
+void RKOptionSet::serializationPropertyChanged (RKComponentPropertyBase* property) {
+	if (updating) return;
+	updating = true;
+	if (model) model->layoutAboutToBeChanged ();
+
+	RK_TRACE (PLUGIN);
+	RK_ASSERT (property == serialization_of_set);
 /* What happens when deserializing a plugin, with a driven optionset, and
  * the property connected to the keycolumn is restored *before* the optionset itself has been de-serialized?
  * 
  * We have to special-case this: If we go into setPropertyValues, and
  * the key column has already been touched, we have to
- * - backup keycolumn *and* all other external columns
  * - apply property values from the serialization
- * - re-apply the backups
+ * - trigger handleKeycolumnUpdate(), delayed
  * 
- * NOTE: This assumes that de-serialization can only happen once during the lifetime of an optionset. At the time of this writing,
- *       this assumption is valid, but it could change, of course.
  */
-	RK_TRACE (PLUGIN);
-#warning Grrr. It doesn't work like this!
-#warning Also it's wrong. Serialization needs to be done by rows (using the row's contents serialization!).
-// The good news is that this means that regular properties can be used, with not virtual fetch/setPropertyValues.
-// The above note still applies. Keys should be de-serialized last. This can simply be done by giving them a name that will be sorted last in the map (zzkeys, or something)
+	if (keycolumn && (keycolumn->value () != KEYCOLUMN_UNINITIALIZED_VALUE)) {
+		QTimer::singleShot (0, this, SLOT (handleKeycolumnUpdate ()));
+	} else {
+		RK_ASSERT (rows.isEmpty ());
+	}
 
-#warning ------------------- TODO ----------------------
-	RKComponentBase::setPropertyValues (list, warn_internal);
+	QList<RowInfo> new_rows;
+	int row = 0;
+	QStringList items = property->value ().split ("\n");
+	bool keys_missing = (keycolumn != 0);
+	for (int i = 0; i < items.size (); ++i) {
+		const QString &item = items[i];
+		int sep = item.indexOf ('=');
+		if (sep < 0) {
+			RK_DO (qDebug ("Bad format while trying to de-serialize optionset, line %d", i), PLUGIN, DL_WARNING);
+			continue;
+		}
+		QString tag = item.left (sep);
+		QString value = item.mid (sep + 1);
+
+		if (tag == QLatin1String ("keys")) {
+			if (!keys_missing) {
+				RK_DO (qDebug ("Unexpected specification of keys while trying to de-serialize optionset, line %d", i), PLUGIN, DL_WARNING);
+				continue;
+			}
+			old_keys = unserializeList (value);
+		} else if (tag == QLatin1String ("_row")) {
+			new_rows.append (RowInfo (unserializeMap (value)));
+			++row;
+		} else {
+			RK_DO (qDebug ("Unexpected tag %s while trying to de-serialize optionset, line %d", qPrintable (tag), i), PLUGIN, DL_WARNING);
+			continue;
+		}
+	}
+
+	if (keycolumn) {
+		RK_ASSERT (rows.size () == old_keys.size ());
+		RK_ASSERT (!keys_missing);
+	}
+
+	// reset all non-external columns to default values
+	QMap<RKComponentPropertyStringList*, ColumnInfo>::const_iterator it;
+	for (it = column_map.constBegin (); it != column_map.constEnd (); ++it) {
+		const ColumnInfo &col = it.value ();
+		if (col.external) continue;
+		QStringList def;
+		for (int i = 0; i < row; ++i) {
+			def.append (getDefaultValue (col, i));
+		}
+		it.key ()->setValues (def);
+	}
+
+	rows = new_rows;
+	row_count->setIntValue (row);
+	current_row->setIntValue (qMin (0, row - 1));
+
+	serialization_of_set->setValue (QString ());	// free some mem, and don't make users think, this can actually be queried in real-time
+	updating = false;
+	if (model) model->layoutChanged ();
 }
 
 void RKOptionSet::addRow () {
@@ -545,7 +626,7 @@
 
 	RK_ASSERT (rows.size () > row);
 	if (row >= 0) {
-		contents_container->setPropertyValues (&(rows[row].full_row_serialization), false);
+		contents_container->setPropertyValues (&(rows[row].full_row_map), false);
 	} else {
 		contents_container->setPropertyValues (&default_row_state, false);
 	}
@@ -562,8 +643,8 @@
 
 	if (row < 0) return;	// No row was active
 	RK_ASSERT (rows.size () > row);
-	rows[row].full_row_serialization.clear ();
-	contents_container->fetchPropertyValuesRecursive (&(rows[row].full_row_serialization));
+	rows[row].full_row_map.clear ();
+	contents_container->fetchPropertyValuesRecursive (&(rows[row].full_row_map));
 }
 
 int getCurrentRowFromDisplay (QTreeView* display) {

Modified: trunk/rkward/rkward/plugin/rkoptionset.h
===================================================================
--- trunk/rkward/rkward/plugin/rkoptionset.h	2012-11-21 15:24:26 UTC (rev 4439)
+++ trunk/rkward/rkward/plugin/rkoptionset.h	2012-11-21 18:57:37 UTC (rev 4440)
@@ -54,15 +54,13 @@
 	void governingPropertyChanged (RKComponentPropertyBase *property);
 	void columnPropertyChanged (RKComponentPropertyBase *property);
 	void currentRowPropertyChanged (RKComponentPropertyBase *property);
+	void serializationPropertyChanged (RKComponentPropertyBase *property);
 	void addRow ();
 	void removeRow ();
 	void currentRowChanged ();
 	void fetchDefaults ();
 protected:
-	// reimplemented from RKComponent
-	void fetchPropertyValuesRecursive (QMap<QString, QString> *list, bool include_top_level=false, const QString &prefix=QString::null) const;
-	// reimplemented from RKComponent
-	void setPropertyValues (QMap<QString, QString> *list, bool warn_internal=false);
+	void fetchPropertyValuesRecursive (QMap<QString, QString> *list, bool include_top_level=false, const QString &prefix=QString ()) const;
 friend class RKOptionSetDisplayModel;
 	int rowCount () const { return row_count->intValue (); };
 	void setRowState (int row, bool finished, bool valid);
@@ -71,6 +69,10 @@
 
 	RKComponentPropertyInt *current_row;
 	RKComponentPropertyInt *row_count;
+/** Un-serializing an optionset's state is terribly complicated, if it isn't guaranteed to happen in a single batch. Therefore, we
+ * keep a dedicated property (serialization_of_set), which holds a _full_ serialization of the set's state. 
+ * However, this representation is not kept up to date, for performance reasons. Rather it is generated only in fetchPropertyValuesRecursive(). */
+ 	RKComponentPropertyBase *serialization_of_set;
 
 /** 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. */
@@ -92,10 +94,10 @@
 	QMap<RKComponentPropertyStringList *, ColumnInfo> column_map;
 	QList<RKComponentPropertyStringList*> visible_columns;
 	struct RowInfo {
-		RowInfo (QMap<QString, QString> initial_values) : valid (false), finished (false), full_row_serialization (initial_values) {};
+		RowInfo (QMap<QString, QString> initial_values) : valid (false), finished (false), full_row_map (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()) */
+		QMap<QString, QString> full_row_map;	/**< complete status representation of this row, (see RKComponent::fetchPropertyValuesRecursive()) */
 	};
 	QList<RowInfo> rows;
 	QMap<QString, QString> default_row_state;

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