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

tfry at users.sf.net tfry at users.sf.net
Fri May 3 14:49:27 UTC 2013


Revision: 4739
          http://sourceforge.net/p/rkward/code/4739
Author:   tfry
Date:     2013-05-03 14:49:21 +0000 (Fri, 03 May 2013)
Log Message:
-----------
Add option allow_duplicates in <varslot>

Modified Paths:
--------------
    trunk/rkward/ChangeLog
    trunk/rkward/doc/rkwardplugins/index.docbook
    trunk/rkward/rkward/plugin/rkcomponentproperties.cpp
    trunk/rkward/rkward/plugin/rkcomponentproperties.h
    trunk/rkward/rkward/plugin/rkvarslot.cpp
    trunk/rkward/rkward/plugin/rkvarslot.h
    trunk/rkward/rkward/plugins/plots/scatterplot.xml

Modified: trunk/rkward/ChangeLog
===================================================================
--- trunk/rkward/ChangeLog	2013-05-01 17:56:55 UTC (rev 4738)
+++ trunk/rkward/ChangeLog	2013-05-03 14:49:21 UTC (rev 4739)
@@ -1,3 +1,4 @@
+- <varslots> can be set to accept the same object several times. Used in scatterplot plugin.
 - New R function rk.embed.device() for manually embedding graphics devices in RKWard
 - Fixed: R backend would exit immediately, without meaningful error message, if there is an error in .Rprofile (or Rprofile.site)
 - Fixed: Installing suggested packages from the package installation dialog was broken

Modified: trunk/rkward/doc/rkwardplugins/index.docbook
===================================================================
--- trunk/rkward/doc/rkwardplugins/index.docbook	2013-05-01 17:56:55 UTC (rev 4738)
+++ trunk/rkward/doc/rkwardplugins/index.docbook	2013-05-03 14:49:21 UTC (rev 4739)
@@ -56,8 +56,8 @@
      and in the FDL itself on how to use it. -->
 <legalnotice>&FDLNotice;</legalnotice>
 
-<date>2012-11-28</date>
-<releaseinfo>0.6.1.00</releaseinfo>
+<date>2013-05-03</date>
+<releaseinfo>0.6.2.00</releaseinfo>
 
 <abstract>
 <para>
@@ -2545,6 +2545,10 @@
 	<listitem><para>Whether the varslot holds only one (default, "false"), or several objects</para></listitem>
 	</varlistentry>
 	<varlistentry>
+	<term><parameter>allow_duplicates</parameter></term>
+	<listitem><para>Whether the varslot may accept only unique objects (default, "false"), or if the same object may be added several times.</para></listitem>
+	</varlistentry>
+	<varlistentry>
 	<term><parameter>min_vars</parameter></term>
 	<listitem><para>Only meaningful if multi="true": Minimum number of vars to be selected for the selection to be considered valid (optional, defaults to "1")</para></listitem>
 	</varlistentry>

Modified: trunk/rkward/rkward/plugin/rkcomponentproperties.cpp
===================================================================
--- trunk/rkward/rkward/plugin/rkcomponentproperties.cpp	2013-05-01 17:56:55 UTC (rev 4738)
+++ trunk/rkward/rkward/plugin/rkcomponentproperties.cpp	2013-05-03 14:49:21 UTC (rev 4739)
@@ -158,6 +158,7 @@
 RKComponentPropertyAbstractList::RKComponentPropertyAbstractList (QObject* parent, bool required) : RKComponentPropertyBase (parent, required) {
 	RK_TRACE (PLUGIN);
 	setAllowedLength ();
+	setStripDuplicates (false);
 }
 
 RKComponentPropertyAbstractList::~RKComponentPropertyAbstractList () {
@@ -252,6 +253,8 @@
 void RKComponentPropertyStringList::setValueAt (int index, const QString& value) {
 	RK_TRACE (PLUGIN);
 	
+	if (getStripDuplicates () && storage.contains (value)) return;
+	
 	while (index >= storage.size ()) storage.append (QString ());	// expand as needed
 	storage[index] = value;
 	doChange ();
@@ -266,6 +269,27 @@
 	}
 }
 
