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

tfry at users.sourceforge.net tfry at users.sourceforge.net
Fri Dec 7 11:07:11 UTC 2012


Revision: 4485
          http://rkward.svn.sourceforge.net/rkward/?rev=4485&view=rev
Author:   tfry
Date:     2012-12-07 11:07:10 +0000 (Fri, 07 Dec 2012)
Log Message:
-----------
Add <switch> element for implementing switch() statements, or remapping values.

Modified Paths:
--------------
    trunk/rkward/ChangeLog
    trunk/rkward/doc/rkwardplugins/index.docbook
    trunk/rkward/rkward/plugin/rkcomponent.cpp
    trunk/rkward/rkward/plugin/rkcomponent.h
    trunk/rkward/rkward/plugin/rkcomponentproperties.cpp
    trunk/rkward/rkward/plugin/rkcomponentproperties.h
    trunk/rkward/rkward/plugin/rkstandardcomponent.cpp
    trunk/rkward/rkward/plugins/data/sort.xml

Modified: trunk/rkward/ChangeLog
===================================================================
--- trunk/rkward/ChangeLog	2012-12-07 10:08:59 UTC (rev 4484)
+++ trunk/rkward/ChangeLog	2012-12-07 11:07:10 UTC (rev 4485)
@@ -1,3 +1,4 @@
+- Added <switch> logic element to switch between several target properties (or fixed values) based on the value of a condition property
 - Sort plugin gains option to sort data.frames by more than one column at a time, and options for type conversion	TODO: adjust test(s)
 - Add in-application debug message viewer (targetted at (plugin) developers)
 - Add setting to customize initial working directory
@@ -4,12 +5,12 @@
 - Windows only: Add UI-checkbox for R's "internet2"-option
 - New functions getString(), getList() and getBoolean() for fetching data in plugin scripts		TODO: more testing, convert at least some plugins
 - Boolean properties now return a numeric, not labelled representation of their value, by default. <checkbox>es should be unaffected.	TODO: when announcing release, link to explanation mail.
-- Added GUI element for entering a set of options for an arbitrary number of items		TODO: document
+- Added <optionset> GUI element for entering a set of options for an arbitrary number of items
 - Reduce CPU usage of pluings while idle
 - Fix conversion from Numeric to Factor in the data editor
 - In the data.frame editor, columns containing invalid values are now highlighted in red
 - Fixed: If none of the previous plugin maps could be found on startup, re-add the default
-- Added GUI element for entering matrix or vector data in plugins
+- Added <matrix> GUI element for entering matrix or vector data in plugins
 - Improve key handling while editing factor levels in a data.frame
 - Added utiltity function rk.flush.output()
 - RKWard is now categorized as Science/Math/Numerical Analysis in its .desktop file

Modified: trunk/rkward/doc/rkwardplugins/index.docbook
===================================================================
--- trunk/rkward/doc/rkwardplugins/index.docbook	2012-12-07 10:08:59 UTC (rev 4484)
+++ trunk/rkward/doc/rkwardplugins/index.docbook	2012-12-07 11:07:10 UTC (rev 4485)
@@ -809,44 +809,37 @@
 
 	<logic>
 		<convert id="varmode" mode="equals" sources="mode.string" standard="variable" />
-		<convert id="constmode" mode="equals" sources="mode.string" standard="constant" />
 
 		<connect client="y.visible" governor="varmode" />
-		<connect client="constant.visible" governor="constmode" />
+		<connect client="constant.visible" governor="varmode.not" />
 	</logic>
 
 	<dialog label="T-Test">
 	[...]
 	</programlisting>
 	<para>
