===========================
zeam.form.ztk choice widget
===========================

Simple case
===========

First we need a choice:

  >>> from zope import interface, schema
  >>> from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
  >>> from zope.interface.verify import verifyObject

  >>> def display_vocabulary(values):
  ...     for value in values:
  ...         print "%r %r %r" % (value.value, value.token, value.title)

  >>> letter_vocabulary = SimpleVocabulary([
  ...     SimpleTerm(value='A', token='a1', title='Letter A'),
  ...     SimpleTerm(value='B', token='b1', title='Letter B'),
  ...     SimpleTerm(value='C', token='c1', title='Letter C')])

  >>> class ISimpleChoice(interface.Interface):
  ...     choice = schema.Choice(
  ...         title=u"My favorite letter",
  ...         source=letter_vocabulary)


And we will need a content and a request to test:

  >>> from zope.publisher.browser import TestRequest
  >>> request = TestRequest()

  >>> class SimpleContent(object):
  ...    interface.implements(ISimpleChoice)
  ...    choice = None
  >>> content = SimpleContent()
  >>> content.choice = 'B'

  >>> broken_content = SimpleContent()
  >>> broken_content.choice = 'Z'

Field
-----

So now you can create a field, and get a choice field:

  >>> from zeam.form.base import Fields
  >>> from zeam.form.base import interfaces

  >>> simple_choice_fields = Fields(ISimpleChoice)
  >>> simple_field = simple_choice_fields['choice']
  >>> simple_field
  <ChoiceSchemaField My favorite letter>

  >>> simple_field.source is letter_vocabulary
  True

  >>> simple_field.validate('A', None)
  >>> simple_field.validate('foo', None)
  u'Constraint not satisfied'

  >>> verifyObject(interfaces.IField, simple_field)
  True

Widget
------

You have an associated widget:

  >>> from zeam.form.ztk import Widgets, FormData, DISPLAY

  >>> simple_form = FormData(content, request)
  >>> simple_form.ignoreContent = False

  >>> simple_widgets = Widgets(
  ...     simple_choice_fields,
  ...     form=simple_form,
  ...     request=request)

  >>> simple_widgets.update()

  >>> simple_widget = simple_widgets['form.field.choice']
  >>> simple_widget
  <ChoiceFieldWidget My favorite letter>

  >>> simple_widget.inputValue()
  'b1'

  >>> print simple_widget.render()
  <select id="form-field-choice" name="form.field.choice" class="field field-choice field-required">
    <option value="a1">Letter A</option>
    <option value="b1" selected="selected">Letter B</option>
    <option value="c1">Letter C</option>
  </select>

Display Widget
--------------

We have a display widget that display a value with the correct title:

  >>> display_form = FormData(content, request)
  >>> display_form.ignoreContent = False
  >>> display_form.ignoreRequest = True
  >>> display_form.mode = DISPLAY

  >>> display_widgets = Widgets(
  ...     simple_choice_fields,
  ...     form=display_form,
  ...     request=request)

  >>> display_widgets.update()

  >>> display_widget = display_widgets['form.field.choice']
  >>> display_widget
  <ChoiceDisplayWidget My favorite letter>

  >>> print display_widget.render()
  Letter B

You can display a content that have a value which is not in the
vocabulary. Nothing will be displayed:

  >>> broken_display_form = FormData(broken_content, request)
  >>> broken_display_form.ignoreContent = False
  >>> broken_display_form.ignoreRequest = True
  >>> broken_display_form.mode = DISPLAY

  >>> broken_display_widgets = Widgets(
  ...     simple_choice_fields,
  ...     form=broken_display_form,
  ...     request=request)

  >>> broken_display_widgets.update()

  >>> broken_display_widget = broken_display_widgets['form.field.choice']
  >>> broken_display_widget
  <ChoiceDisplayWidget My favorite letter>

  >>> print broken_display_widget.render()
  <BLANKLINE>

Extractor
---------

We need a custom extractor as the token value used in the form can be
different than the real value:

  >>> from zope import component
  >>> from zeam.form.base import interfaces

  >>> simple_extractor = component.getMultiAdapter(
  ...      (simple_field, simple_form, request), interfaces.IWidgetExtractor)

  >>> simple_extractor
  <zeam.form.ztk.widgets.choice.ChoiceWidgetExtractor object at ...>
  >>> simple_extractor.extract()
  (<Marker NO_VALUE>, None)