+void RKComponentPropertyStringList::checkStripDuplicates () {
+	if (!getStripDuplicates ()) return;
+	RK_TRACE (PLUGIN);
+
+	QStringList unique;
+	for (int i = 0; i < storage.size (); ++i) {
+		if (!unique.contains (storage[i])) unique.append (storage[i]);
+	}
+	storage = unique;
+}
+
+void RKComponentPropertyStringList::removeAt (int index) {
+	RK_TRACE (PLUGIN);
+	if ((index < 0) || (index >= storage.size ())) {
+		RK_ASSERT (false);
+		return;
+	}
+	storage.removeAt (index);
+	doChange ();
+}
+
 ///////////////////////////////////////////// Bool //////////////////////////////////////////
 
 RKComponentPropertyBool::RKComponentPropertyBool (QObject *parent, bool required, bool default_state, const QString &value_true, const QString &value_false) : RKComponentPropertyBase (parent, required) {
@@ -753,6 +777,7 @@
 
 // no initial requirements
 	dims = min_length = max_length;
+	setStripDuplicates (true);      // legacy default
 
 	addNotificationType (RObjectListener::ObjectRemoved);
 	addNotificationType (RObjectListener::MetaChanged);
@@ -761,13 +786,13 @@
 RKComponentPropertyRObjects::~RKComponentPropertyRObjects () {
 	RK_TRACE (PLUGIN);
 
-	setObjectValue (0);
+	setObjectValueSilent (0);
 }
 
 bool RKComponentPropertyRObjects::addObjectValue (RObject *object) {
 	RK_TRACE (PLUGIN);
 
-	if (appendObject (object)) {
+	if (addObjectValueSilent (object)) {
 		updateValidity ();
 		emit (valueChanged (this));
 		return isValid ();
@@ -775,22 +800,25 @@
 	return false;
 }
 
-bool RKComponentPropertyRObjects::appendObject (RObject *object) {
-	if ((!object) || object_list.contains (object)) return false;
+bool RKComponentPropertyRObjects::addObjectValueSilent (RObject *object) {
+	if (!object) return false;
+	bool is_dupe = object_list.contains (object);
+	if (getStripDuplicates () && is_dupe) return false;
 
 	object_list.append (object);
-	QString probs = checkObjectProblems (object);
-	if (!probs.isEmpty ()) problems.insert (object, probs);
-	listenForObject (object);
+	if (!is_dupe) {
+		QString probs = checkObjectProblems (object);
+		if (!probs.isEmpty ()) problems.insert (object, probs);
+		listenForObject (object);
+	}
 	return true;
 }
 
 void RKComponentPropertyRObjects::objectRemoved (RObject *object) {
 	RK_TRACE (PLUGIN);
 
-	int index = object_list.indexOf (object);
-	if (index >= 0) {
-		object_list.removeAt (index);
+	int removals = object_list.removeAll (object);
+	if (removals) {
 		problems.remove (object);
 		stopListenForObject (object);
 		updateValidity ();
@@ -798,6 +826,18 @@
 	}
 }
 
+void RKComponentPropertyRObjects::removeAt (int index) {
+	RK_TRACE (PLUGIN);
+	if ((index < 0) || (index >= object_list.size ())) {
+		RK_ASSERT (false);
+		return;
+	}
+	RObject* obj = object_list.takeAt (index);
+	if (!object_list.contains (obj)) stopListenForObject (obj);
+	updateValidity ();
+	emit (valueChanged (this));
+}
+
 void RKComponentPropertyRObjects::setClassFilter (const QStringList &classes) {
 	RK_TRACE (PLUGIN);
 
@@ -821,40 +861,33 @@
 	validizeAll ();
 }
 
-bool RKComponentPropertyRObjects::setObjectValue (RObject *object) {
+bool RKComponentPropertyRObjects::setObjectValueSilent (RObject* object) {
 	RK_TRACE (PLUGIN);
 
 	problems.clear ();
-	while (!object_list.isEmpty ()) {
-		stopListenForObject (object_list.takeAt (0));
+	QSet<RObject*> unique = object_list.toSet ();
+	foreach (RObject *obj, unique) {
+		stopListenForObject (obj);
 	}
-	return (addObjectValue (object));
+	object_list.clear ();
+	return (addObjectValueSilent (object));
 }
 
+bool RKComponentPropertyRObjects::setObjectValue (RObject *object) {
+	setObjectValueSilent (object);
+	updateValidity ();
+	emit (valueChanged (this));
+	return isValid ();
+}
+
 void RKComponentPropertyRObjects::setObjectList (const RObject::ObjectList &newlist) {
 	RK_TRACE (PLUGIN);
 
-	bool changes = false;
-
-	// remove items from the old list that are not in the new list
-	for (int i = 0; i < object_list.size (); ++i) {
-		RObject *object = object_list[i];
-		if (!newlist.contains (object)) {
-			stopListenForObject (object_list.takeAt (i));
-			problems.remove (object);
-			--i;
-			changes = true;
+	if (newlist != object_list) {
+		setObjectValueSilent (0);
+		for (int i = 0; i < newlist.size (); ++i) {
+			addObjectValueSilent (newlist[i]);
 		}
-	}
-
-	// now add items from the new list that are not in the old list
-	for (int i = 0; i < newlist.size (); ++i) {
-		RObject *obj = newlist[i];
-		if (appendObject (obj)) changes = true;
-	}
-
-	// emit a signal if there have been any changes
-	if (changes) {
 		updateValidity ();
 		emit (valueChanged (this));
 	}
@@ -945,7 +978,7 @@
 	bool ok = true;
 	for (int i = 0; i < values.size (); ++i) {
 		RObject *obj = RObjectList::getObjectList ()->findObject (values[i]);
-		ok = ok && appendObject (obj);
+		ok = ok && addObjectValueSilent (obj);
 	}
 
 	updateValidity ();

Modified: trunk/rkward/rkward/plugin/rkcomponentproperties.h
===================================================================
--- trunk/rkward/rkward/plugin/rkcomponentproperties.h	2013-05-01 17:56:55 UTC (rev 4738)
+++ trunk/rkward/rkward/plugin/rkcomponentproperties.h	2013-05-03 14:49:21 UTC (rev 4739)
@@ -85,7 +85,11 @@
 	bool atMaxLength () const { return (max_num_items && (max_num_items <= listLength ())); };
 /** reimplemented from RKComponentPropertyBase to actually reconcile requirements with other list properties */
 	void connectToGovernor (RKComponentPropertyBase *governor, const QString &modifier=QString::null, bool reconcile_requirements=true);
+/** If set to true, duplicate values are dropped, silently */
+	void setStripDuplicates (bool strip) { strip_duplicates = strip; };
+	virtual void removeAt (int index) = 0;
 protected:
+	bool getStripDuplicates () const { return strip_duplicates; };
 	bool checkListLength ();
 	virtual int listLength () const = 0;
 	void reconcileLengthRequirements (RKComponentPropertyAbstractList *governor);
@@ -94,6 +98,7 @@
 	int min_num_items;
 	int min_num_items_if_any;
 	int max_num_items;
+	bool strip_duplicates;
 };
 
 /////////////////////////////////////////////// StringList /////////////////////////////////////////////////////
@@ -117,12 +122,14 @@
 /** get all current strings as a QStringList */
 	const QStringList& values () const { return storage; };
 /** set current strings as a QStringList */
-	void setValues (const QStringList &new_values) { storage = new_values; doChange (); };
+	void setValues (const QStringList &new_values) { storage = new_values; checkStripDuplicates (); doChange (); };
 /** reimplemented from RKComponentPropertyBase to use special handling for list properties */
 	void governorValueChanged (RKComponentPropertyBase *property);
 	int listLength () const { return (storage.size ()); };
+	void removeAt (int index);
 private:
 	void doChange () { _value.clear (); emit (valueChanged (this)); };
+	void checkStripDuplicates ();
 	QStringList storage;
 };
 
@@ -323,7 +330,7 @@
 	void connectToGovernor (RKComponentPropertyBase *governor, const QString &modifier=QString::null, bool reconcile_requirements=true);
 /** reimplemented from RKComponentPropertyBase to use special handling for object properties */
 	void governorValueChanged (RKComponentPropertyBase *property);
-	void removeObjectValue (RObject* object) { objectRemoved (object); };
+	void removeAt (int index);
 	int listLength () const { return (object_list.size ()); };
 protected:
 /** remove an object value. reimplemented from RObjectListener::objectRemoved (). This is so we get notified if the object currently selected is removed TODO: is this effectively a duplication of setFromList? */
@@ -337,7 +344,8 @@
 	void updateValidity ();
 /** internal helper to add the object (and check it for problems).
  * @returns true, if the list was changed, false, if the object was already in the list or is 0. */
-	bool appendObject (RObject *object);
+	bool addObjectValueSilent (RObject *object);
+	bool setObjectValueSilent (RObject *object);
 /** Check any object for problems */
 	QString checkObjectProblems (RObject *object) const;
 	RObject::ObjectList object_list;

Modified: trunk/rkward/rkward/plugin/rkvarslot.cpp
===================================================================
--- trunk/rkward/rkward/plugin/rkvarslot.cpp	2013-05-01 17:56:55 UTC (rev 4738)
+++ trunk/rkward/rkward/plugin/rkvarslot.cpp	2013-05-03 14:49:21 UTC (rev 4739)
@@ -37,6 +37,7 @@
 	RK_TRACE (PLUGIN);
 
 	XMLHelper *xml = XMLHelper::getStaticHelper ();
+	updating = false;
 
 	// basic layout
 	QGridLayout *g_layout = new QGridLayout (this);
@@ -91,6 +92,7 @@
 	setRequired (xml->getBoolAttribute (element, "required", false, DL_INFO));
 	available->setTypeFilter (xml->getStringAttribute (element, "types", QString::null, DL_INFO).split (" ", QString::SkipEmptyParts));
 	available->setDimensionFilter (xml->getIntAttribute (element, "num_dimensions", 0, DL_INFO), xml->getIntAttribute (element, "min_length", 0, DL_INFO), xml->getIntAttribute (element, "max_length", INT_MAX, DL_INFO));
+	available->setStripDuplicates (!xml->getBoolAttribute (element, "allow_duplicates", false, DL_INFO));
 
 	connect (available, SIGNAL (valueChanged (RKComponentPropertyBase *)), this, SLOT (availablePropertyChanged (RKComponentPropertyBase *)));
 	availablePropertyChanged (available);		// initialize
@@ -125,6 +127,8 @@
 void RKVarSlot::availablePropertyChanged (RKComponentPropertyBase *) {
 	RK_TRACE (PLUGIN);
 
+	if (updating) return;
+
 	list->clear ();
 	item_map.clear ();
 
@@ -173,6 +177,7 @@
 
 	RK_DEBUG (PLUGIN, DL_DEBUG, "select press in varslot: mode %d, source %s, selected %s", add_mode, qPrintable (fetchStringValue (source)), qPrintable (fetchStringValue (selected)));
 
+	updating = true;
 	// first update the properties
 	if (add_mode) {
 		if (multi) {
@@ -186,20 +191,19 @@
 			if (source->objectValue ()) available->setObjectValue (source->objectValue ());
 		}
 	} else {		// remove-mode
-		RObject::ObjectList objlist;
-		if (multi) {
-			objlist = selected->objectList ();
-		} else {
-			objlist = available->objectList ();
+		QModelIndexList removed = list->selectionModel ()->selectedRows (0);       // Note: list contains no dupes, but is unsorted.
+		QList<int> removed_rows;
+		for (int i = 0; i < removed.size (); ++i) {
+			removed_rows.append (removed[i].row ());
 		}
-
-		RObject::ObjectList::const_iterator it = objlist.begin ();
-		while (it != objlist.end ()) {
-			available->removeObjectValue (*it);
-			selected->removeObjectValue (*it);
-			++it;
+		qSort (removed_rows);
+		for (int i = removed_rows.size () - 1; i >= 0; --i) {
+			available->removeAt (removed_rows[i]);
 		}
+		selected->setObjectValue (0);
 	}
+	updating = false;
+	availablePropertyChanged (available);
 }
 
 #include "rkvarslot.moc"

Modified: trunk/rkward/rkward/plugin/rkvarslot.h
===================================================================
--- trunk/rkward/rkward/plugin/rkvarslot.h	2013-05-01 17:56:55 UTC (rev 4738)
+++ trunk/rkward/rkward/plugin/rkvarslot.h	2013-05-03 14:49:21 UTC (rev 4739)
@@ -59,6 +59,7 @@
 	void setSelectButton (bool add);
 	bool add_mode;
 	bool multi;
+	bool updating;
 
 /** the available objects (typically a copy of the property of the varselector) */
 	RKComponentPropertyRObjects *source;

Modified: trunk/rkward/rkward/plugins/plots/scatterplot.xml
===================================================================
--- trunk/rkward/rkward/plugins/plots/scatterplot.xml	2013-05-01 17:56:55 UTC (rev 4738)
+++ trunk/rkward/rkward/plugins/plots/scatterplot.xml	2013-05-03 14:49:21 UTC (rev 4739)
@@ -21,8 +21,8 @@
 					<varselector id="vars" />
 					<column>
 						<row>
-							<varslot multi="true" duplicate="true" types="number unknown" id="x" source="vars" label="'X' variables" required="true" />
-							<varslot multi="true" duplicate="true" types="number unknown" id="y" source="vars" label="'Y' variables" required="true" />
+							<varslot multi="true" allow_duplicates="true" types="number unknown" id="x" source="vars" label="'X' variables" required="true" />
+							<varslot multi="true" allow_duplicates="true" types="number unknown" id="y" source="vars" label="'Y' variables" required="true" />
 						</row>
 						<preview id="preview"/>
 					</column>





More information about the rkward-tracker mailing list