-		The first two lines inside the logic section are <command><convert></command> tags. Those basically provide two new boolean (on or off, true or false) properties, which can be used later on. The first property (<replaceable>"varmode"</replaceable>) is true, whenever the upper radio button is selected and the second whenever the lower radio button is selected. How is this done?
+		The first line inside the logic section is a <command><convert></command> tag. Basically, this provides a new boolean (on or off, true or false) property, which can be used later on. This property (<replaceable>"varmode"</replaceable>) is true, whenever the upper radio button is selected and false whenever the lower radio button is selected. How is this done?
 	</para>
 	<para>
 		First, under <parameter>sources</parameter>, the source properties to work on are listed (in this case only one each; you could list several as <parameter>sources=</parameter><replaceable>"mode.string;somethingelse"</replaceable>, then <replaceable>"varmode"</replaceable> would only be true, if both <replaceable>"mode.string"</replaceable> and <replaceable>"somethingelse"</replaceable> are equal to the string <replaceable>"variable"</replaceable>). Note that in this case we don't just write <replaceable>"mode"</replaceable> (as we would in <function>getString("mode")</function>, but <replaceable>"mode.string"</replaceable>. This is actually the internal way a radio control works: It has a property <quote>string</quote>, which holds its string value. <function>getString("mode")</function> is just a shorthand, and equivalent to <function>getString("mode.string")</function>. See the reference for all properties of the different GUI elements.
 	</para>
 	<para>
-		Second, we set the mode of conversion to <parameter>mode=</parameter><replaceable>"equals"</replaceable>. This means, we want to check, whether the sources are equal to a certain value. Finally standard is the value to compare against, so with <parameter>standard=</parameter><replaceable>"variable"</replaceable>, we check whether the property <replaceable>"mode.string"</replaceable> is equal to the string <replaceable>"variable"</replaceable> (the value of the upper radio option). If it is equal, then the property varmode is true, else it is false.
+		Second, we set the mode of conversion to <parameter>mode=</parameter><replaceable>"equals"</replaceable>. This means, we want to check, whether the source(s) is (are) equal to a certain value. Finally standard is the value to compare against, so with <parameter>standard=</parameter><replaceable>"variable"</replaceable>, we check whether the property <replaceable>"mode.string"</replaceable> is equal to the string <replaceable>"variable"</replaceable> (the value of the upper radio option). If it is equal, then the property varmode is true, else it is false.
 	</para>
 	<para>
-		The next line is basically the same, but reversed. Here we define a property (<replaceable>"constmode"</replaceable>) which becomes true, if the second radio option is selected.
+		Now to the real stuff: We <command><connect></command> the <replaceable>"varmode"</replaceable> property to y.visible, which controls whether the varslot <replaceable>"y"</replaceable> is shown or not. Note that any element which is made invisible is implicitly non-required. Thus, if the upper radio-option is selected, the varslot <replaceable>"y"</replaceable> is required, and visible. Else it is not required and hidden.
 	</para>
 	<para>
-		Now to the real stuff: We <command><connect></command> the <replaceable>"varmode"</replaceable> property to y.visible, which controls whether the varslot <replaceable>"y"</replaceable> is shown or not. Note that any element which is made invisible is implicitly non-required. Thus, if the upper radio-option is selected, the varslot <replaceable>"y"</replaceable> is required, and visible. Else it is not required and hidden.
+		For the spinbox, we want the exact reverse. Fortunately, we do not need another <command><convert></command> for this: Boolean
+		properties can be negated very easily by appending the modifier <replaceable>"not"</replaceable>, so we <command><connect></command> <replaceable>"varmode.not"</replaceable> to the spinbox's visibility property. In effect, either
+		the varslot is shown and required, <emphasis>or</emphasis> the spinbox is shown and required - depending on which option is selected in the radio control. The GUI is changing itself according to the radio option. Try the example, if you like.
 	</para>
 	<para>
-		We do just the reverse for the spinbox. So in effect, either the varslot is shown and required, <emphasis>or</emphasis> the spinbox is shown and required - depending on which option is selected in the radio control. The GUI is changing itself according to the radio option. Try the example, if you like.
+		For a complete list of properties, refer to the <link linkend="reference">reference</link>. One more property, however, is special in that all GUI elements have it: <quote>enabled</quote>. This is slightly less drastic that <quote>visible</quote>. It does not show/hide the GUI element, but only enables/disables it. Disabled elements are typically shown grayed out, and do not react to user input.
 	</para>
 	<note>
