When setting parameters on modules, some value types provide a custom
widget. For example, VTK allows setting color properties by using
color chooser widgets. These are defined on a per-constant basis, and
they are set at module registration time, so you can define your own
widgets for constants. This file describes how to do just that.

--------------------------------------------------------------------------------
Creating a new constant

To create a widget for your own module, you first need to make sure
your module subclasses from Constant, the base class for all constant
values in VisTrails. If you don't know how to create user-defined
modules, please check the documentation for that first.

A user-defined constant is a module that should respect a few
additional requirements. These are documented in the docstring for
Constant, in core/modules/basic_modules.py, and reproduced here for
completeness.

    When implementing your own constant, You have to adhere to the
    following interface:

    Implement the following methods:
    
       translate_to_python(x): Given a string, translate_to_python
       must return a python value that will be the value seen by the
       execution modules.

       For example, translate_to_python called on a float parameter
       with value '3.15' will return float('3.15').
       
       translate_to_string(): Return a string representation of the
       current constant, which will eventually be passed to
       translate_to_python.

       validate(v): return True if given python value is a plausible
       value for the constant. It should be implemented such that
       validate(translate_to_python(x)) == True for all valid x

    A constant must also expose its default value, through the field
    default_value.

    There are fields you are not allowed to use in your constant classes.
    These are: 'id', 'interpreter', 'logging' and 'change_parameter'

--------------------------------------------------------------------------------
GUI widgets

Now that we have a constant class, we need to create a widget that
allows the custom values to be set.

This can be any PyQt widget, provided that you respect the following
requirements:

1) Your class should always inherit from
core.modules.constant_configuration.ConstantMixin, a class mixin that
provides you with some necessary infrastructure.

2) Your constructor should expect an instance of
core.vistrail.module_param.ModuleParam and the widget's Qt parent. The
fields you are probably going to use from ModuleParam are 'type',
'identifier', 'namespace' and 'strValue'. The first three are used to
specify the actual type of the class, and 'strValue' is a string
representation of the value itself, typically obtained by a call to
translate_to_string() as described above. A typical declaration of the
constructor then would be

  class MyOwnConstant(SomeQtWidget, ConstantMixin):
      def __init__(self, param, parent=None):
          SomeQtWidget.__init__(self, parent)
          ConstantMixin.__init__(self)

3) You should implement a "contents()" method that returns a string
representation of the value encoded by the GUI in its current state.

4) Every time a change in the GUI state should be passed to VisTrails,
you should call update_parent(). Every time this is called a new
version is created, so make sure you have a reasonable granularity.

--------------------------------------------------------------------------------

Constants during execution

To make writing your own modules more convenient, VisTrails provides a
certain amount of transparent conversion for some constants. Consider
this example. A VisTrails pipeline contains a Float module with value
3.0 connected to port "port1" on a downstream module "Foo" whose
compute method is as follows:

class Foo(Module):
    ...
    def compute(self):
        ...
        x = self.getInputFromPort("port1")

In this case, x will be a basic Python value of type 'float', _not_ a
module of type Float. This automatic conversion happens for only a few
classes: Boolean, Integer, Null, Float, and String. These get
translated to the expected python types (Null becomes None).

Note, however, that this translation does _not_ happen for any other
constant, so if you need programmatic access to a constant in your
code, you should distinguish between these cases.

--------------------------------------------------------------------------------
Gotchas, what to watch out for:

If your custom widget is generating errors with tracebacks similar to:

  File "/home/cscheid/vistrails/trunk/vistrails/core/modules/constant_configuration.py", line 43, in update_parent

    if newContents != self._last_contents: 
AttributeError:_last_contents

It probably means you forgot to call the constructor to
ConstantWidgetMixin.

--------------------------------------------------------------------------------
