<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://www.vistrails.org//index.php?action=history&amp;feed=atom&amp;title=Module_Configuration_Example</id>
	<title>Module Configuration Example - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://www.vistrails.org//index.php?action=history&amp;feed=atom&amp;title=Module_Configuration_Example"/>
	<link rel="alternate" type="text/html" href="https://www.vistrails.org//index.php?title=Module_Configuration_Example&amp;action=history"/>
	<updated>2026-05-05T11:36:06Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.36.2</generator>
	<entry>
		<id>https://www.vistrails.org//index.php?title=Module_Configuration_Example&amp;diff=6196&amp;oldid=prev</id>
		<title>Dakoop: /* widgets.py */</title>
		<link rel="alternate" type="text/html" href="https://www.vistrails.org//index.php?title=Module_Configuration_Example&amp;diff=6196&amp;oldid=prev"/>
		<updated>2013-10-07T18:44:05Z</updated>

		<summary type="html">&lt;p&gt;&lt;span dir=&quot;auto&quot;&gt;&lt;span class=&quot;autocomment&quot;&gt;widgets.py&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 18:44, 7 October 2013&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l157&quot;&gt;Line 157:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 157:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;     def refresh_module(self):&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;     def refresh_module(self):&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;         self.controller.flush_delayed_actions()&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;         self.controller.flush_delayed_actions()&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;         self.controller.current_pipeline_view.recreate_module(&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt; &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;            &lt;/del&gt;self.controller.current_pipeline, self.module.id)&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;        # need to check this for 2.0 versus 2.1:&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;         &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;if hasattr(self.controller, 'current_pipeline_scene'):&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;            scene = self.controller.current_pipeline_scene&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;        else:&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;            scene = &lt;/ins&gt;self.controller.current_pipeline_view&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;        scene&lt;/ins&gt;.recreate_module(self.controller.current_pipeline, self.module.id)&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;          &lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;          &lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;     def saveTriggered(self):&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;     def saveTriggered(self):&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;

&lt;!-- diff cache key wikidb-vistrails_:diff::1.12:old-6169:rev-6196 --&gt;
&lt;/table&gt;</summary>
		<author><name>Dakoop</name></author>
	</entry>
	<entry>
		<id>https://www.vistrails.org//index.php?title=Module_Configuration_Example&amp;diff=6169&amp;oldid=prev</id>
		<title>Dakoop at 00:41, 2 October 2013</title>
		<link rel="alternate" type="text/html" href="https://www.vistrails.org//index.php?title=Module_Configuration_Example&amp;diff=6169&amp;oldid=prev"/>
		<updated>2013-10-02T00:41:01Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 00:41, 2 October 2013&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l6&quot;&gt;Line 6:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 6:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;In future versions of VisTrails, we expect to streamline the process and make the API cleaner.  Expect a per-module &amp;lt;code&amp;gt;_settings&amp;lt;/code&amp;gt; field that allows settings like the configuration widget to be specified with the module definition as well as support for named arguments so that port and settings definitions are more understandable.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;In future versions of VisTrails, we expect to streamline the process and make the API cleaner.  Expect a per-module &amp;lt;code&amp;gt;_settings&amp;lt;/code&amp;gt; field that allows settings like the configuration widget to be specified with the module definition as well as support for named arguments so that port and settings definitions are more understandable.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;[[File:custom_module_config.png|center]]&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br/&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==== Example Code for VisTrails 2.0+ ====&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==== Example Code for VisTrails 2.0+ ====&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;

