durusmail: quixote-users: CompositeWidget question
CompositeWidget question
2005-07-15
2005-07-15
CompositeWidget question
mso@oz.net
2005-07-15
I need to make a quantity range widget that renders like this, all on one
line:

    FloatWidget    "-"   FloatWidget   SingleSelectWidget

Valid input would be:

     100  - 1000 gallons
     0.96 -      barrels         (second widget is None)
          -      gallons         (first two widgets are None, meaning no
input)

I'm implementing it this way:

class QuantityRangeWidget(CompositeWidget):
    def __init__(self, name, **kwargs):
        options = [ (x, x, x) for x in VOLUME_UNITS + MASS_UNITS]
        widget.CompositeWidget.__init__(self, name, **kwargs)
        self.add(widget.FloatWidget, 'low')
        self.add(widget.FloatWidget, 'high')
        self.add(widget.SingleSelectWidget, 'unit', value='gallons',
            options=options)

    def render_content(self):
        tio = TemplateIO(html=True)
        tio += self.get_widget('low').render_content()
        tio += htmltext(" to ")
        tio += self.get_widget('high').render_content()
        tio += self.get_widget('unit').render_content()
        return tio.getvalue()

Is this the right way to do it?  Should my ._parse method set the value to
a tuple of subvalues, and .set_value propagate the values to the
subwidgets?  Or should I ignore the widget value and have caller look at
the subwidget values directly?  "form.get_widget('quantity')['low']"?
I suppose I can't do "form['quantity']['low']" ?

What if I need several range controls on the same form?  All the
subwidgets will be in a flat namespace in the HTML.  I'm getting subwidget
names like 'release$low', so I guess that's being taken care of
automatically somehow.
    def _parse(self):
        is_low = self['low'] is not None
        is_high = self['high'] is not None
        is_unit = self['unit'] is not None
        if is_high and not is_low:
            self.error = "Must provide low number."
        if (is_low or is_high) and not is_unit:
            self.error = "Must provide unit."

I made a date widget earlier but that was pretty straightforward, since
the value is a datetime object, and I put the subwidgets in .year, .month,
and .day attributes.  (Perhaps I should have used .add() and .widgets, but
I bypassed them.)  But a range object doesn't have an obvious single value
unless I arbitrarily say  ".value = (low, high, unit)".  Is that how to do
it with composite widgets?

After that I need to make a latitude/longitude widget that accepts:
    123.45               West    (degrees)
    123     45.67        West    (degrees, minutes)
    123     45    45.67  West    (degrees, minutes, seconds)
But first I have to get the simpler widget down.

What is the purpose of WidgetList and WidgetDict?  At first I thought they
were for making arbitrary composite widgets, but that raises the question
of when to use them and when to use CompositeWidget directly, and what
that funny 'add_element' widget is for.  Then I thought, "No, they are
specialized widgets, for growable lists/dicts."  Are they for when you
have multiple values and want to let the user as many additional values as
they want?  But there's nothing to delete an element if they want to go
the other way.  Or are these widgets for something else?

--
-- Mike Orr 

reply