[Checkins] SVN: z3c.form/trunk/ merged zagy-sources branch to get support for sources (not only vocabularies)
Michael Howitz
mh at gocept.com
Thu Dec 11 04:11:57 EST 2008
Log message for revision 93891:
merged zagy-sources branch to get support for sources (not only vocabularies)
Changed:
U z3c.form/trunk/AUTHOR.txt
U z3c.form/trunk/CHANGES.txt
U z3c.form/trunk/setup.py
U z3c.form/trunk/src/z3c/form/browser/checkbox.txt
U z3c.form/trunk/src/z3c/form/browser/radio.txt
U z3c.form/trunk/src/z3c/form/configure.zcml
U z3c.form/trunk/src/z3c/form/converter.txt
U z3c.form/trunk/src/z3c/form/interfaces.py
U z3c.form/trunk/src/z3c/form/term.py
U z3c.form/trunk/src/z3c/form/term.txt
U z3c.form/trunk/src/z3c/form/testing.py
U z3c.form/trunk/src/z3c/form/widget.txt
-=-
Modified: z3c.form/trunk/AUTHOR.txt
===================================================================
--- z3c.form/trunk/AUTHOR.txt 2008-12-11 08:42:56 UTC (rev 93890)
+++ z3c.form/trunk/AUTHOR.txt 2008-12-11 09:11:57 UTC (rev 93891)
@@ -6,3 +6,4 @@
Herman Himmelbauer
Martijn Faassen
Paul Carduner
+Michael Howitz
\ No newline at end of file
Modified: z3c.form/trunk/CHANGES.txt
===================================================================
--- z3c.form/trunk/CHANGES.txt 2008-12-11 08:42:56 UTC (rev 93890)
+++ z3c.form/trunk/CHANGES.txt 2008-12-11 09:11:57 UTC (rev 93891)
@@ -43,6 +43,10 @@
- Refactoring: Use the ``z3c.pt.compat`` template engine compatibility
layer.
+- Feature: Added Support for using sources: where is was previosly
+ possible to use a vocabulary it is now also possible to use a
+ source. (Works both for basic and contextual sources.)
+
- Feature: Added benchmarking suite demonstrating performance gain
when using ``z3c.pt``.
Modified: z3c.form/trunk/setup.py
===================================================================
--- z3c.form/trunk/setup.py 2008-12-11 08:42:56 UTC (rev 93890)
+++ z3c.form/trunk/setup.py 2008-12-11 09:11:57 UTC (rev 93891)
@@ -83,6 +83,7 @@
'z3c.coverage',
'z3c.template',
'z3c.pt >= 1.0b4',
+ 'zc.sourcefactory',
'lxml >= 2.1.1',
],
adding = ['zope.app.container'],
@@ -91,6 +92,7 @@
'setuptools',
'zope.app.component',
'zope.app.pagetemplate',
+ 'zope.browser',
'zope.component',
'zope.configuration',
'zope.event',
Modified: z3c.form/trunk/src/z3c/form/browser/checkbox.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/checkbox.txt 2008-12-11 08:42:56 UTC (rev 93890)
+++ z3c.form/trunk/src/z3c/form/browser/checkbox.txt 2008-12-11 09:11:57 UTC (rev 93891)
@@ -54,14 +54,14 @@
>>> print widget.render()
<input name="widget.name-empty-marker" type="hidden" value="1" />
-Let's provide some values for this widget. We can do this by defining a source
-providing ``ITerms``. This source uses descriminators wich will fit for our
-setup.
+Let's provide some values for this widget. We can do this by defining
+a vocabulary providing ``ITerms``. This vocabulary uses descriminators
+wich will fit for our setup.
>>> import zope.schema.interfaces
>>> from zope.schema.vocabulary import SimpleVocabulary
>>> import z3c.form.term
- >>> class MyTerms(z3c.form.term.ChoiceTerms):
+ >>> class MyTerms(z3c.form.term.ChoiceTermsVocabulary):
... def __init__(self, context, request, form, field, widget):
... self.terms = SimpleVocabulary.fromValues(['yes', 'no'])
>>> zope.component.provideAdapter(z3c.form.term.BoolTerms,
Modified: z3c.form/trunk/src/z3c/form/browser/radio.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/radio.txt 2008-12-11 08:42:56 UTC (rev 93890)
+++ z3c.form/trunk/src/z3c/form/browser/radio.txt 2008-12-11 09:11:57 UTC (rev 93891)
@@ -8,7 +8,7 @@
>>> from z3c.form import interfaces
>>> from z3c.form.browser import radio
-The TextWidget is a widget:
+The RadioWidget is a widget:
>>> verifyClass(interfaces.IWidget, radio.RadioWidget)
True
@@ -53,11 +53,14 @@
providing ITerms. This source uses descriminators wich will fit for our setup.
>>> import zope.schema.interfaces
- >>> from zope.schema.vocabulary import SimpleVocabulary
>>> import z3c.form.term
- >>> class MyTerms(z3c.form.term.ChoiceTerms):
+ >>> from zc.sourcefactory.basic import BasicSourceFactory
+ >>> class YesNoSourceFactory(BasicSourceFactory):
+ ... def getValues(self):
+ ... return ['yes', 'no']
+ >>> class MyTerms(z3c.form.term.ChoiceTermsSource):
... def __init__(self, context, request, form, field, widget):
- ... self.terms = SimpleVocabulary.fromValues(['yes', 'no'])
+ ... self.terms = YesNoSourceFactory()
>>> zope.component.provideAdapter(z3c.form.term.BoolTerms,
... adapts=(zope.interface.Interface,
... interfaces.IFormLayer, zope.interface.Interface,
Modified: z3c.form/trunk/src/z3c/form/configure.zcml
===================================================================
--- z3c.form/trunk/src/z3c/form/configure.zcml 2008-12-11 08:42:56 UTC (rev 93890)
+++ z3c.form/trunk/src/z3c/form/configure.zcml 2008-12-11 09:11:57 UTC (rev 93891)
@@ -77,12 +77,24 @@
<!-- ITerms -->
<adapter
- factory=".term.ChoiceTerms"
+ factory=".term.choice_terms_multiplexer"
/>
<adapter
- factory=".term.CollectionTerms"
+ factory=".term.ChoiceTermsVocabulary"
/>
<adapter
+ factory=".term.ChoiceTermsSource"
+ />
+ <adapter
+ factory=".term.collection_terms_multiplexer"
+ />
+ <adapter
+ factory=".term.CollectionTermsVocabulary"
+ />
+ <adapter
+ factory=".term.CollectionTermsSource"
+ />
+ <adapter
factory=".term.BoolTerms"
/>
Modified: z3c.form/trunk/src/z3c/form/converter.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/converter.txt 2008-12-11 08:42:56 UTC (rev 93890)
+++ z3c.form/trunk/src/z3c/form/converter.txt 2008-12-11 09:11:57 UTC (rev 93891)
@@ -480,13 +480,26 @@
For widgets and fields that work with choices of a sequence, a special data
converter is required that works with terms. A prime example is a choice
-field. Before we can use the converter, we have to register the terms adapter:
+field. Before we can use the converter, we have to register some adapters:
>>> from z3c.form import term
- >>> zope.component.provideAdapter(term.ChoiceTerms)
+ >>> import zc.sourcefactory.browser.source
+ >>> import zc.sourcefactory.browser.token
+ >>> zope.component.provideAdapter(term.ChoiceTermsVocabulary)
+ >>> zope.component.provideAdapter(term.ChoiceTermsSource)
+ >>> zope.component.provideAdapter(term.choice_terms_multiplexer)
+ >>> zope.component.provideAdapter(
+ ... zc.sourcefactory.browser.source.FactoredTerms)
+ >>> zope.component.provideAdapter(
+ ... zc.sourcefactory.browser.token.fromInteger)
-Let's now create a choice field and a widget:
+The choice fields can be used together with vocabularies and sources.
+Using vocabulary
+~~~~~~~~~~~~~~~~
+
+Let's now create a choice field (using a vocabulary) and a widget:
+
>>> from zope.schema.vocabulary import SimpleVocabulary
>>> gender = zope.schema.Choice(
@@ -542,19 +555,82 @@
>>> sdv.toFieldValue([])
'missing'
+Using source
+~~~~~~~~~~~~
+Let's now create a choice field (using a source) and a widget:
+
+ >>> from zc.sourcefactory.basic import BasicSourceFactory
+ >>> class GenderSourceFactory(BasicSourceFactory):
+ ... _mapping = {0: u'male', 1: u'female'}
+ ... def getValues(self):
+ ... return self._mapping.keys()
+ ... def getTitle(self, value):
+ ... return self._mapping[value]
+ >>> gender_source = zope.schema.Choice(
+ ... source = GenderSourceFactory())
+
+ >>> seqWidget = widget.SequenceWidget(TestRequest())
+ >>> seqWidget.field = gender_source
+
+We now use the field and widget to instantiate the converter:
+
+ >>> sdv = converter.SequenceDataConverter(gender, seqWidget)
+
+We can now convert a real value to a widget value, which will be the term's
+token:
+
+ >>> sdv.toWidgetValue(0)
+ ['0']
+
+The result is always a sequence, since sequence widgets only deal collections
+of values. Of course, we can convert the widget value back to an internal
+value:
+
+ >>> sdv.toFieldValue(['0'])
+ 0
+
+Sometimes a field is not required. In those cases, the internalvalue is the
+missing value of the field. The converter interprets that as no value being
+selected:
+
+ >>> gender.missing_value = 'missing'
+
+ >>> sdv.toWidgetValue(gender.missing_value)
+ []
+
+If "no value" has been specified in the widget, the missing value
+of the field is returned:
+
+ >>> sdv.toFieldValue([u'--NOVALUE--'])
+ 'missing'
+
+An empty list will also cause the missing value to be returned:
+
+ >>> sdv.toFieldValue([])
+ 'missing'
+
+
Collection Sequence Data Converter
----------------------------------
For widgets and fields that work with a sequence of choices, another data
converter is required that works with terms. A prime example is a list
-field. Before we can use the converter, we have to register the terms adapter:
+field. Before we can use the converter, we have to register the terms adapters:
>>> from z3c.form import term
- >>> zope.component.provideAdapter(term.CollectionTerms)
+ >>> zope.component.provideAdapter(term.collection_terms_multiplexer)
+ >>> zope.component.provideAdapter(term.CollectionTermsVocabulary)
+ >>> zope.component.provideAdapter(term.CollectionTermsSource)
-Let's now create a set field and a widget:
+Collections can also use either vocabularies or sources.
+Using vocabulary
+~~~~~~~~~~~~~~~~
+
+Let's now create a list field (using the previously defined field using
+a vocabulary) and a widget:
+
>>> genders = zope.schema.List(value_type=gender)
>>> seqWidget = widget.SequenceWidget(TestRequest())
>>> seqWidget.field = genders
@@ -605,7 +681,7 @@
set([0])
Getting Terms
-~~~~~~~~~~~~~
++++++++++++++
As an optimization of this converter, the converter actually does not look up
the terms itself but uses the widget's ``terms`` attribute. If the terms are
@@ -623,7 +699,7 @@
['m']
>>> seqWidget.terms
- <z3c.form.term.CollectionTerms object ...>
+ <z3c.form.term.CollectionTermsVocabulary object ...>
The same is true when getting the field value:
@@ -637,9 +713,90 @@
set([0])
>>> seqWidget.terms
- <z3c.form.term.CollectionTerms object ...>
+ <z3c.form.term.CollectionTermsVocabulary object ...>
+Using source
+~~~~~~~~~~~~
+Let's now create a list field (using the previously defined field using
+a source) and a widget:
+
+ >>> genders_source = zope.schema.List(value_type=gender_source)
+ >>> seqWidget = widget.SequenceWidget(TestRequest())
+ >>> seqWidget.field = genders_source
+
+We now use the field and widget to instantiate the converter:
+
+ >>> csdv = converter.CollectionSequenceDataConverter(
+ ... genders_source, seqWidget)
+
+We can now convert a real value to a widget value, which will be the term's
+token:
+
+ >>> csdv.toWidgetValue([0])
+ ['0']
+
+The result is always a sequence, since sequence widgets only deal collections
+of values. Of course, we can convert the widget value back to an internal
+value:
+
+ >>> csdv.toFieldValue(['0'])
+ [0]
+
+For some field, like the ``Set``, the collection type is a tuple. Sigh. In
+these cases we use the last entry in the tuple as the type to use:
+
+ >>> genders_source = zope.schema.Set(value_type=gender_source)
+ >>> seqWidget = widget.SequenceWidget(TestRequest())
+ >>> seqWidget.field = genders_source
+
+ >>> csdv = converter.CollectionSequenceDataConverter(
+ ... genders_source, seqWidget)
+
+ >>> csdv.toWidgetValue(set([0]))
+ ['0']
+
+ >>> csdv.toFieldValue(['0'])
+ set([0])
+
+Getting Terms
++++++++++++++
+
+As an optimization of this converter, the converter actually does not look up
+the terms itself but uses the widget's ``terms`` attribute. If the terms are
+not yet retrieved, the converter will ask the widget to do so when in need.
+
+So let's see how this works when getting the widget value:
+
+ >>> seqWidget = widget.SequenceWidget(TestRequest())
+ >>> seqWidget.field = genders_source
+
+ >>> seqWidget.terms
+
+ >>> csdv = converter.CollectionSequenceDataConverter(
+ ... genders_source, seqWidget)
+ >>> csdv.toWidgetValue([0])
+ ['0']
+
+ >>> seqWidget.terms
+ <z3c.form.term.CollectionTermsSource object ...>
+
+The same is true when getting the field value:
+
+ >>> seqWidget = widget.SequenceWidget(TestRequest())
+ >>> seqWidget.field = genders_source
+
+ >>> seqWidget.terms
+
+ >>> csdv = converter.CollectionSequenceDataConverter(
+ ... genders_source, seqWidget)
+ >>> csdv.toFieldValue(['0'])
+ set([0])
+
+ >>> seqWidget.terms
+ <z3c.form.term.CollectionTermsSource object ...>
+
+
Boolean to Single Checkbox Data Converter
-----------------------------------------
Modified: z3c.form/trunk/src/z3c/form/interfaces.py
===================================================================
--- z3c.form/trunk/src/z3c/form/interfaces.py 2008-12-11 08:42:56 UTC (rev 93890)
+++ z3c.form/trunk/src/z3c/form/interfaces.py 2008-12-11 09:11:57 UTC (rev 93891)
@@ -288,7 +288,7 @@
# term interfaces
class ITerms(zope.interface.Interface):
- """"""
+ """ """
context = zope.schema.Field()
request = zope.schema.Field()
@@ -315,6 +315,16 @@
LookupError is raised if there isn't a value in the source.
"""
+ def __iter__():
+ """Iterate over terms."""
+
+ def __len__():
+ """Return number of terms."""
+
+ def __contains__(value):
+ """Check wether terms containes the ``value``."""
+
+
class IBoolTerms(ITerms):
"""A specialization that handles boolean choices."""
Modified: z3c.form/trunk/src/z3c/form/term.py
===================================================================
--- z3c.form/trunk/src/z3c/form/term.py 2008-12-11 08:42:56 UTC (rev 93890)
+++ z3c.form/trunk/src/z3c/form/term.py 2008-12-11 09:11:57 UTC (rev 93891)
@@ -15,6 +15,9 @@
$Id$
"""
+
+import zope.browser
+import zope.component
import zope.schema
from zope.schema import vocabulary
@@ -23,7 +26,7 @@
class Terms(object):
- """Base implementationf or custom ITerms."""
+ """Base implementation for custom ITerms."""
zope.interface.implements(interfaces.ITerms)
@@ -45,28 +48,95 @@
def __contains__(self, value):
return self.terms.__contains__(value)
+class SourceTerms(Terms):
+ """Base implementation for ITerms using a source instead of a vocabulary."""
-class ChoiceTerms(Terms):
- """ITerms adapter for zope.schema.IChoice based implementations."""
+ zope.interface.implements(interfaces.ITerms)
+ def __init__(self, context, request, form, field, source, widget):
+ self.context = context
+ self.request = request
+ self.form = form
+ self.field = field
+ self.widget = widget
+ self.source = source
+ self.terms = zope.component.getMultiAdapter(
+ (self.source, self.request),
+ zope.browser.interfaces.ITerms)
+
+ def getTermByToken(self, token):
+ # This is rather expensive
+ for value in self.source:
+ term = self.getTerm(value)
+ if term.token == token:
+ return term
+
+ def getValue(self, token):
+ return self.terms.getValue(token)
+
+ def __iter__(self):
+ for value in self.source:
+ yield self.terms.getTerm(value)
+
+ def __len__(self):
+ return len(self.source)
+
+ def __contains__(self, value):
+ return value in self.source
+
+
+ at zope.interface.implementer(interfaces.ITerms)
+ at zope.component.adapter(
+ zope.interface.Interface,
+ interfaces.IFormLayer,
+ zope.interface.Interface,
+ zope.schema.interfaces.IChoice,
+ interfaces.IWidget)
+def choice_terms_multiplexer(context, request, form, field, widget):
+ field = field.bind(context)
+ terms = field.vocabulary
+ return zope.component.queryMultiAdapter(
+ (context, request, form, field, terms, widget),
+ interfaces.ITerms)
+
+
+class ChoiceTermsVocabulary(Terms):
+ """ITerms adapter for zope.schema.IChoice based implementations using
+ vocabulary."""
+
zope.component.adapts(
zope.interface.Interface,
interfaces.IFormLayer,
zope.interface.Interface,
zope.schema.interfaces.IChoice,
+ zope.schema.interfaces.IBaseVocabulary,
interfaces.IWidget)
- def __init__(self, context, request, form, field, widget):
+ zope.interface.implements(interfaces.ITerms)
+
+ def __init__(self, context, request, form, field, vocabulary, widget):
self.context = context
self.request = request
self.form = form
self.field = field
self.widget = widget
- if field.vocabulary is None:
- field = field.bind(context)
- self.terms = field.vocabulary
+ self.terms = vocabulary
+class ChoiceTermsSource(SourceTerms):
+ "ITerms adapter for zope.schema.IChoice based implementations using source."
+
+ zope.component.adapts(
+ zope.interface.Interface,
+ interfaces.IFormLayer,
+ zope.interface.Interface,
+ zope.schema.interfaces.IChoice,
+ zope.schema.interfaces.IIterableSource,
+ interfaces.IWidget)
+
+ zope.interface.implements(interfaces.ITerms)
+
+
class BoolTerms(Terms):
"""Default yes and no terms are used by default for IBool fields."""
@@ -93,21 +163,49 @@
(False, 'false', self.falseLabel)]]
self.terms = vocabulary.SimpleVocabulary(terms)
+ at zope.interface.implementer(interfaces.ITerms)
+ at zope.component.adapter(
+ zope.interface.Interface,
+ interfaces.IFormLayer,
+ zope.interface.Interface,
+ zope.schema.interfaces.ICollection,
+ interfaces.IWidget)
+def collection_terms_multiplexer(context, request, form, field, widget):
+ terms = field.value_type.bind(context).vocabulary
+ return zope.component.queryMultiAdapter(
+ (context, request, form, field, terms, widget),
+ interfaces.ITerms)
-class CollectionTerms(Terms):
- """ITerms adapter for zope.schema.ICollection based implementations."""
+class CollectionTermsVocabulary(Terms):
+ """ITerms adapter for zope.schema.ICollection based implementations using
+ vocabulary."""
zope.component.adapts(
zope.interface.Interface,
interfaces.IFormLayer,
zope.interface.Interface,
zope.schema.interfaces.ICollection,
+ zope.schema.interfaces.IBaseVocabulary,
interfaces.IWidget)
- def __init__(self, context, request, form, field, widget):
+ def __init__(self, context, request, form, field, vocabulary, widget):
self.context = context
self.request = request
self.form = form
self.field = field
self.widget = widget
- self.terms = field.value_type.bind(self.context).vocabulary
+ self.terms = vocabulary
+
+class CollectionTermsSource(SourceTerms):
+ """ITerms adapter for zope.schema.ICollection based implementations using
+ source."""
+
+ zope.component.adapts(
+ zope.interface.Interface,
+ interfaces.IFormLayer,
+ zope.interface.Interface,
+ zope.schema.interfaces.ICollection,
+ zope.schema.interfaces.IIterableSource,
+ interfaces.IWidget)
+
+ zope.interface.implements(interfaces.ITerms)
Modified: z3c.form/trunk/src/z3c/form/term.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/term.txt 2008-12-11 08:42:56 UTC (rev 93890)
+++ z3c.form/trunk/src/z3c/form/term.txt 2008-12-11 09:11:57 UTC (rev 93891)
@@ -6,6 +6,9 @@
needing them. Since Zope 3 already has sources and vocabularies, the base
terms class simply builds on them.
+Vocabularies
+============
+
Thus, let's create a vocabulary first:
>>> from zope.schema import vocabulary
@@ -15,6 +18,9 @@
... vocabulary.SimpleVocabulary.createTerm(2, '2', u'good')
... ])
+Terms
+-----
+
Now we can create the terms object:
>>> from z3c.form import term
@@ -70,17 +76,30 @@
Now, there are several terms implementations that were designed for particular
fields. Within the framework, terms are used as adapters with the follwoing
-discriminators: context, request, form, field, and widget.
+discriminators: context, request, form, field, vocabulary/source and widget.
-The first terms implementation is for ``Choice`` fields:
+Choice field
+============
+The first terms implementation is for ``Choice`` fields. Choice fields
+unfortunately can have a vocabulary and a source which behave differently.
+Let's have a look a the vocabulary first:
+
+ >>> import zope.component
+ >>> zope.component.provideAdapter(term.ChoiceTermsVocabulary)
+ >>> import z3c.form.testing
+ >>> request = z3c.form.testing.TestRequest()
+ >>> import z3c.form.widget
+ >>> widget = z3c.form.widget.Widget(request)
+
>>> import zope.schema
>>> ratingField = zope.schema.Choice(
... title=u'Rating',
... vocabulary=ratings)
- >>> terms = term.ChoiceTerms(None, None, None, ratingField, None)
+ >>> terms = term.choice_terms_multiplexer(
+ ... None, request, None, ratingField, widget)
>>> [entry.title for entry in terms]
[u'bad', u'okay', u'good']
@@ -93,7 +112,8 @@
Initially we get an error because the "Ratings" vocabulary is not defined:
- >>> terms = term.ChoiceTerms(None, None, None, ratingField2, None)
+ >>> terms = term.choice_terms_multiplexer(
+ ... None, request, None, ratingField2, widget)
Traceback (most recent call last):
...
VocabularyRegistryError: unknown vocabulary: 'Ratings'
@@ -109,10 +129,14 @@
We should now be able to get all terms as before:
- >>> terms = term.ChoiceTerms(None, None, None, ratingField2, None)
+ >>> terms = term.choice_terms_multiplexer(
+ ... None, request, None, ratingField, widget)
>>> [entry.title for entry in terms]
[u'bad', u'okay', u'good']
+Bool fields
+-----------
+
A similar terms implementation exists for a ``Bool`` field:
>>> truthField = zope.schema.Bool()
@@ -132,12 +156,199 @@
>>> [entry.title for entry in terms]
[u'True', u'False']
-Finally, there is a terms adapter for all collections:
+Collections
+-----------
+Finally, there are a terms adapters for all collections. But we have to
+register some adapters before using it:
+
+ >>> from z3c.form import term
+ >>> zope.component.provideAdapter(term.collection_terms_multiplexer)
+ >>> zope.component.provideAdapter(term.CollectionTermsVocabulary)
+ >>> zope.component.provideAdapter(term.CollectionTermsSource)
+
>>> ratingsField = zope.schema.List(
... title=u'Ratings',
... value_type=ratingField)
- >>> terms = term.CollectionTerms(None, None, None, ratingsField, None)
+ >>> terms = term.collection_terms_multiplexer(
+ ... None, request, None, ratingsField, widget)
>>> [entry.title for entry in terms]
[u'bad', u'okay', u'good']
+
+
+Sources
+=======
+
+Basic sources
+-------------
+
+Basic sources need no context to compute their value. Let's create a
+source first:
+
+ >>> from zc.sourcefactory.basic import BasicSourceFactory
+ >>> class RatingSourceFactory(BasicSourceFactory):
+ ... _mapping = {10: u'ugly', 20: u'nice', 30: u'great'}
+ ... def getValues(self):
+ ... return self._mapping.keys()
+ ... def getTitle(self, value):
+ ... return self._mapping[value]
+
+As we did not include the configure.zcml of zc.sourcefactory we have
+to register some required adapters manually. We also need the
+ChoiceTermsSource adapter:
+
+ >>> import zope.component
+ >>> import zc.sourcefactory.browser.source
+ >>> import zc.sourcefactory.browser.token
+ >>> zope.component.provideAdapter(
+ ... zc.sourcefactory.browser.source.FactoredTerms)
+ >>> zope.component.provideAdapter(
+ ... zc.sourcefactory.browser.token.fromInteger)
+ >>> zope.component.provideAdapter(term.ChoiceTermsSource)
+
+Choice fields
+~~~~~~~~~~~~~
+
+Sources can be used with ``Choice`` fields like vocabularies. First
+we create a field based on the source:
+
+ >>> sourceRatingField = zope.schema.Choice(
+ ... title=u'Sourced Rating',
+ ... source=RatingSourceFactory())
+
+We connect the field to a widget to see the ITerms adapter for sources
+at work:
+
+ >>> terms = term.choice_terms_multiplexer(
+ ... None, request, None, sourceRatingField, widget)
+
+Iterating over the terms adapter returnes the term objects:
+
+ >>> [entry for entry in terms]
+ [<zc.sourcefactory.browser.source.FactoredTerm object at 0x...>,
+ <zc.sourcefactory.browser.source.FactoredTerm object at 0x...>,
+ <zc.sourcefactory.browser.source.FactoredTerm object at 0x...>]
+ >>> len(terms)
+ 3
+ >>> [entry.token for entry in terms]
+ ['10', '20', '30']
+ >>> [entry.title for entry in terms]
+ [u'ugly', u'nice', u'great']
+
+Using a token it is possible to look up the term and the value:
+
+ >>> terms.getTermByToken('20').title
+ u'nice'
+ >>> terms.getValue('30')
+ 30
+
+With can test if a value is in the source:
+
+ >>> 30 in terms
+ True
+ >>> 25 in terms
+ False
+
+Collections
+~~~~~~~~~~~
+
+Finally, there are terms adapters for all collections:
+
+ >>> sourceRatingsField = zope.schema.List(
+ ... title=u'Sourced Ratings',
+ ... value_type=sourceRatingField)
+
+ >>> terms = term.collection_terms_multiplexer(
+ ... None, request, None, sourceRatingsField, widget)
+ >>> [entry.title for entry in terms]
+ [u'ugly', u'nice', u'great']
+
+
+Contextual sources
+------------------
+
+Contextual sources depend on the context they are called on. Let's
+create a context and a contextual source:
+
+ >>> from zc.sourcefactory.contextual import BasicContextualSourceFactory
+ >>> class RatingContext(object):
+ ... base_value = 10
+ >>> class ContextualRatingSourceFactory(BasicContextualSourceFactory):
+ ... _mapping = {10: u'ugly', 20: u'nice', 30: u'great'}
+ ... def getValues(self, context):
+ ... return [context.base_value + x for x in self._mapping.keys()]
+ ... def getTitle(self, context, value):
+ ... return self._mapping[value - context.base_value]
+
+As we did not include the configure.zcml of zc.sourcefactory we have
+to register some required adapters manually. We also need the
+ChoiceTermsSource adapter:
+
+ >>> import zope.component
+ >>> import zc.sourcefactory.browser.source
+ >>> import zc.sourcefactory.browser.token
+ >>> zope.component.provideAdapter(
+ ... zc.sourcefactory.browser.source.FactoredContextualTerms)
+ >>> zope.component.provideAdapter(
+ ... zc.sourcefactory.browser.token.fromInteger)
+ >>> zope.component.provideAdapter(term.ChoiceTermsSource)
+
+Choice fields
+~~~~~~~~~~~~~
+
+Contextual sources can be used with ``Choice`` fields like
+vocabularies. First we create a field based on the source:
+
+ >>> contextualSourceRatingField = zope.schema.Choice(
+ ... title=u'Context Sourced Rating',
+ ... source=ContextualRatingSourceFactory())
+
+We create an context object and connect the field to a widget to see
+the ITerms adapter for sources at work:
+
+ >>> rating_context = RatingContext()
+ >>> rating_context.base_value = 100
+ >>> terms = term.choice_terms_multiplexer(
+ ... rating_context, request, None, contextualSourceRatingField, widget)
+
+Iterating over the terms adapter returnes the term objects:
+
+ >>> [entry for entry in terms]
+ [<zc.sourcefactory.browser.source.FactoredTerm object at 0x...>,
+ <zc.sourcefactory.browser.source.FactoredTerm object at 0x...>,
+ <zc.sourcefactory.browser.source.FactoredTerm object at 0x...>]
+ >>> len(terms)
+ 3
+ >>> [entry.token for entry in terms]
+ ['110', '120', '130']
+ >>> [entry.title for entry in terms]
+ [u'ugly', u'nice', u'great']
+
+Using a token, it is possible to look up the term and the value:
+
+ >>> terms.getTermByToken('120').title
+ u'nice'
+ >>> terms.getValue('130')
+ 130
+
+With can test if a value is in the source:
+
+ >>> 130 in terms
+ True
+ >>> 125 in terms
+ False
+
+Collections
+~~~~~~~~~~~
+
+Finally, there are terms adapters for all collections:
+
+ >>> contextualSourceRatingsField = zope.schema.List(
+ ... title=u'Contextual Sourced Ratings',
+ ... value_type=contextualSourceRatingField)
+
+ >>> terms = term.collection_terms_multiplexer(
+ ... rating_context, request, None, contextualSourceRatingsField, widget)
+ >>> [entry.title for entry in terms]
+ [u'ugly', u'nice', u'great']
Modified: z3c.form/trunk/src/z3c/form/testing.py
===================================================================
--- z3c.form/trunk/src/z3c/form/testing.py 2008-12-11 08:42:56 UTC (rev 93890)
+++ z3c.form/trunk/src/z3c/form/testing.py 2008-12-11 09:11:57 UTC (rev 93891)
@@ -310,8 +310,12 @@
zope.component.provideAdapter(converter.TimedeltaDataConverter)
# Adapter for providing terms to radio list and other widgets
zope.component.provideAdapter(term.BoolTerms)
- zope.component.provideAdapter(term.ChoiceTerms)
- zope.component.provideAdapter(term.CollectionTerms)
+ zope.component.provideAdapter(term.choice_terms_multiplexer)
+ zope.component.provideAdapter(term.ChoiceTermsVocabulary)
+ zope.component.provideAdapter(term.ChoiceTermsSource)
+ zope.component.provideAdapter(term.collection_terms_multiplexer)
+ zope.component.provideAdapter(term.CollectionTermsVocabulary)
+ zope.component.provideAdapter(term.CollectionTermsSource)
# Adapter to create an action from a button
zope.component.provideAdapter(
button.ButtonAction, provides=interfaces.IButtonAction)
Modified: z3c.form/trunk/src/z3c/form/widget.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/widget.txt 2008-12-11 08:42:56 UTC (rev 93890)
+++ z3c.form/trunk/src/z3c/form/widget.txt 2008-12-11 09:11:57 UTC (rev 93891)
@@ -501,11 +501,12 @@
the adapter is registered, everything should work as expected:
>>> from z3c.form import term
- >>> zope.component.provideAdapter(term.ChoiceTerms)
+ >>> zope.component.provideAdapter(term.ChoiceTermsVocabulary)
+ >>> zope.component.provideAdapter(term.choice_terms_multiplexer)
>>> seqWidget.update()
>>> seqWidget.terms
- <z3c.form.term.ChoiceTerms object at ...>
+ <z3c.form.term.ChoiceTermsVocabulary object at ...>
So that's it. Everything else is the same from then on.
More information about the Checkins
mailing list