&lt;!-- diff cache key wikidb-vistrails_:diff::1.12:old-6166:rev-6169 --&gt;
&lt;/table&gt;</summary>
		<author><name>Dakoop</name></author>
	</entry>
	<entry>
		<id>https://www.vistrails.org//index.php?title=Module_Configuration_Example&amp;diff=6166&amp;oldid=prev</id>
		<title>Dakoop: Created page with 'A ''module configuration widget'' is a widget that is shown in the module configuration panel (of the Tools window) when a user selects a module.  For many modules, there is no s…'</title>
		<link rel="alternate" type="text/html" href="https://www.vistrails.org//index.php?title=Module_Configuration_Example&amp;diff=6166&amp;oldid=prev"/>
		<updated>2013-10-02T00:21:28Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;#039;A &amp;#039;&amp;#039;module configuration widget&amp;#039;&amp;#039; is a widget that is shown in the module configuration panel (of the Tools window) when a user selects a module.  For many modules, there is no s…&amp;#039;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;A ''module configuration widget'' is a widget that is shown in the module configuration panel (of the Tools window) when a user selects a module.  For many modules, there is no specific configuration widget, and the panel informs users to set parameters via the Module Information panel (on the right side of the main window).  However, other built-in modules like PythonSource have custom widgets.  Any module may specify its own configuration widget via the &amp;lt;code&amp;gt;configureWidgetType&amp;lt;/code&amp;gt; setting.&lt;br /&gt;
&lt;br /&gt;
The current &amp;lt;code&amp;gt;StandardConfigurationWidget&amp;lt;/code&amp;gt; requires only a couple of methods (&amp;lt;code&amp;gt;saveTriggered&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;resetTriggered&amp;lt;/code&amp;gt;), but it is not very clear what needs to be implemented and where.  Below, we have written a &amp;lt;code&amp;gt;ModuleConfigurationWidgetBase&amp;lt;/code&amp;gt; that attempts to abstract much of the common code that developers may wish to use.  Then, the &amp;lt;code&amp;gt;MyConfigurationWidget&amp;lt;/code&amp;gt; focuses on the specifics for a particular configuration widget.  Note that one of the tricky pieces that &amp;lt;code&amp;gt;ModuleConfigurationWidgetBase&amp;lt;/code&amp;gt; takes care of is locating and transforming parameter values.  Any &amp;quot;function&amp;quot; in VisTrails may store multiple parameter values; for example, &amp;quot;SetCameraPosition&amp;quot; might have three parameters (x,y,z).  Thus, we use lists of values throughout the code.  In addition, the parameter values are serialized in order to ensure their storage, but each &amp;lt;code&amp;gt;Constant&amp;lt;/code&amp;gt; subclass must provide &amp;lt;code&amp;gt;translate_to_python&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;translate_to_string&amp;lt;/code&amp;gt; methods.  We use these methods to serialize and deserialize values.  The heavy lifting is done by the &amp;lt;code&amp;gt;self.controller.update_functions&amp;lt;/code&amp;gt; which persists all of the changes to the vistrail.  We use &amp;lt;code&amp;gt;refresh_module&amp;lt;/code&amp;gt; to make sure the changes are reflected in the GUI.&lt;br /&gt;
&lt;br /&gt;
Also, note that the example shows how the &amp;lt;code&amp;gt;fruit&amp;lt;/code&amp;gt;port's visibility can be programmatically set using &amp;lt;code&amp;gt;Module.visible_input_ports&amp;lt;/code&amp;gt;.  However, such changes are not persisted across sessions.  The &amp;lt;code&amp;gt;state_was_changed&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;state_was_reset&amp;lt;/code&amp;gt; provide some cleanup code to make sure that VisTrails is aware when there are unsaved changes; you should link any widget state changes to this method.&lt;br /&gt;
&lt;br /&gt;
In future versions of VisTrails, we expect to streamline the process and make the API cleaner.  Expect a per-module &amp;lt;code&amp;gt;_settings&amp;lt;/code&amp;gt; field that allows settings like the configuration widget to be specified with the module definition as well as support for named arguments so that port and settings definitions are more understandable.&lt;br /&gt;
&lt;br /&gt;
==== Example Code for VisTrails 2.0+ ====&lt;br /&gt;
===== init.py =====&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;from core.modules.vistrails_module import Module&lt;br /&gt;
from widgets import MyConfigurationWidget&lt;br /&gt;
&lt;br /&gt;
class MyConfigureModule(Module):&lt;br /&gt;
    _input_ports = [(&amp;quot;order&amp;quot;, &amp;quot;(edu.utah.sci.vistrails.basic:Integer)&amp;quot;),&lt;br /&gt;
                    (&amp;quot;rating&amp;quot;, &amp;quot;(edu.utah.sci.vistrails.basic:Integer)&amp;quot;),&lt;br /&gt;
                    (&amp;quot;fruit&amp;quot;, &amp;quot;(edu.utah.sci.vistrails.basic:String)&amp;quot;,&lt;br /&gt;
                     {&amp;quot;optional&amp;quot;: True}),]&lt;br /&gt;
    _output_ports = [(&amp;quot;value&amp;quot;, &amp;quot;(edu.utah.sci.vistrails.basic:String)&amp;quot;)]&lt;br /&gt;