-		<para>
-			In the above example, instead of defining two properties <replaceable>"varmode"</replaceable> and <replaceable>"constmode"</replaceable>, we could also have used the negation of <replaceable>"varmode"</replaceable>, like this:
-		</para>
+		<para>Besides <command><convert></command> and <command><connect></command>, there are several further elements for use in the <command><logic></command> section. E.g. conditional constructs can also be implemented using the <command><switch></command>-element. Refer to the <link linkend="logicelements">reference on logic elements</link> for details.</para>
 	</note>
-	<programlisting>
-	<connect client="constant.visible" governor="varmode.not" />
-	</programlisting>
-	<para>
-		Once again, for a complete list of properties, refer to the <link linkend="reference">reference</link>. One more property, however, is special in that all GUI elements have it: <quote>enabled</quote>. This is slightly less drastic that <quote>visible</quote>. It does not show/hide the GUI element, but only enables/disables it. Disabled elements are typically shown grayed out, and do not react to user input.
-	</para>
 </sect1>
 <sect1 id="logic_scripted">
 <title>Scripted GUI logic</title>
@@ -856,7 +849,7 @@
 	<programlisting>
 	[...]
 	<code file="code.js"/>
-
+'
 	<logic>
 		<script><![CDATA[
 			// ECMAScript code in this block
@@ -2691,16 +2684,16 @@
 	<term><optioncolumn></term>
 	<listitem><para>Declares one optioncolumn of the set. For each value that you want to fetch from the optionset, you must declare a separate <optioncolumn>. Attributes:
 		<variablelist>
-			<varlistentry><term>id</term>
+			<varlistentry><term><parameter>id</parameter></term>
 			<listitem><para>The id of the optioncolumn (required, string).</para></listitem></varlistentry>
-			<varlistentry><term>external</term>
+			<varlistentry><term><parameter>external</parameter></term>
 			<listitem><para>Set to true, if the optioncolumn is controlled from outside the optionset (optional, boolean, defaults to false).</para></listitem></varlistentry>
-			<varlistentry><term>label</term>
+			<varlistentry><term><parameter>label</parameter></term>
 			<listitem><para>If given, the optioncolumn will be displayed in the <optiondisplay> in a column by that label (optional, string, defaults to not displayed).</para></listitem></varlistentry>
-			<varlistentry><term>connect</term>
+			<varlistentry><term><parameter>connect</parameter></term>
 			<listitem><para>The property to connect this optioncolumn to, given as id inside the <content>-area. For external <optioncolumn>s, the corresponding value will be set to the externally set value. For regular (non-external) <optioncolumn>s,
 			the corresponding row of the <optioncolumn>-property, will be set when the property changes inside the content-area. (optional, string, defaults to not connected).</para></listitem></varlistentry>
-			<varlistentry><term>default</term>
+			<varlistentry><term><parameter>default</parameter></term>
 			<listitem><para>Only for external columns: The value to assume for this column, if no value is known for an entry. Rarely useful. (Optional, defaults to empty string)</para></listitem></varlistentry>
 		</variablelist>
 	</para></listitem></varlistentry>
@@ -2939,6 +2932,57 @@
 </varlistentry>
 
 <varlistentry>
+<term><switch></term>
+<listitem><para>Create a new property that will relay to different target properties (or fixed strings) based on the value of a condition property. This allows to create logic similar to <function>if()</function> or <function>switch()</function> constructs. Attributes:
+	<variablelist>
+	<varlistentry>
+	<term><parameter>id</parameter></term>
+	<listitem><para>The ID of the new property (required)</para></listitem>
+	</varlistentry>
+	<varlistentry>
+	<term><parameter>condition</parameter></term>
+	<listitem><para>The id of the condition property (required)</para></listitem>
+	</varlistentry>
+	</variablelist>
+Child elements:
+	<variablelist>
+	<varlistentry>
+	<term><true></term>
+	<listitem><para>If the condition property is boolean, you can specify the two child elements <true> and <false> (and only these). (Required, if <false> is also given)</para></listitem>
+	</varlistentry>
+	<varlistentry>
+	<term><false></term>
+	<listitem><para>If the condition property is boolean, you can specify the two child elements <true> and <false> (and only these). (Required, if <true> is also given)</para></listitem>
+	</varlistentry>
+	<varlistentry>
+	<term><case></term>
+	<listitem><para>If the condition property is not boolean, you can supply and arbitrary number of <case>-elements, one for each
+	value of the condition property that you want to match (at least one such element is required, if the condition property is not boolean)</para></listitem>
+	</varlistentry>
+	<varlistentry>
+	<term><default></term>
+	<listitem><para>If the condition property is not boolean, the optional <default>-element, allows to specify the behavior, if no
+	<case> element is matches the value of the condition property (optional, allowed only once, in combination with one or more <case> elements).</para></listitem>
+	</varlistentry>
+	</variablelist>
+Child elements <true>, <false>, <case>, and <default> take the following attributes:
+	<variablelist>
+	<varlistentry>
+	<term><parameter>standard</parameter></term>
+	<listitem><para>Only for <case>-elements: The value to match the condition property against (required, string).</para></listitem>
+	</varlistentry>
+	<varlistentry>
+	<term><parameter>fixed_value</parameter></term>
+	<listitem><para>A fixed string that should be supplied as the value of the <switch> property, if the current condition matches (required, if dynamic_value is not supplied).</para></listitem>
+	</varlistentry>
+	<varlistentry>
+	<term><parameter>dynamic_value</parameter></term>
+	<listitem><para>The <parameter>id</parameter> of the target property that should be supplied as the value of the <switch> property, if the current condition matches (required, if fixed_value is not supplied).</para></listitem>
+	</varlistentry>
+	</variablelist></para></listitem>
+</varlistentry>
+
+<varlistentry>
 <term><connect></term>
 <listitem><para>Connects two properties. The client property will be changed whenever the governor property changes (but not the other way around!). Attributes:
 	<variablelist>
@@ -3262,6 +3306,14 @@
 <term><convert></term>
 <listitem><para>This element (used in the <logic> section) is special, in that is technically *is* a property, instead of just holding one or more properties. It is of boolean kind. Note that useful modifiers of this property (as of all boolean properties) are "not" and "numeric" (see <link linkend="propertytypes">types of properties</link>)</para></listitem>
 </varlistentry>
+
+<varlistentry>
+<term><switch></term>
+<listitem><para>This element (used in the <logic> section) is special, in that is technically *is* a (string) property, instead of just holding one or more properties. It allows to switch between several target properties depending on the value of a condition property, or to re-map values of the condition property. Any modifiers that you supply are passed on to the target properties, thus, e.g. if all target
+properties are RObject properties, you can use the "shortname" modifier on the switch, too. However, if the target properties are of
+different types, using modifiers may lead to errors. For <replaceable>fixed_value</replaceable>s, any modifier is dropped, silently. Note that target properties, when accessed through a switch, are always read-only!</para></listitem>
+</varlistentry>
+
 </variablelist>
 </sect1>
 

Modified: trunk/rkward/rkward/plugin/rkcomponent.cpp
===================================================================
--- trunk/rkward/rkward/plugin/rkcomponent.cpp	2012-12-07 10:08:59 UTC (rev 4484)
+++ trunk/rkward/rkward/plugin/rkcomponent.cpp	2012-12-07 11:07:10 UTC (rev 4485)
@@ -41,6 +41,7 @@
 }
 
 RKComponentPropertyBase* RKComponentBase::lookupProperty (const QString &identifier, QString *remainder, bool warn) {
+	RK_TRACE (PLUGIN);
 	QString _remainder;
 	QString* p_remainder = remainder;
 	if (!remainder) p_remainder = &_remainder;

Modified: trunk/rkward/rkward/plugin/rkcomponent.h
===================================================================
--- trunk/rkward/rkward/plugin/rkcomponent.h	2012-12-07 10:08:59 UTC (rev 4484)
+++ trunk/rkward/rkward/plugin/rkcomponent.h	2012-12-07 11:07:10 UTC (rev 4485)
@@ -40,8 +40,9 @@
 		PropertyDouble = 4,
 		PropertyRObjects = 5,
 		PropertyCode = 6,
-		PropertyLogic = 7,
+		PropertyConvert = 7,
 		PropertyStringList = 8,
+		PropertySwitch = 9,
 		PropertyUser = 1000,		/**< for user expansion */
 		PropertyEnd = 1999,
 		ComponentBase = 2001,

Modified: trunk/rkward/rkward/plugin/rkcomponentproperties.cpp
===================================================================
--- trunk/rkward/rkward/plugin/rkcomponentproperties.cpp	2012-12-07 10:08:59 UTC (rev 4484)
+++ trunk/rkward/rkward/plugin/rkcomponentproperties.cpp	2012-12-07 11:07:10 UTC (rev 4485)
@@ -1150,11 +1150,10 @@
 	sourcePropertyChanged (0);
 }
 
-void RKComponentPropertyConvert::setSources (const QString &source_string) {
+void RKComponentPropertyConvert::setSources (const QStringList &source_ids) {
 	RK_TRACE (PLUGIN);
 
 	sources.clear ();
-	QStringList source_ids = source_string.split (";");
 	for (QStringList::const_iterator it = source_ids.constBegin (); it != source_ids.constEnd (); ++it) {
 		Source s;
 		RKComponentBase *prop = c_parent->lookupComponent (*it, &(s.modifier));
@@ -1277,4 +1276,99 @@
 	return is_valid;
 }
 
+void RKComponentPropertyConvert::connectToGovernor (RKComponentPropertyBase*, const QString&, bool) {
+	RK_DEBUG (PLUGIN, DL_ERROR, "Cannot connect a <convert> property to a governor");
+}
+
+bool RKComponentPropertyConvert::setValue (const QString&) {
+	RK_DEBUG (PLUGIN, DL_ERROR, "Cannot set value for a <convert> property");
+	return false;
+}
+
+/////////////////////////////////////////// Switch ////////////////////////////////////////////////
+
+RKComponentPropertySwitch::RKComponentPropertySwitch (RKComponent* parent, const QStringList& def_values, const QStringList& standards) : RKComponentPropertyBase (parent, false) {
+	RK_TRACE (PLUGIN);
+
+	RKComponentPropertySwitch::def_values = def_values;
+	RKComponentPropertySwitch::standards = standards;
+	condition_prop = 0;
+	c_parent = parent;
+
+	connect (this, SIGNAL(valueChanged(RKComponentPropertyBase*)), this, SLOT(selfChanged(RKComponentPropertyBase*)));
+}
+
+RKComponentPropertySwitch::~RKComponentPropertySwitch () {
+	RK_TRACE (PLUGIN);
+}
+
+void RKComponentPropertySwitch::connectToGovernor (RKComponentPropertyBase*, const QString&, bool) {
+	RK_DEBUG (PLUGIN, DL_ERROR, "Cannot connect a <switch> property to a governor");
+}
+
+bool RKComponentPropertySwitch::setValue (const QString& value) {
+	RK_DEBUG (PLUGIN, DL_ERROR, "Cannot set value for a <switch> property");
+	return false;
+}
+
+void RKComponentPropertySwitch::selfChanged (RKComponentPropertyBase *) {
+	RK_TRACE (PLUGIN);
+	c_parent->changed ();
+}
+
+void RKComponentPropertySwitch::sourcePropertyChanged (RKComponentPropertyBase*) {
+	RK_TRACE (PLUGIN);
+	valueChanged (this);	// new value will be pulled by anyone interested
+}
+
+QVariant RKComponentPropertySwitch::value (const QString& modifier) {
+	RK_TRACE (PLUGIN);
+
+	if (!condition_prop) {
+		RK_ASSERT (false);
+		return QVariant ();
+	}
+	QVariant cond = condition_prop->value (condition_prop_modifier);
+	int index = 0;
+	if (standards.isEmpty ()) {
+		if (RKComponentPropertyBool::variantToBool (cond, 0)) index = 1;
+	} else {
+		index = standards.indexOf (cond.toString ());		// NOTE: list search. Could use a hash, instead, but in general there won't be more than a hand full of standards
+		if (index < 0) index = standards.size ();	// remainder-category
+	}
+
+	// First try to return matching property
+	RKComponentPropertyBase *p = value_props.value (index);
+	if (p) {
+		QString mod = value_prop_mods.value (index);
+		if (!(mod.isEmpty () || modifier.isEmpty ())) mod.append (".");
+		mod.append (modifier);
+		return p->value (mod);
+	}
+
+	// If that fails, try to find a static default string
+	if (index < def_values.size ()) {
+		return def_values[index];	// NOTE: silently dropping modifier. This is useful for static "other" strings.
+	}
+
+	RK_DEBUG (PLUGIN, DL_ERROR, "Neither a fixed value, nor a property is defined for value %s (element %d/%d of standards)", qPrintable (cond.toString ()), index + 1, standards.size ());
+	return QVariant ();
+}
+
+void RKComponentPropertySwitch::setSources (const QString& _condition_prop, const QStringList& _value_props) {
+	RK_TRACE (PLUGIN);
+	RK_ASSERT (!condition_prop);	// must only be called once
+
+	condition_prop = c_parent->lookupProperty (_condition_prop, &condition_prop_modifier, true);
+	if (!condition_prop) RK_DEBUG (PLUGIN, DL_ERROR, "Not a valid condition to connect <switch> property to: %s", qPrintable (_condition_prop));
+
+	for (int i = 0; i < _value_props.size (); ++i) {
+		QString mod;
+		RKComponentPropertyBase *p = c_parent->lookupProperty (_value_props[i], &mod, true);
+		value_props.append (p);	// NOTE: Even if it is 0. value() takes care of that.
+		value_prop_mods.append (mod);
+		if (p) connect (p, SIGNAL (valueChanged(RKComponentPropertyBase*)), this, SLOT (sourcePropertyChanged(RKComponentPropertyBase*)));
+	}
+}
+
 #include "rkcomponentproperties.moc"

Modified: trunk/rkward/rkward/plugin/rkcomponentproperties.h
===================================================================
--- trunk/rkward/rkward/plugin/rkcomponentproperties.h	2012-12-07 10:08:59 UTC (rev 4484)
+++ trunk/rkward/rkward/plugin/rkcomponentproperties.h	2012-12-07 11:07:10 UTC (rev 4485)
@@ -387,6 +387,7 @@
 /** constructor. Note that this property *requires* an RKComponent as parent (the one at the top of all the source properties) */
 	RKComponentPropertyConvert (RKComponent *parent);
 	~RKComponentPropertyConvert ();
+	int type () { return PropertyConvert; };
 
 /** Mode of operation. see setMode () */
 	enum ConvertMode {
@@ -400,7 +401,7 @@
 /** set the mode. Usually you will only call this once, after construction, and usually followed by setSources () - if applicable - setStandard () or setRange (). */
 	void setMode (ConvertMode mode);
 /** set the sources, i.e. the properties to check against. To specify multiple sources, separate their IDs with ";" */
-	void setSources (const QString &source_string);
+	void setSources (const QStringList &sources);
 /** set the standard for comparison. Only meaningful in Equals mode */
 	void setStandard (const QString &standard);
 /** set the range for comparison. Only meaningful in Range mode */
@@ -413,6 +414,10 @@
 
 /** string represenation of the options in ConvertMode. For use in XMLHelper::getMultiChoiceAttribute */
 	static QString convertModeOptionString () { return ("equals;notequals;range;and;or"); };
+/** reimplemented to do raise a warning, and do nothing else. */
+	void connectToGovernor (RKComponentPropertyBase *governor, const QString &modifier=QString::null, bool reconcile_requirements=true);
+/** reimplemented to do raise a warning, and do nothing else. */
+	bool setValue (const QString &value);
 public slots:
 /** unfortuntely, as the parent component likely does not know about us, we have to notify it manually of any changes. That's done from this slot */
 	void selfChanged (RKComponentPropertyBase *);
@@ -431,5 +436,38 @@
 	QList<Source> sources;
 };
 
+/** This special property corresponds to a switch-statement, switching between two or more separate governing props based on the value of a condition prop. */
+class RKComponentPropertySwitch : public RKComponentPropertyBase {
+	Q_OBJECT
+public:
+/** constructor. Note that this property *requires* an RKComponent as parent (the one at the top of all the source properties)
+ @param standards the values to match against. Note: Providing an empty list make the switch operate in boolean mode,
+ switching between the first two sources / values, based on the boolean value of the condition_prop. */
+	RKComponentPropertySwitch (RKComponent *parent, const QStringList& def_values, const QStringList& standards);
+	~RKComponentPropertySwitch ();
+
+/** set the sources, i.e. the properties to operate on */
+	void setSources (const QString &condition_prop, const QStringList &value_props);
+/** reimplemented to do raise a warning, and do nothing else. */
+	void connectToGovernor (RKComponentPropertyBase *governor, const QString &modifier=QString::null, bool reconcile_requirements=true);
+/** reimplemented to do raise a warning, and do nothing else. */
+	bool setValue (const QString &value);
+
+	QVariant value (const QString &modifier=QString ());
+	int type () { return PropertySwitch; };
+public slots:
+/** unfortuntely, as the parent component likely does not know about us, we have to notify it manually of any changes. That's done from this slot */
+	void selfChanged (RKComponentPropertyBase *);
+/** a source property changed. Check the state */
+	void sourcePropertyChanged (RKComponentPropertyBase *);
+private:
+	RKComponent *c_parent;		// actually the same as parent (), but without the hassle of conversion
+	QStringList def_values;
+	QStringList standards;
+	RKComponentPropertyBase *condition_prop;
+	QString condition_prop_modifier;
+	QList<RKComponentPropertyBase*> value_props;
+	QStringList value_prop_mods;
+};
+
 #endif
-

Modified: trunk/rkward/rkward/plugin/rkstandardcomponent.cpp
===================================================================
--- trunk/rkward/rkward/plugin/rkstandardcomponent.cpp	2012-12-07 10:08:59 UTC (rev 4484)
+++ trunk/rkward/rkward/plugin/rkstandardcomponent.cpp	2012-12-07 11:07:10 UTC (rev 4485)
@@ -721,6 +721,7 @@
 	}
 
 	// find convert elements
+	QMap<RKComponentPropertyBase*, QStringList> switch_convert_sources;
 	children = xml->getChildElements (element, "convert", DL_INFO);
 	for (it = children.constBegin (); it != children.constEnd (); ++it) {
 		RKComponentPropertyConvert *convert = new RKComponentPropertyConvert (component ());
@@ -733,12 +734,72 @@
 		} else if (mode == RKComponentPropertyConvert::Range) {
 			convert->setRange (xml->getDoubleAttribute (*it, "min", -FLT_MAX, DL_INFO), xml->getDoubleAttribute (*it, "max", FLT_MAX, DL_INFO));
 		}
-		QString sources = xml->getStringAttribute (*it, "sources", QString::null, DL_WARNING);
-		convert->setSources (sources);
+		switch_convert_sources.insert (convert, xml->getStringAttribute (*it, "sources", QString::null, DL_WARNING).split (';'));
 		convert->setRequireTrue (xml->getBoolAttribute (*it, "require_true", false, DL_INFO));
 		component ()->addChild (id, convert);
 	}
 
+	// find switch elements
+	children = xml->getChildElements (element, "switch", DL_INFO);
+	for (it = children.constBegin (); it != children.constEnd (); ++it) {
+		QDomElement t = xml->getChildElement (*it, "true", DL_INFO);
+		QDomElement f = xml->getChildElement (*it, "false", DL_INFO);
+		if (t.isNull () != f.isNull ()) {
+			xml->displayError (&(*it), "One of <true> / <false> was provided for boolean <switch>, but not the other. Skipping switch.", DL_ERROR);
+			continue;
+		}
+
+		XMLChildList case_elems = xml->getChildElements (*it, "case", DL_INFO);
+		QDomElement default_elem = xml->getChildElement (*it, "default", DL_INFO);
+		if (!default_elem.isNull ()) case_elems.append (default_elem);
+
+		if (t.isNull ()) {
+			if (case_elems.isEmpty ()) {
+				xml->displayError (&(*it), "Neither <true> / <false> nor <case> / <default> were provided. Skipping switch.", DL_ERROR);
+				continue;
+			}
+		} else {
+			if (!case_elems.isEmpty ()) {
+				xml->displayError (&(*it), "One <true> / <false> *or* <case> / <default> may be provided a <switch>. Proceeding with boolean switch.", DL_ERROR);
+				case_elems.clear ();
+			}
+			case_elems.append (f);
+			case_elems.append (t);
+		}
+
+		QStringList def_strings;
+		QStringList standards;
+		QStringList sources;
+		sources.append (xml->getStringAttribute (*it, "condition", QString (), DL_ERROR));	// store condition prop as first "source"
+
+		for (XMLChildList::const_iterator cit = case_elems.constBegin (); cit != case_elems.constEnd (); ++cit) {
+			def_strings.append (xml->getStringAttribute (*cit, "fixed_value", QString (), DL_INFO));
+			sources.append (xml->getStringAttribute (*cit, "dynamic_value", QString (), DL_INFO));
+			if ((*cit).tagName () == "case") standards.append (xml->getStringAttribute (*cit, "standard", QString (), DL_WARNING));
+		}
+
+		QString id = xml->getStringAttribute (*it, "id", "#noid#", DL_WARNING);
+		RKComponentPropertySwitch *switchel = new RKComponentPropertySwitch (component (), def_strings, standards);
+		switchel->setInternal (true);
+		switch_convert_sources.insert (switchel, sources);
+		component ()->addChild (id, switchel);
+	}
+
+	// resolve source properties for switch and convert elements, *after* all properties have been created
+	for (QMap<RKComponentPropertyBase*, QStringList>::const_iterator it = switch_convert_sources.constBegin (); it != switch_convert_sources.constEnd (); ++it) {
+		if (it.key ()->type () == RKComponentBase::PropertyConvert) {
+			static_cast<RKComponentPropertyConvert*> (it.key ())->setSources (it.value ());
+		} else {
+			RK_ASSERT (it.key ()->type () == RKComponentBase::PropertySwitch);
+			QStringList sources = it.value ();
+			if (sources.isEmpty ()) {
+				RK_ASSERT (!sources.isEmpty ());
+				continue;
+			}
+			static_cast<RKComponentPropertySwitch*> (it.key ())->setSources (sources.takeFirst (), sources);
+		}
+	}
+
 	QDomElement e = xml->getChildElement (element, "script", DL_INFO);
 	if (!e.isNull () && allow_script_tag) {
 		QString file = xml->getStringAttribute (e, "file", QString (), DL_INFO);

Modified: trunk/rkward/rkward/plugins/data/sort.xml
===================================================================
--- trunk/rkward/rkward/plugins/data/sort.xml	2012-12-07 10:08:59 UTC (rev 4484)
+++ trunk/rkward/rkward/plugins/data/sort.xml	2012-12-07 11:07:10 UTC (rev 4485)
@@ -77,6 +77,10 @@
 					<logic>
 						<convert id="custom_conversion" mode="equals" sources="conversion.string" standard="custom"/>
 						<connect governor="custom_conversion" client="conversion_custom.enabled"/>
+						<switch id="conversion_label" condition="custom_conversion">
+							<false dynamic_value="conversion.string"/>
+							<true dynamic_value="conversion_custom.text"/>
+						</switch>
 					</logic>
 					<content>
 						<optiondisplay index="true"/>
@@ -86,7 +90,8 @@
 					<optioncolumn id="object" external="true"/>
 					<optioncolumn id="objectshort" external="true" label="Object"/>
 					<optioncolumn id="reverse" label="Order" connect="reverse.state.labeled"/>
-					<optioncolumn id="conversion" label="Sort mode" connect="conversion.string"/>
+					<optioncolumn id="conversion" connect="conversion.string"/>
+					<optioncolumn id="conversion_label" label="Sort mode" connect="conversion_label"/>
 					<optioncolumn id="conversion_custom" connect="conversion_custom.text"/>
 				</optionset>
 				<stretch/>

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