<?xml version="1.0" encoding="UTF-8" ?>
<rdf:RDF xmlns="http://usefulinc.com/ns/doap#" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><Project><name>zope.app.form</name>
<shortdesc>The Original Zope 3 Form Framework</shortdesc>
<description>This package provides a form and widget framework for Zope 3. It also
implements a few high-level ZCML directives for declaring forms. More advanced
alternatives are implemented in ``zope.formlib`` and ``z3c.form``.


Detailed documentation:


===============
Browser Widgets
===============

.. contents::

This directory contains widgets: views on bound schema fields.  Many of these
are straightforward.  For instance, see the `TextWidget` in textwidgets.py,
which is a subclass of BrowserWidget in widget.py.  It is registered as an
`IBrowserRequest` view of an `ITextLine` schema field, providing the
`IInputWidget` interface::

  &lt;view
      type="zope.publisher.interfaces.browser.IBrowserRequest"
      for="zope.schema.interfaces.ITextLine"
      provides="zope.app.form.interfaces.IInputWidget"
      factory=".TextWidget"
      permission="zope.Public"
      /&gt;

The widget then receives the field and the request as arguments to the factory
(i.e., the `TextWidget` class).

Some widgets in Zope 3 extend this pattern.  This extension is configurable:
simply do not load the zope/app/form/browser/configure.zcml file if you do not
wish to participate in the extension.  The widget registration is extended for
`Choice` fields and for the `collection` fields.

Default Choice Field Widget Registration and Lookup
===================================================

As described above, all field widgets are obtained by looking up a browser
`IInputWidget` or `IDisplayWidget` view for the field object.  For `Choice`
fields, the default registered widget defers all of its behavior to the result
of another lookup: a browser widget view for the field *and* the Choice field's
vocabulary.  

This allows registration of Choice widgets that differ on the basis of the
vocabulary type.  For example, a widget for a vocabulary of images might have
a significantly different user interface than a widget for a vocabulary of
words.  A dynamic vocabulary might implement `IIterableVocabulary` if its
contents are below a certain length, but not implement the marker "iterable"
interface if the number of possible values is above the threshhold.

This also means that choice widget factories are called with with an additional
argument.  Rather than being called with the field and the request as
arguments, choice widgets receive the field, vocabulary, and request as
arguments.

Some `Choice` widgets may also need to provide a query interface,
particularly if the vocabulary is too big to iterate over.  The vocabulary
may provide a query which implements an interface appropriate for that
vocabulary.  You then can register a query view -- a view registered for the
query interface and the field interface -- that implements
`zope.app.forms.browser.interfaces.IVocabularyQueryView`.

Default Collection Field Widget Registration and Lookup
=======================================================

The default configured lookup for collection fields -- List, Tuple, and Set, for
instance -- begins with the usual lookup for a browser widget view for the
field object.  This widget defers its display to the result of another lookup:
a browser widget view registered for the field and the field's `value_type`
(the type of the contained values).  This allows registrations for collection
widgets that differ on the basis of the members -- a widget for entering a list
of text strings might differ significantly from a widget for entering a list of
dates...or even a list of choices, as discussed below.

This registration pattern has three implications that should be highlighted. 

* First, collection fields that do not specify a `value_type` probably cannot
  have a reasonable widget.

* Second, collection widgets that wish to be the default widget for a
  collection with any `value_type` should be registered for the collection
  field and a generic value_type: the `IField` interface.  Do  not register the
  generic widget for the collection field only or you will break the lookup
  behavior as described here.

* Third, like choice widget factories, sequence widget factories (classes or
  functions) take three arguments.  Typical sequence widgets receive the
  field, the `value_type`, and the request as arguments.

Collections of Choices
----------------------

If a collection field's `value_type` is a `Choice` field, the second widget
again defers its behavior, this time to a third lookup based on the collection
field and the choice's vocabulary.  This means that a widget for a list of
large image choices can be different than a widget for a list of small image
choices (with a different vocabulary interface), different from a widget for a
list of keyword choices, and different from a set of keyword choices.

Some advanced applications may wish to do a further lookup on the basis of the
unique attribute of the collection field--perhaps looking up a named view with
a "unique" or "lenient" token depending on the field's value, but this is not
enabled in the default Zope 3 configuration.

Registering Widgets for a New Collection Field Type
---------------------------------------------------

Because of this lookup pattern, basic widget registrations for new field types
must follow a recipe.  For example, a developer may introduce a new Bag field
type for simple shopping cart functionality and wishes to add widgets for it
within the default Zope 3 collection widget registration.  The bag widgets
should be registered something like this. 

The only hard requirement is that the developer must register the bag + choice
widget: the widget is just the factory for the third dispatch as described
above, so the developer can use the already implemented widgets listed below::

  &lt;view
      type="zope.publisher.interfaces.browser.IBrowserRequest"
      for="zope.schema.interfaces.IBag
           zope.schema.interfaces.IChoice"
      provides="zope.app.form.interfaces.IDisplayWidget"
      factory=".ChoiceCollectionDisplayWidget"
      permission="zope.Public"
      /&gt;

  &lt;view
      type="zope.publisher.interfaces.browser.IBrowserRequest"
      for="zope.schema.interfaces.IBag
           zope.schema.interfaces.IChoice"
      provides="zope.app.form.interfaces.IInputWidget"
      factory=".ChoiceCollectionInputWidget"
      permission="zope.Public"
      /&gt;

Beyond this, the developer may also have a generic bag widget she wishes to
register.  This might look something like this, assuming there's a
`BagSequenceWidget` available in this package::

  &lt;view
      type="zope.publisher.interfaces.browser.IBrowserRequest"
      for="zope.schema.interfaces.IBag
           zope.schema.interfaces.IField"
      provides="zope.app.form.interfaces.IInputWidget"
      factory=".BagSequenceWidget"
      permission="zope.Public"
      /&gt;

Then any widgets for the bag and a vocabulary would be registered according to
this general pattern, in which `IIterableVocabulary` would be the interface of
any appropriate vocabulary and `BagWidget` is some appropriate widget::

  &lt;view
      type="zope.publisher.interfaces.browser.IBrowserRequest"
      for="zope.schema.interfaces.IBag
           zope.schema.interfaces.IIterableVocabulary"
      provides="zope.app.form.interfaces.IInputWidget"
      factory=".BagWidget"
      permission="zope.Public"
      /&gt;


Choice widgets and the missing value
====================================

Choice widgets for a non-required field include a "no value" item to allow for
not selecting any value at all. This value used to be omitted for required
fields on the assumption that the widget should avoid invalid input from the
start.

However, if the context object doesn't yet have a field value set and there's
no default value, a dropdown widget would have to select an arbitrary value
due to the way it is displayed in the browser. This way, the field would
always validate, but possibly with a value the user never chose consciously.

Starting with version 3.6.0, dropdown widgets for required fields display a
"no value" item even for required fields if an arbitrary value would have to
be selected by the widget otherwise.

To switch the old behaviour back on for backwards compatibility, do

  zope.app.form.browser.itemswidgets.EXPLICIT_EMPTY_SELECTION = False

during application start-up.


============================================================
Simple example showing ObjectWidget and SequenceWidget usage
============================================================

The following implements a Poll product (add it as
zope/app/demo/poll) which has poll options defined as:

label
  A `TextLine` holding the label of the option
description
  Another `TextLine` holding the description of the option

Simple stuff.

Our Poll product holds an editable list of the `PollOption` instances.
This is shown in the ``poll.py`` source below::

    from persistent import Persistent
    from interfaces import IPoll, IPollOption
    from zope.interface import implements, classImplements

    class PollOption(Persistent, object):
        implements(IPollOption)

    class Poll(Persistent, object):
        implements(IPoll)

        def getResponse(self, option):
            return self._responses[option]

        def choose(self, option):
            self._responses[option] += 1
            self._p_changed = 1

        def get_options(self):
            return self._options

        def set_options(self, options):
            self._options = options
            self._responses = {}
            for option in self._options:
                self._responses[option.label] = 0

        options = property(get_options, set_options, None, 'fiddle options')

And the Schemas are defined in the ``interfaces.py`` file below::

    from zope.interface import Interface
    from zope.schema import Object, Tuple, TextLine
    from zope.schema.interfaces import ITextLine
    from zope.i18nmessageid import MessageFactory

    _ = MessageFactory("poll")

    class IPollOption(Interface):
        label = TextLine(title=u'Label', min_length=1)
        description = TextLine(title=u'Description', min_length=1)

    class IPoll(Interface):
        options = Tuple(title=u'Options',
            value_type=Object(IPollOption, title=u'Poll Option'))

        def getResponse(option): "get the response for an option"

        def choose(option): 'user chooses an option'

Note the use of the `Tuple` and `Object` schema fields above.  The
`Tuple` could optionally have restrictions on the min or max number of
items - these will be enforced by the `SequenceWidget` form handling
code. The `Object` must specify the schema that is used to generate its
data.

Now we have to specify the actual add and edit views. We use the existing
AddView and EditView, but we pre-define the widget for the sequence because
we need to pass in additional information. This is given in the
``browser.py`` file::

    from zope.app.form.browser.editview import EditView
    from zope.app.form.browser.add import AddView
    from zope.app.form import CustomWidgetFactory
    from zope.app.form.browser import SequenceWidget, ObjectWidget

    from interfaces import IPoll
    from poll import Poll, PollOption

    class PollVoteView:
        __used_for__ = IPoll

        def choose(self, option):
            self.context.choose(option)
            self.request.response.redirect('.')

    ow = CustomWidgetFactory(ObjectWidget, PollOption)
    sw = CustomWidgetFactory(SequenceWidget, subwidget=ow)

    class PollEditView(EditView):
        __used_for__ = IPoll

        options_widget = sw

    class PollAddView(AddView):
        __used_for__ = IPoll

        options_widget = sw