&lt;br /&gt;
_modules = [(MyConfigureModule, {&amp;quot;configureWidgetType&amp;quot;: MyConfigurationWidget})]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== widgets.py =====&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;from PyQt4 import QtCore, QtGui&lt;br /&gt;
from itertools import izip&lt;br /&gt;
&lt;br /&gt;
from gui.modules.module_configure import StandardModuleConfigurationWidget&lt;br /&gt;
from core import debug&lt;br /&gt;
&lt;br /&gt;
class ModuleConfigurationWidgetBase(StandardModuleConfigurationWidget):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;ModuleConfigurationWidgetBase provides more scaffolding over&lt;br /&gt;
    StandardModuleConfigurationWidget so developers do not have to&lt;br /&gt;
    comb through the source code to determine what needs to be implemented&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    def __init__(self, module, controller, parent=None):&lt;br /&gt;
        StandardModuleConfigurationWidget.__init__(self, module, controller, &lt;br /&gt;
                                                   parent)&lt;br /&gt;
        self.has_button_layout = False&lt;br /&gt;
        self.create_widget()&lt;br /&gt;
        self.set_gui_values()&lt;br /&gt;
&lt;br /&gt;
    def create_widget(self):&lt;br /&gt;
        raise NotImplementedError('Subclass needs to implement'&lt;br /&gt;
                                  '&amp;quot;create_widget&amp;quot;')&lt;br /&gt;
&lt;br /&gt;
    def set_vistrails_values(self):&lt;br /&gt;
        raise NotImplementedError('Subclass needs to implement '&lt;br /&gt;
                                  '&amp;quot;set_vistrails_values&amp;quot;')&lt;br /&gt;
&lt;br /&gt;
    def set_gui_values(self):&lt;br /&gt;
        raise NotImplementedError('Subclass needs to implement '&lt;br /&gt;
                                  '&amp;quot;set_gui_values&amp;quot;')&lt;br /&gt;
&lt;br /&gt;
    def create_button_layout(self):&lt;br /&gt;
        self.has_button_layout = True&lt;br /&gt;
&lt;br /&gt;
        button_layout = QtGui.QHBoxLayout()&lt;br /&gt;
        self.reset_button = QtGui.QPushButton('&amp;amp;Reset')&lt;br /&gt;
        self.reset_button.setEnabled(False)&lt;br /&gt;
        self.save_button = QtGui.QPushButton('&amp;amp;Save')&lt;br /&gt;
        self.save_button.setDefault(True)&lt;br /&gt;
        self.save_button.setEnabled(False)&lt;br /&gt;
        button_layout.addStretch(1)&lt;br /&gt;
        button_layout.addWidget(self.reset_button)&lt;br /&gt;
        button_layout.addWidget(self.save_button)&lt;br /&gt;
&lt;br /&gt;
        self.connect(self.reset_button, QtCore.SIGNAL(&amp;quot;clicked()&amp;quot;),&lt;br /&gt;
                     self.resetTriggered)&lt;br /&gt;
        self.connect(self.save_button, QtCore.SIGNAL(&amp;quot;clicked()&amp;quot;),&lt;br /&gt;
                     self.saveTriggered)&lt;br /&gt;
