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

tfry at users.sourceforge.net tfry at users.sourceforge.net
Sun Nov 25 11:30:30 UTC 2012


Revision: 4453
          http://rkward.svn.sourceforge.net/rkward/?rev=4453&view=rev
Author:   tfry
Date:     2012-11-25 11:30:29 +0000 (Sun, 25 Nov 2012)
Log Message:
-----------
Fix verification of deserialization (for the moment, at least). Add possibility to add utility properties inside the optionset's contenst area

Modified Paths:
--------------
    trunk/rkward/rkward/plugin/rkcomponent.cpp
    trunk/rkward/rkward/plugin/rkcomponent.h
    trunk/rkward/rkward/plugin/rkcomponentmap.cpp
    trunk/rkward/rkward/plugin/rkoptionset.cpp
    trunk/rkward/rkward/plugin/rkoptionset.h
    trunk/rkward/rkward/plugin/rkstandardcomponentgui.cpp
    trunk/rkward/rkward/plugins/testing/optionset.js
    trunk/rkward/rkward/plugins/testing/optionset.xml

Modified: trunk/rkward/rkward/plugin/rkcomponent.cpp
===================================================================
--- trunk/rkward/rkward/plugin/rkcomponent.cpp	2012-11-25 11:20:48 UTC (rev 4452)
+++ trunk/rkward/rkward/plugin/rkcomponent.cpp	2012-11-25 11:30:29 UTC (rev 4453)
@@ -65,7 +65,7 @@
 	}
 }
 
-void RKComponentBase::setPropertyValues (PropertyValueMap *list, bool warn_internal) {
+void RKComponentBase::setPropertyValues (const PropertyValueMap *list, bool warn) {
 	RK_TRACE (PLUGIN);
 	// TODO: visibility enabledness and requiredness should be excluded, as those are not directly user settable. Perhaps even mark up all properties as user settable or not.
 
@@ -74,60 +74,71 @@
 		RKComponentBase *prop = lookupComponent (it.key (), &mod);
 		if (mod.isEmpty () && prop->isProperty ()) {		// found a property
 			RKComponentPropertyBase* p = static_cast<RKComponentPropertyBase*>(prop);
-			RK_ASSERT (!(p->isInternal () && warn_internal));
+			if (p->isInternal () && warn) {
+				RK_DO (qDebug ("Setting value for property %s, which is marked internal.", qPrintable (it.key ())), PLUGIN, DL_WARNING);
+			}
 			p->setValue (it.value ());
+		} else {
+			if (warn) RK_DO (qDebug ("Property %s not found while setting values. Remainder was %s.", qPrintable (it.key ()), qPrintable (mod)), PLUGIN, DL_WARNING);
 		}
 	}
 }
 