Note the creation of the widget via a `CustomWidgetFactory`.  So,
whenever the options_widget is used, a new
``SequenceWidget(subwidget=CustomWidgetFactory(ObjectWidget,
PollOption))`` is created. The subwidget argument indicates that each
item in the sequence should be represented by the indicated widget
instead of their default. If the contents of the sequence were just
`Text` fields, then the default would be just fine - the only odd cases
are Sequence and Object Widgets because they need additional arguments
when they're created.

Each item in the sequence will be represented by a
``CustomWidgetFactory(ObjectWidget, PollOption)`` - thus a new
``ObjectWidget(context, request, PollOption)`` is created for each
one. The `PollOption` class ("factory") is used to create new instances
when new data is created in add forms (or edit forms when we're adding
new items to a Sequence).

Tying all this together is the ``configure.zcml``::

    &lt;configure xmlns='http://namespaces.zope.org/zope'
        xmlns:browser='http://namespaces.zope.org/browser'&gt;

    &lt;content class=".poll.Poll"&gt;
    &lt;factory id="zope.app.demo.poll"
             permission="zope.ManageContent" /&gt;

    &lt;implements 
        interface="zope.annotation.interfaces.IAttributeAnnotatable"
        /&gt;

    &lt;require
        permission="zope.View"
        interface=".interfaces.IPoll"
        /&gt;

    &lt;require
        permission="zope.ManageContent"
        set_schema=".interfaces.IPoll"
        /&gt;
    &lt;/content&gt;

    &lt;content class=".poll.PollOption"&gt;
    &lt;require
        permission="zope.View"
        interface=".interfaces.IPollOption"
        /&gt;
    &lt;/content&gt;

    &lt;browser:page for=".interfaces.IPoll"
        name="index.html"
        template="results.zpt"
        permission="zope.View"
        menu="zmi_views" title="View"
        /&gt;

    &lt;browser:pages
        for=".interfaces.IPoll"
        class=".browser.PollVoteView"
        permission="zope.ManageContent"&gt;
        &lt;browser:page name="vote.html" template="vote.zpt"
            menu="zmi_views" title="Vote" /&gt;
        &lt;browser:page name="choose" attribute="choose" /&gt;
    &lt;/browser:pages&gt;

    &lt;browser:addform
        schema=".interfaces.IPoll"
        label="Add a Poll"
        content_factory=".poll.Poll"
        name="AddPoll.html"
        class=".browser.PollAddView"
        permission="zope.ManageContent" /&gt;

    &lt;browser:addMenuItem
        title="Poll Demo"
        description="Poll Demo"
        content_factory=".poll.Poll"
        view="AddPoll.html"
        permission="zope.ManageContent"
        /&gt;


    &lt;browser:editform
        schema=".interfaces.IPoll"
        class=".browser.PollEditView"
        label="Change a Poll"
        name="edit.html"
        menu="zmi_views" title="Edit"
        permission="zope.ManageContent" /&gt;

    &lt;/configure&gt;

Note the use of the ``class`` attribute on the ``addform`` and
``editform`` elements.  Otherwise, nothing much exciting here.

Finally, we have some additional views...

``results.zpt``::

    &lt;html metal:use-macro="context/@@standard_macros/page"&gt;
    &lt;title metal:fill-slot="title"&gt;Poll results&lt;/title&gt;
    &lt;div metal:fill-slot="body"&gt;
    &lt;table border="1"&gt;
    &lt;caption&gt;Poll results&lt;/caption&gt;
    &lt;thead&gt;
        &lt;tr&gt;&lt;th&gt;Option&lt;/th&gt;&lt;th&gt;Results&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
        &lt;tr tal:repeat="option context/options"&gt;
        &lt;td tal:content="option/label"&gt;Option&lt;/td&gt;
        &lt;td tal:content="python:context.getResponse(option.label)"&gt;Result&lt;/td&gt;
        &lt;td tal:content="option/description"&gt;Option&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
    &lt;/table&gt;
    &lt;/div&gt;
    &lt;/html&gt;

``vote.zpt``::

    &lt;html metal:use-macro="context/@@standard_macros/page"&gt;
    &lt;title metal:fill-slot="title"&gt;Poll voting&lt;/title&gt;
    &lt;div metal:fill-slot="body"&gt;
    &lt;form action="choose"&gt;
    &lt;table border="1"&gt;
    &lt;caption&gt;Poll voting&lt;/caption&gt;
    &lt;tbody&gt;
        &lt;tr tal:repeat="option context/options"&gt;
        &lt;td&gt;&lt;input type="radio" name="option"
                    tal:attributes="value option/label"&gt;&lt;/td&gt;
        &lt;td tal:content="option/label"&gt;Option&lt;/td&gt;
        &lt;td tal:content="option/description"&gt;Option&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
    &lt;/table&gt;
    &lt;input type="submit"&gt;
    &lt;/form&gt;
    &lt;/div&gt;
    &lt;/html&gt;



=============
Object Widget
=============

The following example shows a Family with Mother and Father.
First define the interface for a person:

  &gt;&gt;&gt; from zope.interface import Interface, implements
  &gt;&gt;&gt; from zope.schema import TextLine

  &gt;&gt;&gt; class IPerson(Interface):
  ...     """Interface for Persons."""
  ...
  ...     name = TextLine(title=u'Name', description=u'The first name')

Let's define the class:

  &gt;&gt;&gt; class Person(object):
  ...
  ...     implements(IPerson)
  ...
  ...     def __init__(self, name=''):
  ...         self.name = name

Let's define the interface family:

  &gt;&gt;&gt; from zope.schema import Object

  &gt;&gt;&gt; class IFamily(Interface):
  ...     """The familiy interface.""" 
  ...  
  ...     mother = Object(title=u'Mother',
  ...                     required=False, 
  ...                     schema=IPerson)
  ...
  ...     father = Object(title=u'Father',
  ...                     required=False, 
  ...                     schema=IPerson)

Let's define the class family with FieldProperty's mother and father
FieldProperty validate the values if they get added:

  &gt;&gt;&gt; from zope.schema.fieldproperty import FieldProperty

  &gt;&gt;&gt; class Family(object):
  ...     """The familiy interface."""
  ...
  ...     implements(IFamily)
  ...
  ...     mother = FieldProperty(IFamily['mother'])
  ...     father = FieldProperty(IFamily['father'])
  ...
  ...     def __init__(self, mother=None, father=None):
  ...         self.mother = mother
  ...         self.father = father

Let's make a instance of Family with None attributes:

  &gt;&gt;&gt; family = Family()
  &gt;&gt;&gt; bool(family.mother == None)
  True

  &gt;&gt;&gt; bool(family.father == None)
  True

Let's make a instance of Family with None attributes:

  &gt;&gt;&gt; mother = Person(u'Margrith')
  &gt;&gt;&gt; father = Person(u'Joe')
  &gt;&gt;&gt; family = Family(mother, father)
  &gt;&gt;&gt; IPerson.providedBy(family.mother)
  True

  &gt;&gt;&gt; IPerson.providedBy(family.father)
  True

Let's define a dummy class which doesn't implements IPerson:

  &gt;&gt;&gt; class Dummy(object):
  ...     """Dummy class."""
  ...     def __init__(self, name=''):
  ...         self.name = name

Raise a SchemaNotProvided exception if we add a Dummy instance to a Family 
object:

  &gt;&gt;&gt; foo = Dummy('foo')
  &gt;&gt;&gt; bar = Dummy('bar')
  &gt;&gt;&gt; family = Family(foo, bar)
  Traceback (most recent call last):
  ...
  SchemaNotProvided

Now let's setup a enviroment for use the widget like in a real application:

  &gt;&gt;&gt; from zope.app.testing import ztapi
  &gt;&gt;&gt; from zope.publisher.browser import TestRequest
  &gt;&gt;&gt; from zope.schema.interfaces import ITextLine
  &gt;&gt;&gt; from zope.schema import TextLine
  &gt;&gt;&gt; from zope.app.form.browser import TextWidget
  &gt;&gt;&gt; from zope.app.form.browser import ObjectWidget
  &gt;&gt;&gt; from zope.app.form.interfaces import IInputWidget

Register the TextLine widget used in the IPerson interface for the field 'name'.

  &gt;&gt;&gt; ztapi.browserViewProviding(ITextLine, TextWidget, IInputWidget)

Let's define a request and provide input value for the mothers name used
in the family object:

  &gt;&gt;&gt; request = TestRequest(HTTP_ACCEPT_LANGUAGE='pl')
  &gt;&gt;&gt; request.form['field.mother.name'] = u'Margrith Ineichen'

Before we update the object let's check the value name of the mother
instance on the family object:

  &gt;&gt;&gt; family.mother.name
  u'Margrith'

Now let's initialize a ObjectWidget with the right attributes:

  &gt;&gt;&gt; mother_field = IFamily['mother']
  &gt;&gt;&gt; factory = Person
  &gt;&gt;&gt; widget = ObjectWidget(mother_field, request, factory)

Now comes the magic. Apply changes means we force the ObjectWidget to read 
the request, extract the value and save it on the content. The ObjectWidget 
instance uses a real Person class (factory) for add the value. The value is 
temporary stored in this factory class. The ObjectWidget reads the value from 
this factory and set it to the attribute 'name' of the instance mother 
(The object mother is allready there). If we don't have a instance mother 
allready store in the family object, the factory instance will be stored 
directly to the family attribute mother. For more information see the method 
'applyChanges()' in the interface 
zope.app.form.browser.objectwidget.ObjectWidget.

  &gt;&gt;&gt; widget.applyChanges(family)
  True

Test the updated mother's name value on the object family:

  &gt;&gt;&gt; family.mother.name
  u'Margrith Ineichen'
  
  &gt;&gt;&gt; IPerson.providedBy(family.mother)
  True

So, now you know my mothers and fathers name. I hope it's also clear how to 
use the Object field and the ObjectWidget.