&lt;br /&gt;
        return button_layout&lt;br /&gt;
&lt;br /&gt;
    def state_was_changed(self, *args, **kwargs):&lt;br /&gt;
        if self.has_button_layout:&lt;br /&gt;
            self.save_button.setEnabled(True)&lt;br /&gt;
            self.reset_button.setEnabled(True)&lt;br /&gt;
        self.state_changed = True&lt;br /&gt;
&lt;br /&gt;
    def state_was_reset(self):&lt;br /&gt;
        if self.has_button_layout:&lt;br /&gt;
            self.save_button.setEnabled(False)&lt;br /&gt;
            self.reset_button.setEnabled(False)&lt;br /&gt;
        self.state_changed = False        &lt;br /&gt;
&lt;br /&gt;
    def get_function_by_name(self, function_name):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Given its name, returns a ModuleFunction object if it exists&lt;br /&gt;
        otherwise None.  If two or more functions exist for the same&lt;br /&gt;
        port, it writes a warning and returns the first.&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        found = []&lt;br /&gt;
        for function in self.module.functions:&lt;br /&gt;
            if function.name == function_name:&lt;br /&gt;
                found.append(function)&lt;br /&gt;
&lt;br /&gt;
        if len(found) &amp;gt; 1:&lt;br /&gt;
            debug.warning(&amp;quot;Found more than one function named '%s'&amp;quot; % \&lt;br /&gt;
                          function_name)&lt;br /&gt;
        if len(found) &amp;lt; 1:&lt;br /&gt;
            return None&lt;br /&gt;
        return found[0]&lt;br /&gt;
&lt;br /&gt;
    def get_function_values(self, function_name):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Takes a function name and returns a list of (python) values on that&lt;br /&gt;
        function.  Note that this is a list because there can be&lt;br /&gt;
        multiple parameter values per function if we have a compound&lt;br /&gt;
        port.&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        f = self.get_function_by_name(function_name)&lt;br /&gt;
        if f is None:&lt;br /&gt;
            return None&lt;br /&gt;
&lt;br /&gt;
        str_values = [p.strValue for p in f.params]&lt;br /&gt;
&lt;br /&gt;
        ps = self.module.get_port_spec(function_name, 'input')&lt;br /&gt;
        descriptors = ps.descriptors()&lt;br /&gt;
        if len(str_values) != len(descriptors):&lt;br /&gt;
            debug.critical(&amp;quot;Parameters for '%s' do not match specification&amp;quot; % \&lt;br /&gt;
                           function_name)&lt;br /&gt;
            return None&lt;br /&gt;
&lt;br /&gt;
        values = []&lt;br /&gt;
        for str_value, desc in izip(str_values, descriptors):&lt;br /&gt;
            value = desc.module.translate_to_python(str_value)&lt;br /&gt;
            values.append(value)&lt;br /&gt;
&lt;br /&gt;
        return values&lt;br /&gt;
&lt;br /&gt;
    def get_function_str_values(self, function_name, values):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;Takes a function name and a list of (python) values and serializes&lt;br /&gt;
        them, returning a list of string values.  Note that this is a&lt;br /&gt;
        list because there can be multiple parameter values per&lt;br /&gt;
        function if we have a compound port.&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        ps = self.module.get_port_spec(function_name, 'input')&lt;br /&gt;
        descriptors = ps.descriptors()&lt;br /&gt;
        if len(values) != len(descriptors):&lt;br /&gt;
            debug.critical(&amp;quot;Values for '%s' do not match specification&amp;quot; % \&lt;br /&gt;
                           function_name)&lt;br /&gt;
            return None&lt;br /&gt;
        &lt;br /&gt;
        str_values = []&lt;br /&gt;
        for value, desc in izip(values, descriptors):&lt;br /&gt;
            str_value = desc.module.translate_to_string(value)&lt;br /&gt;
            str_values.append(str_value)&lt;br /&gt;
&lt;br /&gt;
        return str_values&lt;br /&gt;