Let's now do it with a value:

  >>> simple_request = TestRequest(
  ...    form={simple_widget.identifier: u'a1', })

  >>> simple_extractor = component.getMultiAdapter(
  ...    (simple_field, simple_form, simple_request),
  ...    interfaces.IWidgetExtractor)

  >>> simple_extractor.extract()
  ('A', None)

And a value which is not in the vocabulary:

  >>> broken_request = TestRequest(
  ...    form={simple_widget.identifier: u'z42', })

  >>> broken_extractor = component.getMultiAdapter(
  ...    (simple_field, simple_form, broken_request),
  ...    interfaces.IWidgetExtractor)

  >>> broken_extractor.extract()
  (None, u'Invalid value')

Context binded source
=====================

Let's define a source which need the context to produce its values,
and an interface for it:

  >>> from grokcore import component
  >>> from zope.schema.interfaces import IContextSourceBinder

  >>> @component.provider(IContextSourceBinder)
  ... def secondVocabulary(context):
  ...     return letter_vocabulary

  >>> class ISecondChoice(interface.Interface):
  ...     choice = schema.Choice(
  ...         title=u"My Choice",
  ...         source=secondVocabulary)

  >>> class SecondContent(object):
  ...    interface.implements(ISecondChoice)
  ...    choice = None

  >>> content = SecondContent()
  >>> content.choice = 'C'

Field
-----

So now you can create a field, and get a choice field:

  >>> from zeam.form.ztk import Fields

  >>> secondChoiceFields = Fields(ISecondChoice)
  >>> secondField = secondChoiceFields['choice']
  >>> secondField
  <ChoiceSchemaField My Choice>
  >>> secondField.source is secondVocabulary
  True

  >>> choices = secondField.getChoices(None)
  >>> choices
  <zope.schema.vocabulary.SimpleVocabulary object at ...>
  >>> display_vocabulary(choices)
  'A' 'a1' 'Letter A'
  'B' 'b1' 'Letter B'
  'C' 'c1' 'Letter C'

  >>> secondField.validate('A', None)
  >>> secondField.validate(42, None)
  u'Constraint not satisfied'

Widget
------

You have an associated widget:

  >>> from zeam.form.ztk import Widgets, FormData

  >>> secondSub = FormData(content, request)
  >>> secondSub.ignoreContent = False

  >>> secondWidgets = Widgets(
  ...     secondChoiceFields,
  ...     form=secondSub,
  ...     request=request)

  >>> secondWidgets.update()

  >>> secondWidget = secondWidgets['form.field.choice']
  >>> secondWidget
  <ChoiceFieldWidget My Choice>

  >>> secondWidget.inputValue()
  'c1'

  >>> print secondWidget.render()
  <select id="form-field-choice" name="form.field.choice" class="field field-choice field-required">
    <option value="a1">Letter A</option>
    <option value="b1">Letter B</option>
    <option value="c1" selected="selected">Letter C</option>
  </select>

Registered vocabulary
=====================

Let's create a vocabulary that is registered in the ZCA, and use it in
a schema:

  >>> from zope.schema.interfaces import IVocabularyFactory
  >>> from zope.component import provideUtility, queryUtility

  >>> @component.provider(IVocabularyFactory)
  ... def vocabulary_factory(context):
  ...     return letter_vocabulary

  >>> provideUtility(vocabulary_factory, IVocabularyFactory, name="Third letter")
  >>> vocabulary = queryUtility(IVocabularyFactory, name="Third letter")
  >>> vocabulary
  <function vocabulary_factory at ...>

  >>> class IThirdChoice(interface.Interface):
  ...     choice = schema.Choice(
  ...         title=u"The third letter",
  ...         vocabulary="Third letter")

Field
-----

So now you can create a field, and get a choice field:

  >>> vocabulary_fields = Fields(IThirdChoice)
  >>> vocabulary_field = vocabulary_fields['choice']
  >>> vocabulary_field
  <ChoiceSchemaField The third letter>
  >>> vocabulary_field.source is vocabulary_factory
  True

  >>> choices = vocabulary_field.getChoices(None)
  >>> choices
  <zope.schema.vocabulary.SimpleVocabulary object at ...>
  >>> display_vocabulary(choices)
  'A' 'a1' 'Letter A'
  'B' 'b1' 'Letter B'
  'C' 'c1' 'Letter C'

  >>> vocabulary_field.validate('C', None)