==============
Source Widgets
==============

Sources are objects that represent sets of values from which one might choose
and are used with Choice schema fields. Source widgets currently fall into two
categories:

- widgets for iterable sources

- widgets for queryable sources

Sources (combined with the available adapters) may support both approaches, but
no widgets currently support both.

In both cases, the widgets need views that can be used to get tokens to
represent source values in forms, as well as textual representations of values.
We use the `zope.browser.interfaces.ITerms` views for that.

All of our examples will be using the component architecture::

  &gt;&gt;&gt; import zope.interface
  &gt;&gt;&gt; import zope.component
  &gt;&gt;&gt; import zope.schema

This `ITerms` implementation can be used for the sources involved in
our tests::

  &gt;&gt;&gt; from zope.browser.interfaces import ITerms
  &gt;&gt;&gt; import zope.publisher.interfaces.browser
  &gt;&gt;&gt; import zope.app.form.browser.interfaces
  &gt;&gt;&gt; from zope.schema.vocabulary import SimpleTerm
  &gt;&gt;&gt; class ListTerms:
  ...
  ...     zope.interface.implements(ITerms)
  ...
  ...     def __init__(self, source, request):
  ...         pass # We don't actually need the source or the request :)
  ...
  ...     def getTerm(self, value):
  ...         title = unicode(value)
  ...         try:
  ...             token = title.encode('base64').strip()
  ...         except binascii.Error:
  ...             raise LookupError(token)
  ...         return SimpleTerm(value, token=token, title=title)
  ...
  ...     def getValue(self, token):
  ...         return token.decode('base64')

This view just uses the unicode representations of values as titles and the
base-64 encoding of the titles as tokens.  This is a very simple strategy
that's only approriate when the values have short and unique unicode
representations.

All of the source widgets are in a single module::

  &gt;&gt;&gt; import zope.app.form.browser.source

We'll also need request objects::

  &gt;&gt;&gt; from zope.publisher.browser import TestRequest


Iterable Source Widgets
=======================

Iterable sources are expected to be simpler than queriable sources, so they
represent a good place to start.  The most important aspect of iterable sources
for widgets is that it's actually possible to enumerate all the values from the
source.  This allows each possible value to be listed in a  &lt;select&gt; form field.

Let's start with a simple example.  We have a very trivial source,
which is basically a list::

  &gt;&gt;&gt; class SourceList(list):
  ...     zope.interface.implements(zope.schema.interfaces.IIterableSource)

We need to register our `ITerms` view::

  &gt;&gt;&gt; zope.component.provideAdapter(
  ...     ListTerms,
  ...     (SourceList, zope.publisher.interfaces.browser.IBrowserRequest))

Let's define a choice field using our iterable source::

  &gt;&gt;&gt; dog = zope.schema.Choice(
  ...    __name__ = 'dog',
  ...    title=u"Dogs",
  ...    source=SourceList(['spot', 'bowser', 'prince', 'duchess', 'lassie']),
  ...    )

  &gt;&gt;&gt; dog = dog.bind(object())

When we get a choice input widget for a choice field, the default widget
factory gets a view on the field and the field's source.  We'll just create the
view directly::

  &gt;&gt;&gt; request = TestRequest()
  &gt;&gt;&gt; widget = zope.app.form.browser.source.SourceSelectWidget(
  ...     dog, dog.source, request)

  &gt;&gt;&gt; print widget()
  &lt;div&gt;
  &lt;div class="value"&gt;
  &lt;select id="field.dog" name="field.dog" size="5" &gt;
  &lt;option value="c3BvdA=="&gt;spot&lt;/option&gt;
  &lt;option value="Ym93c2Vy"&gt;bowser&lt;/option&gt;
  &lt;option value="cHJpbmNl"&gt;prince&lt;/option&gt;
  &lt;option value="ZHVjaGVzcw=="&gt;duchess&lt;/option&gt;
  &lt;option value="bGFzc2ll"&gt;lassie&lt;/option&gt;
  &lt;/select&gt;
  &lt;/div&gt;
  &lt;input name="field.dog-empty-marker" type="hidden" value="1" /&gt;
  &lt;/div&gt;

Since the field is required, an empty selection is not valid:

  &gt;&gt;&gt; widget.getInputValue()
  Traceback (most recent call last):
  MissingInputError: ('field.dog', u'Dogs', None)

Also, the widget is required in this case:

  &gt;&gt;&gt; widget.required
  True

If the request contains a value, it is marked as selected::

  &gt;&gt;&gt; request.form["field.dog-empty-marker"] = "1"
  &gt;&gt;&gt; request.form["field.dog"] = "Ym93c2Vy"

  &gt;&gt;&gt; print widget()
  &lt;div&gt;
  &lt;div class="value"&gt;
  &lt;select id="field.dog" name="field.dog" size="5" &gt;
  &lt;option value="c3BvdA=="&gt;spot&lt;/option&gt;
  &lt;option selected="selected" value="Ym93c2Vy"&gt;bowser&lt;/option&gt;
  &lt;option value="cHJpbmNl"&gt;prince&lt;/option&gt;
  &lt;option value="ZHVjaGVzcw=="&gt;duchess&lt;/option&gt;
  &lt;option value="bGFzc2ll"&gt;lassie&lt;/option&gt;
  &lt;/select&gt;
  &lt;/div&gt;
  &lt;input name="field.dog-empty-marker" type="hidden" value="1" /&gt;
  &lt;/div&gt;

If we set the displayed value for the widget, that value is marked as
selected::

  &gt;&gt;&gt; widget.setRenderedValue("duchess")
  &gt;&gt;&gt; print widget()
  &lt;div&gt;
  &lt;div class="value"&gt;
  &lt;select id="field.dog" name="field.dog" size="5" &gt;
  &lt;option value="c3BvdA=="&gt;spot&lt;/option&gt;
  &lt;option value="Ym93c2Vy"&gt;bowser&lt;/option&gt;
  &lt;option value="cHJpbmNl"&gt;prince&lt;/option&gt;
  &lt;option selected="selected" value="ZHVjaGVzcw=="&gt;duchess&lt;/option&gt;
  &lt;option value="bGFzc2ll"&gt;lassie&lt;/option&gt;
  &lt;/select&gt;
  &lt;/div&gt;
  &lt;input name="field.dog-empty-marker" type="hidden" value="1" /&gt;
  &lt;/div&gt;

Dropdown widgets are achieved with SourceDropdownWidget, which simply
generates a selection list of size 1::

  &gt;&gt;&gt; request = TestRequest()
  &gt;&gt;&gt; widget = zope.app.form.browser.source.SourceDropdownWidget(
  ...     dog, dog.source, request)
  &gt;&gt;&gt; print widget() # doctest: +ELLIPSIS
  &lt;div&gt;
  &lt;div class="value"&gt;
  &lt;select id="field.dog" name="field.dog" size="1" &gt;
  &lt;option selected="selected" value=""&gt;(no value)&lt;/option&gt;...

An alternative to SourceSelectWidget for small numbers of items is
SourceRadioWidget that provides a radio button group for the items::

  &gt;&gt;&gt; request = TestRequest()
  &gt;&gt;&gt; widget = zope.app.form.browser.source.SourceRadioWidget(
  ...     dog, dog.source, request)
  &gt;&gt;&gt; print widget() # doctest: +NORMALIZE_WHITESPACE
  &lt;div&gt;
  &lt;div class="value"&gt;
  &lt;label for="field.dog.0"&gt;&lt;input class="radioType" id="field.dog.0"
      name="field.dog" type="radio" value="c3BvdA==" /&gt;&amp;nbsp;spot&lt;/label&gt;&lt;br
  /&gt;&lt;label for="field.dog.1"&gt;&lt;input class="radioType" id="field.dog.1"
      name="field.dog" type="radio" value="Ym93c2Vy" /&gt;&amp;nbsp;bowser&lt;/label&gt;&lt;br
  /&gt;&lt;label for="field.dog.2"&gt;&lt;input class="radioType" id="field.dog.2"
      name="field.dog" type="radio" value="cHJpbmNl" /&gt;&amp;nbsp;prince&lt;/label&gt;&lt;br
  /&gt;&lt;label for="field.dog.3"&gt;&lt;input class="radioType" id="field.dog.3"
      name="field.dog" type="radio" value="ZHVjaGVzcw==" /&gt;&amp;nbsp;duchess&lt;/label&gt;&lt;br
  /&gt;&lt;label for="field.dog.4"&gt;&lt;input class="radioType" id="field.dog.4"
      name="field.dog" type="radio" value="bGFzc2ll" /&gt;&amp;nbsp;lassie&lt;/label&gt;
  &lt;/div&gt;
  &lt;input name="field.dog-empty-marker" type="hidden" value="1" /&gt;
  &lt;/div&gt;

We'll select an item by setting the appropriate fields in the request::

  &gt;&gt;&gt; request.form['field.dog-empty-marker'] = '1'
  &gt;&gt;&gt; request.form['field.dog'] = 'bGFzc2ll'
  &gt;&gt;&gt;
  &gt;&gt;&gt; widget = zope.app.form.browser.source.SourceRadioWidget(
  ...     dog, dog.source, request)
  &gt;&gt;&gt; print widget() # doctest: +NORMALIZE_WHITESPACE
  &lt;div&gt;
  &lt;div class="value"&gt;
  &lt;label for="field.dog.0"&gt;&lt;input class="radioType" id="field.dog.0"
      name="field.dog" type="radio" value="c3BvdA==" /&gt;&amp;nbsp;spot&lt;/label&gt;&lt;br
  /&gt;&lt;label for="field.dog.1"&gt;&lt;input class="radioType" id="field.dog.1"
      name="field.dog" type="radio" value="Ym93c2Vy" /&gt;&amp;nbsp;bowser&lt;/label&gt;&lt;br
  /&gt;&lt;label for="field.dog.2"&gt;&lt;input class="radioType" id="field.dog.2"
      name="field.dog" type="radio" value="cHJpbmNl" /&gt;&amp;nbsp;prince&lt;/label&gt;&lt;br
  /&gt;&lt;label for="field.dog.3"&gt;&lt;input class="radioType" id="field.dog.3"
      name="field.dog" type="radio" value="ZHVjaGVzcw==" /&gt;&amp;nbsp;duchess&lt;/label&gt;&lt;br
  /&gt;&lt;label for="field.dog.4"&gt;&lt;input class="radioType" checked="checked"
      id="field.dog.4" name="field.dog" type="radio" value="bGFzc2ll"
      /&gt;&amp;nbsp;lassie&lt;/label&gt;
  &lt;/div&gt;
  &lt;input name="field.dog-empty-marker" type="hidden" value="1" /&gt;
  &lt;/div&gt;