&lt;br /&gt;
    def refresh_module(self):&lt;br /&gt;
        self.controller.flush_delayed_actions()&lt;br /&gt;
        self.controller.current_pipeline_view.recreate_module(&lt;br /&gt;
            self.controller.current_pipeline, self.module.id)&lt;br /&gt;
        &lt;br /&gt;
    def saveTriggered(self):&lt;br /&gt;
        self.set_vistrail_values()&lt;br /&gt;
&lt;br /&gt;
    def resetTriggered(self):&lt;br /&gt;
        self.set_gui_values()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class MyConfigurationWidget(ModuleConfigurationWidgetBase):&lt;br /&gt;
    def create_widget(self):&lt;br /&gt;
        grid_layout = QtGui.QGridLayout()&lt;br /&gt;
        slider_label = QtGui.QLabel(&amp;quot;Order:&amp;quot;)&lt;br /&gt;
        self.slider_widget = QtGui.QSlider()&lt;br /&gt;
        self.slider_widget.setTracking(False)&lt;br /&gt;
        self.slider_widget.setOrientation(QtCore.Qt.Horizontal)&lt;br /&gt;
        self.slider_widget.setMinimum(0)&lt;br /&gt;
        self.slider_widget.setMaximum(100)&lt;br /&gt;
        grid_layout.addWidget(slider_label, 1, 1)&lt;br /&gt;
        grid_layout.addWidget(self.slider_widget, 1, 2)&lt;br /&gt;
        &lt;br /&gt;
        spin_label = QtGui.QLabel(&amp;quot;Rating:&amp;quot;)&lt;br /&gt;
        self.spin_box = QtGui.QSpinBox()&lt;br /&gt;
        self.spin_box.setRange(-10,10)&lt;br /&gt;
        grid_layout.addWidget(spin_label, 2, 1)&lt;br /&gt;
        grid_layout.addWidget(self.spin_box, 2, 2)&lt;br /&gt;
&lt;br /&gt;
        list_label = QtGui.QLabel(&amp;quot;Fruit:&amp;quot;)&lt;br /&gt;
        self.list_widget = QtGui.QListWidget()&lt;br /&gt;
        self.list_widget.setSelectionMode(&lt;br /&gt;
            QtGui.QAbstractItemView.SingleSelection)&lt;br /&gt;
        self.list_widget.addItem(&amp;quot;Apple&amp;quot;)&lt;br /&gt;
        self.list_widget.addItem(&amp;quot;Banana&amp;quot;)&lt;br /&gt;
        self.list_widget.addItem(&amp;quot;Cherry&amp;quot;)&lt;br /&gt;
        grid_layout.addWidget(list_label, 3, 1, 1, 2)&lt;br /&gt;
        grid_layout.addWidget(self.list_widget, 4, 1, 1, 2)&lt;br /&gt;
&lt;br /&gt;
        button_layout = self.create_button_layout()&lt;br /&gt;
        grid_layout.addLayout(button_layout, 6, 1, 1, 2)&lt;br /&gt;
&lt;br /&gt;
        self.setLayout(grid_layout)&lt;br /&gt;
&lt;br /&gt;
        self.connect(self.slider_widget, QtCore.SIGNAL(&amp;quot;valueChanged(int)&amp;quot;),&lt;br /&gt;
                     self.state_was_changed)&lt;br /&gt;
        self.connect(self.spin_box, QtCore.SIGNAL(&amp;quot;valueChanged(int)&amp;quot;),&lt;br /&gt;
                     self.state_was_changed)&lt;br /&gt;
        self.connect(self.list_widget, QtCore.SIGNAL(&amp;quot;itemSelectionChanged()&amp;quot;),&lt;br /&gt;
                     self.state_was_changed)&lt;br /&gt;