-QString RKComponentBase::serializeState () const {
+//static
+QString RKComponentBase::valueMapToString (const PropertyValueMap &map) {
 	RK_TRACE (PLUGIN);
 
-	PropertyValueMap props;
-	fetchPropertyValuesRecursive (&props, true);
-
 	QString out;
-	for (PropertyValueMap::const_iterator it = props.constBegin (); it != props.constEnd (); ++it) {
+	for (PropertyValueMap::const_iterator it = map.constBegin (); it != map.constEnd (); ++it) {
 		if (!out.isEmpty ()) out.append ("\n");
 		out.append (RKCommonFunctions::escape (it.key () + "=" + it.value ()));
 	}
-
 	return out;
 }
 
-RKComponent::UnserializeError RKComponentBase::unserializeState (const QStringList &state) {
+//static
+bool RKComponentBase::stringListToValueMap (const QStringList &strings, PropertyValueMap *map) {
 	RK_TRACE (PLUGIN);
 
-	PropertyValueMap props;
-
-	for (int i = 0; i < state.count (); ++i) {
-		QString line = state[i];
+	for (int i = 0; i < strings.size (); ++i) {
+		QString line = RKCommonFunctions::unescape (strings[i]);
 		int sep = line.indexOf ('=');
-		if (sep < 0) return BadFormat;
-		props.insert (RKCommonFunctions::unescape (line.left (sep)), RKCommonFunctions::unescape (line.mid (sep+1)));
+		if (sep < 0) return false;
+		map->insert (line.left (sep), line.mid (sep+1));
 	}
+	return true;
+}
 
-	setPropertyValues (&props);
+QStringList RKComponentBase::matchAgainstState (const PropertyValueMap &state) {
+	RK_TRACE (PLUGIN);
+	QStringList probs;
 
-	// verify
-	UnserializeError error = NoError;
-	for (PropertyValueMap::const_iterator it = props.constBegin (); it != props.constEnd (); ++it) {
-		if (fetchStringValue (it.key ()) != it.value ()) {
-			// COMPAT: In RKWard 0.5.1, the formatting of real numbers was different. Hence we compare the numeric values, instead
+	PropertyValueMap current;
+	fetchPropertyValuesRecursive (&current, true);
+
+	for (PropertyValueMap::const_iterator it = state.constBegin (); it != state.constEnd (); ++it) {
+		QString current_value = current.value (it.key ());
+		if (current_value != it.value ()) {
+			// this is not necessarily a problem. The value may simply not be in the serialization, or in slightly different format
 			QString dummy;
 			RKComponentBase *prop = lookupComponent (it.key (), &dummy);
-			if (dummy.isEmpty () && prop && prop->type () == PropertyDouble) {
-				if (static_cast<RKComponentPropertyDouble*> (prop)->doubleValue () == it.value ().toDouble ()) {
+			if (dummy.isEmpty () && prop) {
+				// COMPAT: In RKWard 0.5.1, the formatting of real numbers was different. Hence we compare the numeric values, instead
+				if ((prop->type () == PropertyDouble) && static_cast<RKComponentPropertyDouble*> (prop)->doubleValue () == it.value ().toDouble ()) {
 					continue;
+				} else if (prop->value () == it.value ()) {
+					continue;
+				} else {
+					if (current_value.isEmpty () && !prop->value ().isEmpty ()) current_value = prop->value ();
+					probs.append (QString ("Tried to apply 'value %1' to property %2, but got '%3', instead").arg (it.value (), it.key (), current_value));
 				}
+			} else {
+				probs.append (QString ("No such property %1 (remainder was %2)").arg (it.key (), dummy));
 			}
-
-			RK_DO(qDebug ("Tried to apply value %s to property %s, but got %s", qPrintable (it.value ()), qPrintable (it.key ()), qPrintable (fetchStringValue (it.key ()))), PLUGIN, DL_WARNING);
-			error = NotAllSettingsApplied;
 		}
 	}
 
-	return error;
+	return probs;
 }
 
 QString RKComponentBase::fetchStringValue (const QString &identifier) {

Modified: trunk/rkward/rkward/plugin/rkcomponent.h
===================================================================
--- trunk/rkward/rkward/plugin/rkcomponent.h	2012-11-25 11:20:48 UTC (rev 4452)
+++ trunk/rkward/rkward/plugin/rkcomponent.h	2012-11-25 11:30:29 UTC (rev 4453)
@@ -107,16 +107,19 @@
 /** simple convenience function to add a child to the map of children */
 	virtual void addChild (const QString &id, RKComponentBase *child);
 
+	typedef QMap<QString, QString> PropertyValueMap;
+	static QString valueMapToString (const PropertyValueMap &map);
+	static bool stringListToValueMap (const QStringList &strings, PropertyValueMap *map);
 /** serialize the state of this component / property and all its children. Note: Only the non-internal property-values are serialzed, not the components / properties themselves. @see fetchPropertyValuesRecursive() */
-	QString serializeState () const;
-/** set values from a string created with serializeState() (split by "\n"). @see serializeState (), @see setPropertyValues ().
+	void serializeState (PropertyValueMap *map) const { fetchPropertyValuesRecursive (map, true); };
+/** set values from a map as created with serializeState(). @see serializeState (), @see setPropertyValues ().
 @returns status code */
-	UnserializeError unserializeState (const QStringList &state);
+	void applyState (const PropertyValueMap &state) { setPropertyValues (&state, true); };
+	QStringList matchAgainstState (const PropertyValueMap &state);
 
 /** Some properties/components will be marked as internal, such as visibility properties, which are not meant to be set directly by the user. These will be ignored in RKComponent::fetchPropertyValuesRecursive() */
 	void setInternal (bool internal) { is_internal = internal; };
 	bool isInternal () const { return is_internal; };
-	typedef QMap<QString, QString> PropertyValueMap;
 protected:
 friend class RKOptionSet;
 	QHash<QString, RKComponentBase*> child_map;
@@ -127,9 +130,9 @@
 @param prefix used during recursion to provide full ids for the added objects */
 	virtual void fetchPropertyValuesRecursive (PropertyValueMap *list, bool include_top_level=false, const QString &prefix=QString ()) const;
 	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.
+/** 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, they are ignored.
 @param list a list of id->value such as generated by fetchPropertyValuesRecursive () */
-	void setPropertyValues (PropertyValueMap *list, bool warn_internal=false);
+	void setPropertyValues (const PropertyValueMap *list, bool warn = false);
 private:
 	bool is_internal;
 };

Modified: trunk/rkward/rkward/plugin/rkcomponentmap.cpp
===================================================================
--- trunk/rkward/rkward/plugin/rkcomponentmap.cpp	2012-11-25 11:20:48 UTC (rev 4452)
+++ trunk/rkward/rkward/plugin/rkcomponentmap.cpp	2012-11-25 11:30:29 UTC (rev 4453)
@@ -252,54 +252,57 @@
 	RKStandardComponent *component = handle->invoke (0, 0);
 	RK_ASSERT (component);
 
-	RKComponent::UnserializeError error = component->unserializeState (serialized_settings);
-	if (error == RKComponent::BadFormat) {
+	RKComponent::PropertyValueMap state;
+	bool format_ok = RKComponent::stringListToValueMap (serialized_settings, &state);
+	if (!format_ok) {
 		_message = i18n ("Bad serialization format while trying to invoke plugin '%1'. Please contact the RKWard team (Help->About RKWard->Authors).").arg (component_id);
 		if (message) *message = _message;
 		else KMessageBox::error (component, _message, i18n ("Bad serialization format"));
 		return false;
 	}
-	if (error == RKComponent::NotAllSettingsApplied) {
-		_message = i18n ("Not all specified settings could be applied. Most likely this is because some R objects are no longer present in your current workspace.");
-		if (message) *message = _message;
-		else KMessageBox::information (component, _message, i18n ("Not all settings applied"));
-		// TODO: Don't show again-box?
-		// not considered an error
-	}
+	component->applyState (state);
 
-	if (submit_mode == ManualSubmit) return true;
-
-
-	// Auto-Submit
+	// now wait for the component to settle
 	// the call to processEvents(), below, is quite dangerous, as the component self-destructs on errors. This helps us prevent crashes.
 	QObjectCleanupHandler chandler;
 	chandler.add (component);
-	
-#ifndef Q_OS_WIN
 	// if the plugin takes longer than 5 seconds to settle, than that really is sort of buggy...
 	const int max_wait = 5000;
-#else
-#warning Temporary workaround. Remove this.
-	// (yet on windows, the PHP backend is *real* slow. We give it a bit longer as long as we still use it...
-	const int max_wait = 50000;
-#endif
 
 	QTime t;
 	t.start ();
-	while ((!chandler.isEmpty ()) && (component->recursiveStatus () == RKComponentBase::Processing) && (t.elapsed () < max_wait)) {
+	RKComponentBase::ComponentStatus status;
+	while ((!chandler.isEmpty ()) && ((status = component->recursiveStatus ()) == RKComponentBase::Processing) && (t.elapsed () < max_wait)) {
 		QCoreApplication::processEvents (QEventLoop::ExcludeUserInputEvents, (max_wait / 2));
 	}
-	RKComponentBase::ComponentStatus status = RKComponentBase::Dead;
-	if (!chandler.isEmpty ()) status = component->recursiveStatus ();
+	if (chandler.isEmpty ()) status = RKComponentBase::Dead;
 	chandler.remove (component);	// otherwise it would auto-delete the component, later!
 
+	if (status == RKComponentBase::Dead) {
+		if (message) {
+			_message.append (i18n ("\nThe plugin has crashed."));
+			*message = _message;
+		}
+		return false;
+	}
+
+	QStringList problems = component->matchAgainstState (state);
+	if (!problems.isEmpty ()) {
+		_message = i18n ("Not all specified settings could be applied. Most likely this is because some R objects are no longer present in your current workspace.");
+		RK_DO (qDebug ("%s", qPrintable (problems.join ("\n"))), PLUGIN, DL_WARNING);	// TODO: make failures available to backend
+		if (message) *message = _message;
+		else KMessageBox::informationList (component, _message, problems, i18n ("Not all settings applied"));
+		// TODO: Don't show again-box?
+		// not considered an error
+	}
+
+	if (submit_mode == ManualSubmit) return true;
+
 	if (status == RKComponentBase::Satisfied) {
 		bool ok = component->submit (in_chain);
 		RK_ASSERT (ok);
 	} else {
-		if (submit_mode == AutoSubmitOrFail) {
-			if (status != RKComponentBase::Dead) component->kill ();
-		}
+		if (submit_mode == AutoSubmitOrFail) component->kill ();
 
 		_message.append (i18n ("\nThe plugin could not be auto-submitted with these settings."));
 		if (message) *message = _message;

Modified: trunk/rkward/rkward/plugin/rkoptionset.cpp
===================================================================
--- trunk/rkward/rkward/plugin/rkoptionset.cpp	2012-11-25 11:20:48 UTC (rev 4452)
+++ trunk/rkward/rkward/plugin/rkoptionset.cpp	2012-11-25 11:30:29 UTC (rev 4453)
@@ -79,7 +79,8 @@
 	display = 0;	// will be created from the builder, on demand -> createDisplay ()
 	contents_container = new RKComponent (this, user_area);
 	RKComponentBuilder *builder = new RKComponentBuilder (contents_container, QDomElement ());
-	builder->buildElement (xml->getChildElement (element, "content", DL_ERROR), user_area, false);	// NOTE that parent widget != parent component, here, by intention. The point is that the display should not be disabled along with the contents
+	QDomElement content_element = xml->getChildElement (element, "content", DL_ERROR);
+	builder->buildElement (content_element, user_area, 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);
 	connect (standardComponent (), SIGNAL (standardInitializationComplete()), this, SLOT (fetchDefaults()));
@@ -166,6 +167,20 @@
 		}
 	}
 
+	// helper properties
+	XMLChildList properties = xml->getChildElements (content_element, "property", DL_WARNING);
+	for (int i = 0; i < properties.size (); ++i) {
+		const QDomElement &e = properties.at (i);
+		QString id = xml->getStringAttribute (e, "id", QString (), DL_ERROR);
+		if (contents_container->child_map.contains (id)) {
+			RK_DO (qDebug ("Id %s already in use. Skipping property declaration", qPrintable (id)), PLUGIN, DL_WARNING);
+			continue;
+		}
+		RKComponentPropertyBase *prop = new RKComponentPropertyBase (contents_container, false);
+		prop->setInternal (true);
+		contents_container->addChild (id, prop);
+	}
+
 	if (display) {		// may or may not have been created
 		model->column_labels = visible_column_labels;
 		display->setItemsExpandable (false);
@@ -359,14 +374,13 @@
 	rows = new_rows;
 	n_unfinished_rows = n_invalid_rows = row;
 	row_count->setIntValue (row);
+	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 (update_key_col) handleKeycolumnUpdate ();
 
 	active_row = -1;
 	current_row->setIntValue (qMin (0, row - 1));
 
-#warning ------------ TODO: rework method of verification of serialization -------------
-//	serialization_of_set->setValue (QString ());	// free some mem, and don't make users think, this can actually be queried in real-time
 	if (model) model->layoutChanged ();
 	changed ();
 }
@@ -486,7 +500,7 @@
 QString getDefaultValue (const RKOptionSet::ColumnInfo& ci, int row) {
 	// let's not trace this simple helper fun
 	Q_UNUSED (row);
-#warning TODO: should also allow scripted defaults
+// TODO: should also allow scripted defaults?
 	return ci.default_value;
 }
 

Modified: trunk/rkward/rkward/plugin/rkoptionset.h
===================================================================
--- trunk/rkward/rkward/plugin/rkoptionset.h	2012-11-25 11:20:48 UTC (rev 4452)
+++ trunk/rkward/rkward/plugin/rkoptionset.h	2012-11-25 11:30:29 UTC (rev 4453)
@@ -32,12 +32,8 @@
 
 /** 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
- * - Fix verification logic for deserialization (whether settings have been applied, successfully)
- * - clear all compiler TODO warnings
- * 
-  *@author Thomas Friedrichsmeier
-  */
+ * @author Thomas Friedrichsmeier
+ */
 class RKOptionSet : public RKComponent {
 	Q_OBJECT
 public:

Modified: trunk/rkward/rkward/plugin/rkstandardcomponentgui.cpp
===================================================================
--- trunk/rkward/rkward/plugin/rkstandardcomponentgui.cpp	2012-11-25 11:20:48 UTC (rev 4452)
+++ trunk/rkward/rkward/plugin/rkstandardcomponentgui.cpp	2012-11-25 11:30:29 UTC (rev 4453)
@@ -173,7 +173,9 @@
 	command.clear ();
 	RKComponentHandle *handle = component->getHandle ();
 	if (handle->isAccessible ()) {
-		command.append (".rk.rerun.plugin.link(plugin=\"" + RKComponentMap::getComponentId (handle) + "\", settings=\"" + RKCommonFunctions::escape (component->serializeState ()) + "\", label=\"" + i18n ("Run again") + "\")\n");
+		RKComponent::PropertyValueMap map;
+		component->serializeState (&map);
+		command.append (".rk.rerun.plugin.link(plugin=\"" + RKComponentMap::getComponentId (handle) + "\", settings=\"" + RKCommonFunctions::escape (RKComponent::valueMapToString (map)) + "\", label=\"" + i18n ("Run again") + "\")\n");
 		// NOTE: the serialized state is quote-escape *again* for passing to R.
 	}
 	// separator line

Modified: trunk/rkward/rkward/plugins/testing/optionset.js
===================================================================
--- trunk/rkward/rkward/plugins/testing/optionset.js	2012-11-25 11:20:48 UTC (rev 4452)
+++ trunk/rkward/rkward/plugins/testing/optionset.js	2012-11-25 11:30:29 UTC (rev 4453)
@@ -7,4 +7,13 @@
 	echo ("row_count <- " + getValue ("set.row_count") + "\n");
 	echo ("current_row <- " + getValue ("set.current_row") + "\n");
 	echo ("set.contents.enabled <- " + getValue ("set.contents.enabled") + "\n");
+
+	var codeprops = getValue ("set.plotoption_printout").split ("\n");
+	for (i = 0; i < codeprops.length; ++i) {
+		echo ("Plotoption string printout " + i + " in driven set: " + codeprops[i] + "\n");
+	}
+	codeprops = getValue ("set.plotoption_pre").split ("\n");
+	for (i = 0; i < codeprops.length; ++i) {
+		echo ("Plotoption string preprocess " + i + " in driven set: " + codeprops[i] + "\n");
+	}
 }

Modified: trunk/rkward/rkward/plugins/testing/optionset.xml
===================================================================
--- trunk/rkward/rkward/plugins/testing/optionset.xml	2012-11-25 11:20:48 UTC (rev 4452)
+++ trunk/rkward/rkward/plugins/testing/optionset.xml	2012-11-25 11:30:29 UTC (rev 4453)
@@ -5,6 +5,7 @@
 
 	<logic>
 		<set id="set.contents.dummybox.enabled" to="false"/>
+		<!--		<connect governor="set.contents.x" client="set.contents.test_embed.xvar"/> -->
 		<connect governor="x.available" client="set.var" />
 		<connect governor="x.available.shortname" client="set.varname" />
 		<connect governor="mset.object" client="cset.object" />
@@ -61,6 +62,7 @@
 				<row>
 					<optionset id="set" min_rows="1" keycolumn="var">
 						<content>
+							<!--							<property id="x"/> -->
 							<frame>
 								<optiondisplay index="false"/>
 								<checkbox id="dummybox" label="This dummy option is always disabled"/>
@@ -69,10 +71,12 @@
 								<embed id="test_embed" component="rkward::plot_options" as_button="true"/>
 							</frame>
 						</content>
-						<option id="var" label="test" external="true"/>
+						<option id="var" label="test" external="true" connect="test_embed.xvar"/>
 						<option id="varname" label="Varname" external="true"/>
 						<option id="ca" label="Comment A" connect="commenta.text"/>
 						<option id="cb" connect="commentb.text"/>
+						<option id="plotoption_printout" connect="test_embed.code.printout"/>
+						<option id="plotoption_pre" connect="test_embed.code.preprocess"/>
 					</optionset>
 				</row>
 			</tab>

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