For list-valued fields with items chosen from iterable sources, there are the
SourceMultiSelectWidget and SourceOrderedMultiSelectWidget widgets. The latter
widget includes support for re-ording the list items.
SourceOrderedMultiSelectWidget is configured as the default widget for lists of
choices.

If you don't need ordering support through the web UI, then you can use
the simpler SourceMultiSelectWidget::

  &gt;&gt;&gt; dogSource = SourceList([
  ...     u'spot', u'bowser', u'prince', u'duchess', u'lassie'])
  &gt;&gt;&gt; dogs = zope.schema.List(
  ...     __name__ = 'dogs',
  ...     title=u"Dogs",
  ...     value_type=zope.schema.Choice(
  ...         source=dogSource,
  ...     )
  ... )
  &gt;&gt;&gt; dogs = dogs.bind(object()) # give the field a context

  &gt;&gt;&gt; request = TestRequest()
  &gt;&gt;&gt; widget = zope.app.form.browser.source.SourceMultiSelectWidget(
  ...     dogs, dogSource, request)

Let's look at the rendered widget::

  &gt;&gt;&gt; print widget() # doctest: +NORMALIZE_WHITESPACE
  &lt;div&gt;
  &lt;div class="value"&gt;
  &lt;select id="field.dogs" multiple="multiple" name="field.dogs:list"
    size="5" &gt;&lt;option value="c3BvdA=="&gt;spot&lt;/option&gt;
  &lt;option value="Ym93c2Vy"&gt;bowser&lt;/option&gt;
  &lt;option value="cHJpbmNl"&gt;prince&lt;/option&gt;
  &lt;option value="ZHVjaGVzcw=="&gt;duchess&lt;/option&gt;
  &lt;option value="bGFzc2ll"&gt;lassie&lt;/option&gt;&lt;/select&gt;
  &lt;/div&gt;
  &lt;input name="field.dogs-empty-marker" type="hidden" value="1" /&gt;
  &lt;/div&gt;

We have no input yet::

  &gt;&gt;&gt; try:
  ...     widget.getInputValue()
  ... except zope.app.form.interfaces.MissingInputError:
  ...     print 'no input'
  no input

Select an item::

  &gt;&gt;&gt; request.form['field.dogs-empty-marker'] = '1'
  &gt;&gt;&gt; request.form['field.dogs'] = ['bGFzc2ll']
  &gt;&gt;&gt; widget.getInputValue()
  ['lassie']

and another::

  &gt;&gt;&gt; request.form['field.dogs'] = ['cHJpbmNl', 'bGFzc2ll']
  &gt;&gt;&gt; widget.getInputValue()
  ['prince', 'lassie']

Finally, what does the widget look like now::

  &gt;&gt;&gt; print widget() # doctest: +NORMALIZE_WHITESPACE
  &lt;div&gt;
  &lt;div class="value"&gt;
  &lt;select id="field.dogs" multiple="multiple" name="field.dogs:list"
    size="5" &gt;&lt;option value="c3BvdA=="&gt;spot&lt;/option&gt;
  &lt;option value="Ym93c2Vy"&gt;bowser&lt;/option&gt;
  &lt;option selected="selected" value="cHJpbmNl"&gt;prince&lt;/option&gt;
  &lt;option value="ZHVjaGVzcw=="&gt;duchess&lt;/option&gt;
  &lt;option selected="selected" value="bGFzc2ll"&gt;lassie&lt;/option&gt;&lt;/select&gt;
  &lt;/div&gt;
  &lt;input name="field.dogs-empty-marker" type="hidden" value="1" /&gt;
  &lt;/div&gt;


An alternative for small numbers of items is to use SourceMultiCheckBoxWidget::

  &gt;&gt;&gt; request = TestRequest()
  &gt;&gt;&gt; widget = zope.app.form.browser.source.SourceMultiCheckBoxWidget(
  ...     dogs, dogSource, request)

The rendered widget::

  &gt;&gt;&gt; print widget() # doctest: +NORMALIZE_WHITESPACE
  &lt;div&gt;
  &lt;div class="value"&gt;
  &lt;label for="field.dogs.0"&gt;&lt;input class="checkboxType" id="field.dogs.0"
    name="field.dogs" type="checkbox" value="c3BvdA==" /&gt;&amp;nbsp;spot&lt;/label&gt;&lt;br
    /&gt;&lt;label for="field.dogs.1"&gt;&lt;input class="checkboxType" id="field.dogs.1"
        name="field.dogs" type="checkbox" value="Ym93c2Vy"
        /&gt;&amp;nbsp;bowser&lt;/label&gt;&lt;br
    /&gt;&lt;label for="field.dogs.2"&gt;&lt;input class="checkboxType" id="field.dogs.2"
        name="field.dogs" type="checkbox" value="cHJpbmNl"
        /&gt;&amp;nbsp;prince&lt;/label&gt;&lt;br
    /&gt;&lt;label for="field.dogs.3"&gt;&lt;input class="checkboxType" id="field.dogs.3"
        name="field.dogs" type="checkbox"
        value="ZHVjaGVzcw==" /&gt;&amp;nbsp;duchess&lt;/label&gt;&lt;br
    /&gt;&lt;label for="field.dogs.4"&gt;&lt;input class="checkboxType" id="field.dogs.4"
        name="field.dogs" type="checkbox" value="bGFzc2ll"
        /&gt;&amp;nbsp;lassie&lt;/label&gt;
  &lt;/div&gt;
  &lt;input name="field.dogs-empty-marker" type="hidden" value="1" /&gt;
  &lt;/div&gt;

We have no input yet::

  &gt;&gt;&gt; try:
  ...     widget.getInputValue()
  ... except zope.app.form.interfaces.MissingInputError:
  ...     print 'no input'
  no input

Select an item::

  &gt;&gt;&gt; request.form['field.dogs-empty-marker'] = '1'
  &gt;&gt;&gt; request.form['field.dogs'] = ['bGFzc2ll']
  &gt;&gt;&gt; widget.getInputValue()
  ['lassie']

and another::

  &gt;&gt;&gt; request.form['field.dogs'] = ['c3BvdA==', 'bGFzc2ll']
  &gt;&gt;&gt; widget.getInputValue()
  ['spot', 'lassie']

Finally, what does the widget look like now::

  &gt;&gt;&gt; print widget() # doctest: +NORMALIZE_WHITESPACE
  &lt;div&gt;
  &lt;div class="value"&gt;
  &lt;label for="field.dogs.0"&gt;&lt;input class="checkboxType" checked="checked"
    id="field.dogs.0" name="field.dogs" type="checkbox" value="c3BvdA=="
    /&gt;&amp;nbsp;spot&lt;/label&gt;&lt;br
    /&gt;&lt;label for="field.dogs.1"&gt;&lt;input class="checkboxType" id="field.dogs.1"
        name="field.dogs" type="checkbox" value="Ym93c2Vy"
        /&gt;&amp;nbsp;bowser&lt;/label&gt;&lt;br
    /&gt;&lt;label for="field.dogs.2"&gt;&lt;input class="checkboxType" id="field.dogs.2"
        name="field.dogs" type="checkbox" value="cHJpbmNl"
        /&gt;&amp;nbsp;prince&lt;/label&gt;&lt;br
    /&gt;&lt;label for="field.dogs.3"&gt;&lt;input class="checkboxType" id="field.dogs.3"
        name="field.dogs" type="checkbox"
        value="ZHVjaGVzcw==" /&gt;&amp;nbsp;duchess&lt;/label&gt;&lt;br
    /&gt;&lt;label for="field.dogs.4"&gt;&lt;input class="checkboxType" checked="checked"
        id="field.dogs.4" name="field.dogs" type="checkbox" value="bGFzc2ll"
        /&gt;&amp;nbsp;lassie&lt;/label&gt;
  &lt;/div&gt;
  &lt;input name="field.dogs-empty-marker" type="hidden" value="1" /&gt;
  &lt;/div&gt;


For list ordering support, use SourceOrderedMultiSelectWidget::

  &gt;&gt;&gt; request = TestRequest()
  &gt;&gt;&gt; widget = zope.app.form.browser.source.SourceOrderedMultiSelectWidget(
  ...     dogs, dogSource, request)

The widget is too complicated to show in complete rendered form here.
Insted, we'll inspect the properties of the widget::

  &gt;&gt;&gt; from zope.app.form.interfaces import MissingInputError
  &gt;&gt;&gt; try:
  ...     widget.getInputValue()
  ... except MissingInputError:
  ...     print 'no input'
  no input

  &gt;&gt;&gt; widget.choices() == [
  ...     {'text': u'spot',    'value': 'c3BvdA=='},
  ...     {'text': u'bowser',  'value': 'Ym93c2Vy'},
  ...     {'text': u'prince',  'value': 'cHJpbmNl'},
  ...     {'text': u'duchess', 'value': 'ZHVjaGVzcw=='},
  ...     {'text': u'lassie',  'value': 'bGFzc2ll'}
  ... ]
  True

  &gt;&gt;&gt; widget.selected()
  []