&lt;br /&gt;
        # setting port visibility&lt;br /&gt;
        self.checkbox = QtGui.QCheckBox(&amp;quot;Show Fruit Port&amp;quot;)&lt;br /&gt;
        grid_layout.addWidget(self.checkbox, 5, 1, 1, 2)&lt;br /&gt;
        if &amp;quot;fruit&amp;quot; in self.module.visible_input_ports:&lt;br /&gt;
            self.checkbox.setChecked(True)&lt;br /&gt;
        self.connect(self.checkbox, QtCore.SIGNAL(&amp;quot;toggled(bool)&amp;quot;),&lt;br /&gt;
                     self.toggle_fruit_visibility)&lt;br /&gt;
&lt;br /&gt;
    # setting port visibility&lt;br /&gt;
    def toggle_fruit_visibility(self, *args, **kwargs):&lt;br /&gt;
        if self.checkbox.isChecked():&lt;br /&gt;
            self.module.visible_input_ports.add(&amp;quot;fruit&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            self.module.visible_input_ports.discard(&amp;quot;fruit&amp;quot;)&lt;br /&gt;
        self.refresh_module()&lt;br /&gt;
&lt;br /&gt;
    def set_gui_values(self):&lt;br /&gt;
        # each value will either be None or a list (usually with only&lt;br /&gt;
        # a single value)&lt;br /&gt;
        order = self.get_function_values(&amp;quot;order&amp;quot;)&lt;br /&gt;
        rating = self.get_function_values(&amp;quot;rating&amp;quot;)&lt;br /&gt;
        fruit = self.get_function_values(&amp;quot;fruit&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        if order is not None:&lt;br /&gt;
            self.slider_widget.setValue(order[0])&lt;br /&gt;
        else:&lt;br /&gt;
            self.slider_widget.setValue(0)&lt;br /&gt;
        if rating is not None:&lt;br /&gt;
            self.spin_box.setValue(rating[0])&lt;br /&gt;
        else:&lt;br /&gt;
            self.spin_box.setValue(0)&lt;br /&gt;
        if fruit:&lt;br /&gt;
            items = self.list_widget.findItems(fruit[0], QtCore.Qt.MatchExactly)&lt;br /&gt;
            if len(items) &amp;gt; 0:&lt;br /&gt;
                self.list_widget.setCurrentItem(items[0])&lt;br /&gt;
            else:&lt;br /&gt;
                self.list_widget.setCurrentRow(-1)            &lt;br /&gt;
        else:&lt;br /&gt;
            self.list_widget.setCurrentRow(-1)&lt;br /&gt;
&lt;br /&gt;
        # call reset since the setting above likely triggered&lt;br /&gt;
        # state_was_changed&lt;br /&gt;
        self.state_was_reset()    &lt;br /&gt;
&lt;br /&gt;
    def set_vistrail_values(self):&lt;br /&gt;
        order = self.slider_widget.value()&lt;br /&gt;
        rating = self.spin_box.value()&lt;br /&gt;
        fruit = ''&lt;br /&gt;
        selected_items = self.list_widget.selectedItems()&lt;br /&gt;
        if len(selected_items) &amp;gt; 0:&lt;br /&gt;
            fruit = selected_items[0].text()&lt;br /&gt;
        &lt;br /&gt;
        # update_functions takes a list of tuples; each tupe is of the&lt;br /&gt;
        # form (function name, &amp;lt;list of param str values&amp;gt;)&lt;br /&gt;
        functions = [(f_name,self. get_function_str_values(f_name, f_val))&lt;br /&gt;
                     for (f_name, f_val) in [(&amp;quot;order&amp;quot;, [order]),&lt;br /&gt;
                                             (&amp;quot;rating&amp;quot;, [rating]),&lt;br /&gt;
                                             (&amp;quot;fruit&amp;quot;, [fruit])]]&lt;br /&gt;
        self.controller.update_functions(self.module,&lt;br /&gt;
                                         functions)&lt;br /&gt;
&lt;br /&gt;
        # need to reset state before refreshing the module&lt;br /&gt;
        self.state_was_reset()&lt;br /&gt;
&lt;br /&gt;
        # refresh the module so any parameter changes are visible&lt;br /&gt;
        self.refresh_module()&amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dakoop</name></author>
	</entry>
</feed>