Let's try out selecting items. Select one item::

  &gt;&gt;&gt; request.form['field.dogs-empty-marker'] = '1'
  &gt;&gt;&gt; request.form['field.dogs'] = ['bGFzc2ll']
  &gt;&gt;&gt; widget.selected() # doctest: +NORMALIZE_WHITESPACE
  [{'text': u'lassie',  'value': 'bGFzc2ll'}]

  &gt;&gt;&gt; widget.getInputValue()
  ['lassie']

Select two items::

  &gt;&gt;&gt; request.form['field.dogs'] = ['c3BvdA==', 'bGFzc2ll']
  &gt;&gt;&gt; widget.selected()  # doctest: +NORMALIZE_WHITESPACE
  [{'text': u'spot',    'value': 'c3BvdA=='},
   {'text': u'lassie',  'value': 'bGFzc2ll'}]

  &gt;&gt;&gt; widget.getInputValue()
  ['spot', 'lassie']


For set-valued fields, use SourceMultiSelectSetWidget::

  &gt;&gt;&gt; dogSet = zope.schema.Set(
  ...     __name__ = 'dogSet',
  ...     title=u"Dogs",
  ...     value_type=zope.schema.Choice(
  ...         source=dogSource,
  ...     )
  ... )
  &gt;&gt;&gt; dogSet = dogSet.bind(object()) # give the field a context
  &gt;&gt;&gt; request = TestRequest()
  &gt;&gt;&gt; widget = zope.app.form.browser.source.SourceMultiSelectSetWidget(
  ...     dogSet, dogSource, request)

  &gt;&gt;&gt; try:
  ...     widget.getInputValue()
  ... except zope.app.form.interfaces.MissingInputError:
  ...     print 'no input'
  no input

  &gt;&gt;&gt; print widget()  # doctest: +NORMALIZE_WHITESPACE
  &lt;div&gt;
  &lt;div class="value"&gt;
  &lt;select id="field.dogSet" multiple="multiple"
      name="field.dogSet:list" size="5" &gt;&lt;option value="c3BvdA=="&gt;spot&lt;/option&gt;
  &lt;option value="Ym93c2Vy"&gt;bowser&lt;/option&gt;
  &lt;option value="cHJpbmNl"&gt;prince&lt;/option&gt;
  &lt;option value="ZHVjaGVzcw=="&gt;duchess&lt;/option&gt;
  &lt;option value="bGFzc2ll"&gt;lassie&lt;/option&gt;&lt;/select&gt;
  &lt;/div&gt;
  &lt;input name="field.dogSet-empty-marker" type="hidden" value="1" /&gt;
  &lt;/div&gt;

Let's try out selecting items. Select one item::

  &gt;&gt;&gt; request.form['field.dogSet-empty-marker'] = '1'
  &gt;&gt;&gt; request.form['field.dogSet'] = ['bGFzc2ll']
  &gt;&gt;&gt; widget.getInputValue()
  set(['lassie'])

Select two items::

  &gt;&gt;&gt; request.form['field.dogSet'] = ['c3BvdA==', 'bGFzc2ll']
  &gt;&gt;&gt; widget.getInputValue()
  set(['spot', 'lassie'])

The rendered widget (still with the two items selected) looks like this::

  &gt;&gt;&gt; print widget()  # doctest: +NORMALIZE_WHITESPACE
  &lt;div&gt;
  &lt;div class="value"&gt;
  &lt;select id="field.dogSet" multiple="multiple"
      name="field.dogSet:list" size="5" &gt;&lt;option selected="selected"
      value="c3BvdA=="&gt;spot&lt;/option&gt;
  &lt;option value="Ym93c2Vy"&gt;bowser&lt;/option&gt;
  &lt;option value="cHJpbmNl"&gt;prince&lt;/option&gt;
  &lt;option value="ZHVjaGVzcw=="&gt;duchess&lt;/option&gt;
  &lt;option selected="selected" value="bGFzc2ll"&gt;lassie&lt;/option&gt;&lt;/select&gt;
  &lt;/div&gt;
  &lt;input name="field.dogSet-empty-marker" type="hidden" value="1" /&gt;
  &lt;/div&gt;



Source Widget Query Framework
=============================

An important aspect of sources is that they may have too many values to
enumerate.  Rather than listing all of the values, we, instead, provide
interfaces for querying values and selecting values from query results.
Matters are further complicated by the fact that different sources may have
very different interfaces for querying them.

To make matters more interesting, a source may be an aggregation of several
collections, each with their own querying facilities. An example of such a
source is a principal source, where principals might come from a number of
places, such as an LDAP database and ZCML-based principal definitions.

The default widgets for selecting values from sources use the
following approach:

- One or more query objects are obtained from the source by adapting the source
  to `zope.schema.ISourceQueriables`. If no adapter is obtained, then the
  source itself is assumed to be queriable.

- For each queriable found, a
  `zope.app.form.browser.interfaces.ISourceQueryView` view is looked up. This
  view is used to obtain the HTML for displaying a query form. The view is also
  used to obtain search results.

Let's start with a simple example.  We have a very trivial source,
which is basically a list:

  &gt;&gt;&gt; class SourceList(list):
  ...     zope.interface.implements(zope.schema.interfaces.ISource)

We need to register our `ITerms` view::

  &gt;&gt;&gt; zope.component.provideAdapter(
  ...     ListTerms,
  ...     (SourceList, zope.publisher.interfaces.browser.IBrowserRequest))

We aren't going to provide an adapter to `ISourceQueriables`, so the source
itself will be used as it's own queriable.  We need to provide a query view
for the source::

  &gt;&gt;&gt; class ListQueryView:
  ...
  ...     zope.interface.implements(
  ...         zope.app.form.browser.interfaces.ISourceQueryView)
  ...     zope.component.adapts(
  ...         SourceList,
  ...         zope.publisher.interfaces.browser.IBrowserRequest,
  ...         )
  ...
  ...     def __init__(self, source, request):
  ...         self.source = source
  ...         self.request = request
  ...
  ...     def render(self, name):
  ...         return (
  ...             '&lt;input name="%s.string"&gt;\n'
  ...             '&lt;input type="submit" name="%s" value="Search"&gt;'
  ...             % (name, name)
  ...             )
  ...
  ...     def results(self, name):
  ...         if name in self.request:
  ...             search_string = self.request.get(name+'.string')
  ...             if search_string is not None:
  ...                 return [value
  ...                         for value in self.source
  ...                         if search_string in value
  ...                         ]
  ...         return None

  &gt;&gt;&gt; zope.component.provideAdapter(ListQueryView)

Now, we can define a choice field::

  &gt;&gt;&gt; dog = zope.schema.Choice(
  ...    __name__ = 'dog',
  ...    title=u"Dogs",
  ...    source=SourceList(['spot', 'bowser', 'prince', 'duchess', 'lassie']),
  ...    )

As before, we'll just create the view directly::

  &gt;&gt;&gt; request = TestRequest()
  &gt;&gt;&gt; widget = zope.app.form.browser.source.SourceInputWidget(
  ...     dog, dog.source, request)

Now if we render the widget, we'll see the input value (initially nothing) and
a form elements for seaching for values::

  &gt;&gt;&gt; print widget()
  &lt;div class="value"&gt;
    &lt;div class="row"&gt;
      &lt;div class="label"&gt;
       Selected
      &lt;/div&gt;
      &lt;div class="field"&gt;
       Nothing
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;input type="hidden" name="field.dog.displayed" value="y" /&gt;
    &lt;div class="queries"&gt;
      &lt;div class="query"&gt;
        &lt;div class="queryinput"&gt;
  &lt;input name="field.dog.query.string"&gt;
  &lt;input type="submit" name="field.dog.query" value="Search"&gt;
        &lt;/div&gt; &lt;!-- queryinput --&gt;
      &lt;/div&gt; &lt;!-- query --&gt;
    &lt;/div&gt; &lt;!-- queries --&gt;
  &lt;/div&gt; &lt;!-- value --&gt;

This shows that we haven't selected a dog. We get a search box that we can type
seach strings into.  Let's supply a search string. We do this by providing data
in the form and by "selecting" the submit button::

  &gt;&gt;&gt; request.form['field.dog.displayed'] = u'y'
  &gt;&gt;&gt; request.form['field.dog.query.string'] = u'o'
  &gt;&gt;&gt; request.form['field.dog.query'] = u'Search'

Because the field is required, a non-selection is not valid. Thus, while the
widget still hasInput, it will raise an error when you getInputValue::

  &gt;&gt;&gt; widget.hasInput()
  True
  &gt;&gt;&gt; widget.getInputValue()
  Traceback (most recent call last):
  ...
  MissingInputError: ('dog', u'Dogs', None)

If the field is not required::

  &gt;&gt;&gt; dog.required = False

then as long as the field is displayed, the widget still has input but returns
the field's missing value::

  &gt;&gt;&gt; widget.hasInput()
  True
  &gt;&gt;&gt; widget.getInputValue() # None

Now if we render the widget, we'll see the search results::

  &gt;&gt;&gt; dog.required = True
  &gt;&gt;&gt; print widget()
  &lt;div class="value"&gt;
    &lt;div class="row"&gt;
      &lt;div class="label"&gt;
       Selected
      &lt;/div&gt;
      &lt;div class="field"&gt;
       Nothing
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;input type="hidden" name="field.dog.displayed" value="y" /&gt;
    &lt;div class="queries"&gt;
      &lt;div class="query"&gt;
        &lt;div class="queryinput"&gt;
  &lt;input name="field.dog.query.string"&gt;
  &lt;input type="submit" name="field.dog.query" value="Search"&gt;
        &lt;/div&gt; &lt;!-- queryinput --&gt;
        &lt;div class="queryresults"&gt;
  &lt;select name="field.dog.query.selection"&gt;
  &lt;option value="Ym93c2Vy"&gt;bowser&lt;/option&gt;
  &lt;option value="c3BvdA=="&gt;spot&lt;/option&gt;
  &lt;/select&gt;
  &lt;input type="submit" name="field.dog.query.apply" value="Apply" /&gt;
        &lt;/div&gt; &lt;!-- queryresults --&gt;
      &lt;/div&gt; &lt;!-- query --&gt;
    &lt;/div&gt; &lt;!-- queries --&gt;
  &lt;/div&gt; &lt;!-- value --&gt;

If we select an item::

  &gt;&gt;&gt; request.form['field.dog.displayed'] = u'y'
  &gt;&gt;&gt; del request.form['field.dog.query.string']
  &gt;&gt;&gt; del request.form['field.dog.query']
  &gt;&gt;&gt; request.form['field.dog.query.selection'] = u'c3BvdA=='
  &gt;&gt;&gt; request.form['field.dog.query.apply'] = u'Apply'

Then we'll show the newly selected value::

  &gt;&gt;&gt; print widget()
  &lt;div class="value"&gt;
    &lt;div class="row"&gt;
      &lt;div class="label"&gt;
       Selected
      &lt;/div&gt;
      &lt;div class="field"&gt;
       spot
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;input type="hidden" name="field.dog" value="c3BvdA==" /&gt;
    &lt;input type="hidden" name="field.dog.displayed" value="y" /&gt;
    &lt;div class="queries"&gt;
      &lt;div class="query"&gt;
        &lt;div class="queryinput"&gt;
  &lt;input name="field.dog.query.string"&gt;
  &lt;input type="submit" name="field.dog.query" value="Search"&gt;
        &lt;/div&gt; &lt;!-- queryinput --&gt;
      &lt;/div&gt; &lt;!-- query --&gt;
    &lt;/div&gt; &lt;!-- queries --&gt;
  &lt;/div&gt; &lt;!-- value --&gt;

Note that we should have an input value now, since pressing the 'Apply' button
provides us with input::

  &gt;&gt;&gt; widget.hasInput()
  True

We should also be able to get the input value::

  &gt;&gt;&gt; widget.getInputValue()
  'spot'

Now, let's look at a more complicated example. We'll define a source that
combines multiple sources::

  &gt;&gt;&gt; class MultiSource:
  ...
  ...     zope.interface.implements(
  ...        zope.schema.interfaces.ISource,
  ...        zope.schema.interfaces.ISourceQueriables,
  ...        )
  ...
  ...     def __init__(self, *sources):
  ...         self.sources = [(unicode(i), s) for (i, s) in enumerate(sources)]
  ...
  ...     def __contains__(self, value):
  ...         for i, s in self.sources:
  ...             if value in s:
  ...                 return True
  ...         return False
  ...
  ...     def getQueriables(self):
  ...         return self.sources

This multi-source implements `ISourceQueriables`. It assumes that the sources
it's given are queriable and just returns the sources as the queryable objects.

We can reuse our terms view::

  &gt;&gt;&gt; zope.component.provideAdapter(
  ...     ListTerms,
  ...     (MultiSource, zope.publisher.interfaces.browser.IBrowserRequest))

Now, we'll create a pet choice that combines dogs and cats::

  &gt;&gt;&gt; pet = zope.schema.Choice(
  ...    __name__ = 'pet',
  ...    title=u"Dogs and Cats",
  ...    source=MultiSource(
  ...      dog.source,
  ...      SourceList(['boots', 'puss', 'tabby', 'tom', 'tiger']),
  ...      ),
  ...    )

and a widget::

  &gt;&gt;&gt; widget = zope.app.form.browser.source.SourceInputWidget(
  ...     pet, pet.source, request)

Now if we display the widget, we'll see search inputs for both dogs
and cats::

  &gt;&gt;&gt; print widget()
  &lt;div class="value"&gt;
    &lt;div class="row"&gt;
      &lt;div class="label"&gt;
       Selected
      &lt;/div&gt;
      &lt;div class="field"&gt;
       Nothing
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;input type="hidden" name="field.pet.displayed" value="y" /&gt;
    &lt;div class="queries"&gt;
      &lt;div class="query"&gt;
        &lt;div class="queryinput"&gt;
  &lt;input name="field.pet.MA__.string"&gt;
  &lt;input type="submit" name="field.pet.MA__" value="Search"&gt;
        &lt;/div&gt; &lt;!-- queryinput --&gt;
      &lt;/div&gt; &lt;!-- query --&gt;
      &lt;div class="query"&gt;
        &lt;div class="queryinput"&gt;
  &lt;input name="field.pet.MQ__.string"&gt;
  &lt;input type="submit" name="field.pet.MQ__" value="Search"&gt;
        &lt;/div&gt; &lt;!-- queryinput --&gt;
      &lt;/div&gt; &lt;!-- query --&gt;
    &lt;/div&gt; &lt;!-- queries --&gt;
  &lt;/div&gt; &lt;!-- value --&gt;

As before, we can perform a search::

  &gt;&gt;&gt; request.form['field.pet.displayed'] = u'y'
  &gt;&gt;&gt; request.form['field.pet.MQ__.string'] = u't'
  &gt;&gt;&gt; request.form['field.pet.MQ__'] = u'Search'

In which case, we'll get some results::

  &gt;&gt;&gt; print widget() # doctest:
  &lt;div class="value"&gt;
    &lt;div class="row"&gt;
      &lt;div class="label"&gt;
       Selected
      &lt;/div&gt;
      &lt;div class="field"&gt;
       Nothing
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;input type="hidden" name="field.pet.displayed" value="y" /&gt;
    &lt;div class="queries"&gt;
      &lt;div class="query"&gt;
        &lt;div class="queryinput"&gt;
  &lt;input name="field.pet.MA__.string"&gt;
  &lt;input type="submit" name="field.pet.MA__" value="Search"&gt;
        &lt;/div&gt; &lt;!-- queryinput --&gt;
      &lt;/div&gt; &lt;!-- query --&gt;
      &lt;div class="query"&gt;
        &lt;div class="queryinput"&gt;
  &lt;input name="field.pet.MQ__.string"&gt;
  &lt;input type="submit" name="field.pet.MQ__" value="Search"&gt;
        &lt;/div&gt; &lt;!-- queryinput --&gt;
        &lt;div class="queryresults"&gt;
  &lt;select name="field.pet.MQ__.selection"&gt;
  &lt;option value="Ym9vdHM="&gt;boots&lt;/option&gt;
  &lt;option value="dGFiYnk="&gt;tabby&lt;/option&gt;
  &lt;option value="dGlnZXI="&gt;tiger&lt;/option&gt;
  &lt;option value="dG9t"&gt;tom&lt;/option&gt;
  &lt;/select&gt;
  &lt;input type="submit" name="field.pet.MQ__.apply" value="Apply" /&gt;
        &lt;/div&gt; &lt;!-- queryresults --&gt;
      &lt;/div&gt; &lt;!-- query --&gt;
    &lt;/div&gt; &lt;!-- queries --&gt;
  &lt;/div&gt; &lt;!-- value --&gt;

from which we can choose::

  &gt;&gt;&gt; request.form['field.pet.displayed'] = u'y'
  &gt;&gt;&gt; del request.form['field.pet.MQ__.string']
  &gt;&gt;&gt; del request.form['field.pet.MQ__']
  &gt;&gt;&gt; request.form['field.pet.MQ__.selection'] = u'dGFiYnk='
  &gt;&gt;&gt; request.form['field.pet.MQ__.apply'] = u'Apply'

and get a selection::

  &gt;&gt;&gt; print widget()
  &lt;div class="value"&gt;
    &lt;div class="row"&gt;
      &lt;div class="label"&gt;
       Selected
      &lt;/div&gt;
      &lt;div class="field"&gt;
       tabby
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;input type="hidden" name="field.pet" value="dGFiYnk=" /&gt;
    &lt;input type="hidden" name="field.pet.displayed" value="y" /&gt;
    &lt;div class="queries"&gt;
      &lt;div class="query"&gt;
        &lt;div class="queryinput"&gt;
  &lt;input name="field.pet.MA__.string"&gt;
  &lt;input type="submit" name="field.pet.MA__" value="Search"&gt;
        &lt;/div&gt; &lt;!-- queryinput --&gt;
      &lt;/div&gt; &lt;!-- query --&gt;
      &lt;div class="query"&gt;
        &lt;div class="queryinput"&gt;
  &lt;input name="field.pet.MQ__.string"&gt;
  &lt;input type="submit" name="field.pet.MQ__" value="Search"&gt;
        &lt;/div&gt; &lt;!-- queryinput --&gt;
      &lt;/div&gt; &lt;!-- query --&gt;
    &lt;/div&gt; &lt;!-- queries --&gt;
  &lt;/div&gt; &lt;!-- value --&gt;

Note that we should have an input value now, since pressing the 'Apply' button
provides us with input::

  &gt;&gt;&gt; widget.hasInput()
  True

and we can get the input value::

  &gt;&gt;&gt; widget.getInputValue()
  'tabby'

There's a display widget, which doesn't use queriables, since it doesn't assign
values::

  &gt;&gt;&gt; request = TestRequest()
  &gt;&gt;&gt; widget = zope.app.form.browser.source.SourceDisplayWidget(
  ...     pet, pet.source, request)
  &gt;&gt;&gt; print widget()
  Nothing
  &gt;&gt;&gt; from zope.app.form.browser.interfaces import IBrowserWidget
  &gt;&gt;&gt; IBrowserWidget.providedBy(widget)
  True

  &gt;&gt;&gt; widget.setRenderedValue('tabby')
  &gt;&gt;&gt; print widget()
  tabby

Like any good display widget, input is not required::

  &gt;&gt;&gt; widget.required
  False

If we specify a list of choices::

  &gt;&gt;&gt; pets = zope.schema.List(__name__ = 'pets', title=u"Pets",
  ...                         value_type=pet)

when a widget is computed for the field, a view will be looked up for the field
and the source, where, in this case, the field is a list field. We'll just call
the widget factory directly::

  &gt;&gt;&gt; widget = zope.app.form.browser.source.SourceListInputWidget(
  ...     pets, pets.value_type.source, request)

If we render the widget::

  &gt;&gt;&gt; print widget()
  &lt;div class="value"&gt;
    &lt;input type="hidden" name="field.pets.displayed" value="y" /&gt;
    &lt;div class="queries"&gt;
      &lt;div class="query"&gt;
        &lt;div class="queryinput"&gt;
  &lt;input name="field.pets.MA__.string"&gt;
  &lt;input type="submit" name="field.pets.MA__" value="Search"&gt;
        &lt;/div&gt; &lt;!-- queryinput --&gt;
      &lt;/div&gt; &lt;!-- query --&gt;
      &lt;div class="query"&gt;
        &lt;div class="queryinput"&gt;
  &lt;input name="field.pets.MQ__.string"&gt;
  &lt;input type="submit" name="field.pets.MQ__" value="Search"&gt;
        &lt;/div&gt; &lt;!-- queryinput --&gt;
      &lt;/div&gt; &lt;!-- query --&gt;
    &lt;/div&gt; &lt;!-- queries --&gt;
  &lt;/div&gt; &lt;!-- value --&gt;

Here the output looks very similar to the simple choice case.  We get a search
input for each source.  In this case, we don't show any inputs
(TODO we probably should make it clearer that there are no selected values.)

As before, we can search one of the sources::

  &gt;&gt;&gt; request.form['field.pets.displayed'] = u'y'
  &gt;&gt;&gt; request.form['field.pets.MQ__.string'] = u't'
  &gt;&gt;&gt; request.form['field.pets.MQ__'] = u'Search'

In which case, we'll get some results::

  &gt;&gt;&gt; print widget()
  &lt;div class="value"&gt;
    &lt;input type="hidden" name="field.pets.displayed" value="y" /&gt;
    &lt;div class="queries"&gt;
      &lt;div class="query"&gt;
        &lt;div class="queryinput"&gt;
  &lt;input name="field.pets.MA__.string"&gt;
  &lt;input type="submit" name="field.pets.MA__" value="Search"&gt;
        &lt;/div&gt; &lt;!-- queryinput --&gt;
      &lt;/div&gt; &lt;!-- query --&gt;
      &lt;div class="query"&gt;
        &lt;div class="queryinput"&gt;
  &lt;input name="field.pets.MQ__.string"&gt;
  &lt;input type="submit" name="field.pets.MQ__" value="Search"&gt;
        &lt;/div&gt; &lt;!-- queryinput --&gt;
        &lt;div class="queryresults"&gt;
  &lt;select name="field.pets.MQ__.selection:list" multiple&gt;
  &lt;option value="Ym9vdHM="&gt;boots&lt;/option&gt;
  &lt;option value="dGFiYnk="&gt;tabby&lt;/option&gt;
  &lt;option value="dGlnZXI="&gt;tiger&lt;/option&gt;
  &lt;option value="dG9t"&gt;tom&lt;/option&gt;
  &lt;/select&gt;
  &lt;input type="submit" name="field.pets.MQ__.apply" value="Apply" /&gt;
        &lt;/div&gt; &lt;!-- queryresults --&gt;
      &lt;/div&gt; &lt;!-- query --&gt;
    &lt;/div&gt; &lt;!-- queries --&gt;
  &lt;/div&gt; &lt;!-- value --&gt;

from which we can select some values::

  &gt;&gt;&gt; request.form['field.pets.displayed'] = u'y'
  &gt;&gt;&gt; del request.form['field.pets.MQ__.string']
  &gt;&gt;&gt; del request.form['field.pets.MQ__']
  &gt;&gt;&gt; request.form['field.pets.MQ__.selection'] = [
  ...     u'dGFiYnk=', u'dGlnZXI=', u'dG9t']
  &gt;&gt;&gt; request.form['field.pets.MQ__.apply'] = u'Apply'

Which then leads to the selections appearing as widget selections::

  &gt;&gt;&gt; print widget()
  &lt;div class="value"&gt;
    &lt;input type="checkbox" name="field.pets.checked:list" value="dGFiYnk=" /&gt;
    tabby
    &lt;input type="hidden" name="field.pets:list" value="dGFiYnk=" /&gt;
    &lt;br /&gt;
    &lt;input type="checkbox" name="field.pets.checked:list" value="dGlnZXI=" /&gt;
    tiger
    &lt;input type="hidden" name="field.pets:list" value="dGlnZXI=" /&gt;
    &lt;br /&gt;
    &lt;input type="checkbox" name="field.pets.checked:list" value="dG9t" /&gt;
    tom
    &lt;input type="hidden" name="field.pets:list" value="dG9t" /&gt;
    &lt;br /&gt;
    &lt;input type="submit" name="field.pets.remove" value="Remove" /&gt;
    &lt;br /&gt;
    &lt;input type="hidden" name="field.pets.displayed" value="y" /&gt;
    &lt;div class="queries"&gt;
      &lt;div class="query"&gt;
        &lt;div class="queryinput"&gt;
  &lt;input name="field.pets.MA__.string"&gt;
  &lt;input type="submit" name="field.pets.MA__" value="Search"&gt;
        &lt;/div&gt; &lt;!-- queryinput --&gt;
      &lt;/div&gt; &lt;!-- query --&gt;
      &lt;div class="query"&gt;
        &lt;div class="queryinput"&gt;
  &lt;input name="field.pets.MQ__.string"&gt;
  &lt;input type="submit" name="field.pets.MQ__" value="Search"&gt;
        &lt;/div&gt; &lt;!-- queryinput --&gt;
      &lt;/div&gt; &lt;!-- query --&gt;
    &lt;/div&gt; &lt;!-- queries --&gt;
  &lt;/div&gt; &lt;!-- value --&gt;

We can get the selected values::

  &gt;&gt;&gt; widget.getInputValue()
  ['tabby', 'tiger', 'tom']

We now see the values we selected.  We also have checkboxes and buttons that
allow us to remove selections::

  &gt;&gt;&gt; request.form['field.pets.displayed'] = u'y'
  &gt;&gt;&gt; request.form['field.pets'] = [u'dGFiYnk=', u'dGlnZXI=', u'dG9t']
  &gt;&gt;&gt; del request.form['field.pets.MQ__.selection']
  &gt;&gt;&gt; del request.form['field.pets.MQ__.apply']
  &gt;&gt;&gt; request.form['field.pets.checked'] = [u'dGFiYnk=', u'dG9t']
  &gt;&gt;&gt; request.form['field.pets.remove'] = u'Remove'

  &gt;&gt;&gt; print widget()
  &lt;div class="value"&gt;
    &lt;input type="checkbox" name="field.pets.checked:list" value="dGlnZXI=" /&gt;
    tiger
    &lt;input type="hidden" name="field.pets:list" value="dGlnZXI=" /&gt;
    &lt;br /&gt;
    &lt;input type="submit" name="field.pets.remove" value="Remove" /&gt;
    &lt;br /&gt;
    &lt;input type="hidden" name="field.pets.displayed" value="y" /&gt;
    &lt;div class="queries"&gt;
      &lt;div class="query"&gt;
        &lt;div class="queryinput"&gt;
  &lt;input name="field.pets.MA__.string"&gt;
  &lt;input type="submit" name="field.pets.MA__" value="Search"&gt;
        &lt;/div&gt; &lt;!-- queryinput --&gt;
      &lt;/div&gt; &lt;!-- query --&gt;
      &lt;div class="query"&gt;
        &lt;div class="queryinput"&gt;
  &lt;input name="field.pets.MQ__.string"&gt;
  &lt;input type="submit" name="field.pets.MQ__" value="Search"&gt;
        &lt;/div&gt; &lt;!-- queryinput --&gt;
      &lt;/div&gt; &lt;!-- query --&gt;
    &lt;/div&gt; &lt;!-- queries --&gt;
  &lt;/div&gt; &lt;!-- value --&gt;


Using vocabulary-dependent widgets with sources
===============================================

if you have a widget that uses old-style vocabularies but don't have the time
to rewrite it for sources, all is not lost! The wrapper
IterableSourceVocabulary can be used to make sources and ITerms look like a
vocabulary. This allows us to use vocabulary-based widgets with sources
instead of vocabularies.

Usage::

  &gt;&gt;&gt; from zope.schema.vocabulary import SimpleTerm

  &gt;&gt;&gt; values  = [u'a', u'b', u'c']
  &gt;&gt;&gt; tokens  = [ '0',  '1',  '2']
  &gt;&gt;&gt; titles  = [u'A', u'B', u'C']

  &gt;&gt;&gt; terms = [SimpleTerm(values[i], token=tokens[i], title=titles[i]) \
  ...     for i in range(0,len(values))]

  &gt;&gt;&gt; class TestSource(list):
  ...     zope.interface.implements(zope.schema.interfaces.IIterableSource)
  &gt;&gt;&gt; source = TestSource(values)

  &gt;&gt;&gt; class TestTerms(object):
  ...     zope.interface.implements(ITerms)
  ...     def __init__(self, source, request):
  ...         pass
  ...     def getTerm(self, value):
  ...         index = values.index(value)
  ...         return terms[index]
  ...     def getValue(self, token):
  ...         index = tokens.index(token)
  ...         return values[index]

  &gt;&gt;&gt; zope.component.provideAdapter(
  ...     TestTerms,
  ...     (TestSource, zope.publisher.interfaces.browser.IBrowserRequest))

  &gt;&gt;&gt; from zope.app.form.browser.source import IterableSourceVocabulary
  &gt;&gt;&gt; request = TestRequest()
  &gt;&gt;&gt; vocab = IterableSourceVocabulary(source, request)
  &gt;&gt;&gt; from zope.interface.verify import verifyClass, verifyObject
  &gt;&gt;&gt; verifyClass(zope.schema.interfaces.IVocabularyTokenized, \
  ...     IterableSourceVocabulary)
  True
  &gt;&gt;&gt; verifyObject(zope.schema.interfaces.IVocabularyTokenized, vocab)
  True

  &gt;&gt;&gt; len(vocab)
  3
  &gt;&gt;&gt; (u'a' in vocab) and (u'b' in vocab) and (u'c' in vocab)
  True
  &gt;&gt;&gt; [value for value in vocab] == terms
  True
  &gt;&gt;&gt; term = vocab.getTerm(u'b')
  &gt;&gt;&gt; (term.value, term.token, term.title)
  (u'b', '1', u'B')
  &gt;&gt;&gt; term = vocab.getTermByToken('2')
  &gt;&gt;&gt; (term.value, term.token, term.title)
  (u'c', '2', u'C')


====================
Internationalization
====================

Forms are fully internationalized.  The field names, descriptions,
labels, and hints are all automatically translated if they are made
i18n messages in the schema.

Let's take this simple add form...

  &gt;&gt;&gt; print http(r"""
  ... GET /+/addfieldcontent.html HTTP/1.1
  ... Authorization: Basic mgr:mgrpw
  ... """, handle_errors=False)
  HTTP/1.1 200 OK
  ...

with an error...

  &gt;&gt;&gt; print http(r"""
  ... POST /+/addfieldcontent.html HTTP/1.1
  ... Authorization: Basic mgr:mgrpw
  ... Content-Length: 670
  ... Content-Type: multipart/form-data; boundary=---------------------------19588947601368617292863650127
  ...
  ... -----------------------------19588947601368617292863650127
  ... Content-Disposition: form-data; name="field.title"
  ...
  ...
  ... -----------------------------19588947601368617292863650127
  ... Content-Disposition: form-data; name="field.description"
  ...
  ...
  ... -----------------------------19588947601368617292863650127
  ... Content-Disposition: form-data; name="field.somenumber"
  ...
  ... 0
  ... -----------------------------19588947601368617292863650127
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ...
  ... Hinzufxgen
  ... -----------------------------19588947601368617292863650127
  ... Content-Disposition: form-data; name="add_input_name"
  ...
  ...
  ... -----------------------------19588947601368617292863650127--
  ... """, handle_errors=False)
  HTTP/1.1 200 OK
  ...
            There are &lt;strong&gt;1&lt;/strong&gt; input errors.
  ...


Translated
==========

And now the add form in German:

  &gt;&gt;&gt; print http(r"""
  ... GET /+/addfieldcontent.html HTTP/1.1
  ... Accept-Language: de
  ... Authorization: Basic mgr:mgrpw
  ... """, handle_errors=False)
  HTTP/1.1 200 OK
  ...Felderinhalt hinzuf...
  ...Eine kurz...Titel...
  ...Eine ausf...Beschreibung...
  ...Irgendeine Zahl...
  ...Irgendeine Liste...
  ...Irgendeine Liste hinzuf...
  ...Auffrischen...
  ...Hinzuf...
  ...Objektname...

The same with an input error:

  &gt;&gt;&gt; print http(r"""
  ... POST /+/addfieldcontent.html HTTP/1.1
  ... Accept-Language: de
  ... Authorization: Basic mgr:mgrpw
  ... Content-Length: 670
  ... Content-Type: multipart/form-data; boundary=---------------------------19588947601368617292863650127
  ...
  ... -----------------------------19588947601368617292863650127
  ... Content-Disposition: form-data; name="field.title"
  ...
  ...
  ... -----------------------------19588947601368617292863650127
  ... Content-Disposition: form-data; name="field.description"
  ...
  ...
  ... -----------------------------19588947601368617292863650127
  ... Content-Disposition: form-data; name="field.somenumber"
  ...
  ... 0
  ... -----------------------------19588947601368617292863650127
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ...
  ... Hinzufxgen
  ... -----------------------------19588947601368617292863650127
  ... Content-Disposition: form-data; name="add_input_name"
  ...
  ...
  ... -----------------------------19588947601368617292863650127--
  ... """, handle_errors=False)
  HTTP/1.1 200 OK
  ...Felderinhalt hinzuf...
  ...Ein Fehler ist aufgetreten...
  ...Es gab &lt;strong&gt;1&lt;/strong&gt; Eingabefehler...
  ...Eine kurz...Titel...
  ...Erforderliche Eingabe fehlt...
  ...Eine ausf...Beschreibung...
  ...Irgendeine Zahl...
  ...Irgendeine Liste...
  ...hinzuf...
  ...Auffrischen...
  ...Hinzuf...
  ...Objektname...


Source widgets
==============

Titles of terms are translated by the source widgets. Let's create a source
for which the terms create message ids:

  &gt;&gt;&gt; import zc.sourcefactory.basic
  &gt;&gt;&gt; from zope.i18nmessageid import MessageFactory
  &gt;&gt;&gt; _ = MessageFactory('coffee')
  &gt;&gt;&gt; class Coffees(zc.sourcefactory.basic.BasicSourceFactory):
  ...     def getValues(self):
  ...         return ['arabica', 'robusta', 'liberica', 'excelsa']
  ...     def getTitle(self, value):
  ...         return _(value, default='Translated %s' % value)


  &gt;&gt;&gt; import zope.schema
  &gt;&gt;&gt; from zope.publisher.browser import TestRequest
  &gt;&gt;&gt; coffee = zope.schema.Choice(
  ...    __name__ = 'coffee',
  ...    title=u"Kinds of coffee beans",
  ...    source=Coffees())
  &gt;&gt;&gt; request = TestRequest()
  &gt;&gt;&gt; widget = zope.app.form.browser.source.SourceDisplayWidget(
  ...     coffee, coffee.source, request)
  &gt;&gt;&gt; print widget()
  Nothing
  &gt;&gt;&gt; from zope.app.form.browser.interfaces import IBrowserWidget
  &gt;&gt;&gt; IBrowserWidget.providedBy(widget)
  True
  &gt;&gt;&gt; widget.setRenderedValue('arabica')
  &gt;&gt;&gt; print widget()
  Translated arabica


=======
CHANGES
=======

3.9.0 (2009-10-08)
==================

- Internationalized 'Invalid value' used with ConversionError
- Added dependency on transaction and test dependency on zope.app.component.
- Moved dependencies on ZODB3 and zope.location to the test extra.
- Reduced the dependency on zope.app.publisher to a dependency on
  zope.browsermenu plus a test dependency on zope.browserpage.

3.8.1 (2009-07-23)
==================

- Fix unittest failure due to translation update.

3.8.0 (2009-05-24)
==================

- Use standard properties instead of `zope.cachedescriptors`.

- Require `zope.browser` 1.1 instead of `zope.app.container` for IAdding.

3.7.3 (2009-05-11)
==================

- Fixed invalid markup.

3.7.2 (2009-03-12)
==================

- Fixed bug where OrderedMultiSelectWidget did not respect the widgets
  size attribute.

- Fixed bug in SequenceWidget where it crashed while trying to iterate
  a missing_value (None in most of cases) on _getRenderedValue.

- Adapt to removal of deprecated interfaces from zope.component.interfaces.
  The IView was moved to zope.publisher and we use our custom IWidgetFactory
  interface instead of removed zope.component.interfaces.IViewFactory.

- Fix tests to work on Python 2.6.

3.7.1 (2009-01-31)
==================

- Adapt to the upcoming zope.schema release 3.5.1 which will also silence the
  spurious `set` failures.

3.7.0 (2008-12-11)
==================

- use zope.browser.interfaces.ITerms instead of zope.app.form.browser.interfaces

- Depending on zope.schema&gt;=3.5a1 which uses the builtin ``set`` instead of the
  ``sets`` module.


3.6.4 (2008-11-26)
==================

- The URIDisplayWidget doesn't render an anchor for empty/None values.


3.6.3 (2008-10-15)
==================

- Get rid of deprecated usage of LayerField from
  zope.app.component.back35, replaced by
  zope.configuration.fields.GlobalInterface.

3.6.2 (2008-09-08)
==================


- Fixed restructured text in doc tests to unbreak the PyPI page.

(3.6.1 skipped due to a typo)


3.6.0 (2008-08-22)
==================

- Dropdown widgets display an item for the missing value even if the field is
  required when no value is selected. See zope/app/form/browser/README.txt on
  how to switch this off for BBB.

- Source select widgets for required fields are now required as well. They
  used not to be required on the assumption that some value would be selected
  by the browser, which had always been wrong except for dropdown widgets.


3.5.0 (2008-06-05)
==================

- Translate the title on SequenceWidget's "Add &lt;title&gt;" button.

- No longer uses zapi.


3.4.2 (2008-02-07)
==================

- Made display widgets for sources translate message IDs correctly.


3.4.1 (2007-10-31)
==================

- Resolve ``ZopeSecurityPolicy`` deprecation warning.


3.4.0 (2007-10-24)
==================

- ``zope.app.form`` now supports Python2.5

- Initial release independent of the main Zope tree.


Before 3.4
==========

This package was part of the Zope 3 distribution and did not have its own
CHANGES.txt. For earlier changes please refer to either our subversion log or
the CHANGES.txt of earlier Zope 3 releases.</description>
<homepage rdf:resource="http://pypi.python.org/pypi/zope.app.form" />
<maintainer><foaf:Person><foaf:name>Zope Corporation and Contributors</foaf:name>
<foaf:mbox_sha1sum>2a5d53de05a9e41953ed1826447b07e9a7fa1525</foaf:mbox_sha1sum></foaf:Person></maintainer>
<release><Version><revision>3.9.0</revision></Version></release>
</Project></rdf:RDF>