[Checkins] SVN: zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/ Move widget implementations to zope.formlib.

Martijn Faassen faassen at startifact.com
Wed Dec 30 14:46:05 EST 2009


Log message for revision 107377:
  Move widget implementations to zope.formlib.
  

Changed:
  U   zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/__init__.py
  U   zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/boolwidgets.py
  U   zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/itemswidgets.py
  D   zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/objectwidget.pt
  U   zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/objectwidget.py
  D   zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/orderedSelectionList.pt
  D   zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/sequencewidget.pt
  U   zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/sequencewidget.py
  U   zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/tests/test_itemswidget.py
  U   zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/textwidgets.py

-=-
Modified: zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/__init__.py
===================================================================
--- zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/__init__.py	2009-12-30 19:21:24 UTC (rev 107376)
+++ zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/__init__.py	2009-12-30 19:46:00 UTC (rev 107377)
@@ -17,64 +17,67 @@
 """
 __docformat__ = 'restructuredtext'
 
+# the implementation of widgets has moved to zope.formlib.widgets
+# import directly from there instead.
+
 from zope.formlib.widget import BrowserWidget, DisplayWidget
 from zope.formlib.widget import UnicodeDisplayWidget
 
-from zope.app.form.browser.textwidgets import TextWidget, BytesWidget
-from zope.app.form.browser.textwidgets import TextAreaWidget, BytesAreaWidget
-from zope.app.form.browser.textwidgets import PasswordWidget, FileWidget
-from zope.app.form.browser.textwidgets import ASCIIWidget, ASCIIAreaWidget
-from zope.app.form.browser.textwidgets import IntWidget, FloatWidget
-from zope.app.form.browser.textwidgets import DecimalWidget
-from zope.app.form.browser.textwidgets import DatetimeWidget, DateWidget
-from zope.app.form.browser.textwidgets import DatetimeI18nWidget
-from zope.app.form.browser.textwidgets import DateI18nWidget
-from zope.app.form.browser.textwidgets import DatetimeDisplayWidget
-from zope.app.form.browser.textwidgets import DateDisplayWidget
-from zope.app.form.browser.textwidgets import BytesDisplayWidget
-from zope.app.form.browser.textwidgets import ASCIIDisplayWidget
-from zope.app.form.browser.textwidgets import URIDisplayWidget
+from zope.formlib.widgets import TextWidget, BytesWidget
+from zope.formlib.widgets import TextAreaWidget, BytesAreaWidget
+from zope.formlib.widgets import PasswordWidget, FileWidget
+from zope.formlib.widgets import ASCIIWidget, ASCIIAreaWidget
+from zope.formlib.widgets import IntWidget, FloatWidget
+from zope.formlib.widgets import DecimalWidget
+from zope.formlib.widgets import DatetimeWidget, DateWidget
+from zope.formlib.widgets import DatetimeI18nWidget
+from zope.formlib.widgets import DateI18nWidget
+from zope.formlib.widgets import DatetimeDisplayWidget
+from zope.formlib.widgets import DateDisplayWidget
+from zope.formlib.widgets import BytesDisplayWidget
+from zope.formlib.widgets import ASCIIDisplayWidget
+from zope.formlib.widgets import URIDisplayWidget
 
 # Widgets for boolean fields
-from zope.app.form.browser.boolwidgets import CheckBoxWidget
-from zope.app.form.browser.boolwidgets import BooleanRadioWidget
-from zope.app.form.browser.boolwidgets import BooleanSelectWidget
-from zope.app.form.browser.boolwidgets import BooleanDropdownWidget
+from zope.formlib.widgets import CheckBoxWidget
+from zope.formlib.widgets import BooleanRadioWidget
+from zope.formlib.widgets import BooleanSelectWidget
+from zope.formlib.widgets import BooleanDropdownWidget
 
 # Choice and Sequence Display Widgets
-from zope.app.form.browser.itemswidgets import ItemDisplayWidget
-from zope.app.form.browser.itemswidgets import ItemsMultiDisplayWidget
-from zope.app.form.browser.itemswidgets import SetDisplayWidget
-from zope.app.form.browser.itemswidgets import ListDisplayWidget
+from zope.formlib.widgets import ItemDisplayWidget
+from zope.formlib.widgets import ItemsMultiDisplayWidget
+from zope.formlib.widgets import SetDisplayWidget
+from zope.formlib.widgets import ListDisplayWidget
 
 # Widgets for fields with vocabularies.
 # Note that these are only dispatchers for the widgets below.
-from zope.app.form.browser.itemswidgets import ChoiceDisplayWidget
-from zope.app.form.browser.itemswidgets import ChoiceInputWidget
-from zope.app.form.browser.itemswidgets import CollectionDisplayWidget
-from zope.app.form.browser.itemswidgets import CollectionInputWidget
-from zope.app.form.browser.itemswidgets import ChoiceCollectionDisplayWidget
-from zope.app.form.browser.itemswidgets import ChoiceCollectionInputWidget
+from zope.formlib.widgets import ChoiceDisplayWidget
+from zope.formlib.widgets import ChoiceInputWidget
+from zope.formlib.widgets import CollectionDisplayWidget
+from zope.formlib.widgets import CollectionInputWidget
+from zope.formlib.widgets import ChoiceCollectionDisplayWidget
+from zope.formlib.widgets import ChoiceCollectionInputWidget
 
 # Widgets that let you choose a single item from a list
 # These widgets are multi-views on (field, vocabulary)
-from zope.app.form.browser.itemswidgets import SelectWidget
-from zope.app.form.browser.itemswidgets import DropdownWidget
-from zope.app.form.browser.itemswidgets import RadioWidget
+from zope.formlib.widgets import SelectWidget
+from zope.formlib.widgets import DropdownWidget
+from zope.formlib.widgets import RadioWidget
 
 # Widgets that let you choose several items from a list
 # These widgets are multi-views on (field, vocabulary)
-from zope.app.form.browser.itemswidgets import MultiSelectWidget
-from zope.app.form.browser.itemswidgets import MultiSelectSetWidget
-from zope.app.form.browser.itemswidgets import MultiSelectFrozenSetWidget
-from zope.app.form.browser.itemswidgets import MultiCheckBoxWidget
-from zope.app.form.browser.itemswidgets import OrderedMultiSelectWidget
+from zope.formlib.widgets import MultiSelectWidget
+from zope.formlib.widgets import MultiSelectSetWidget
+from zope.formlib.widgets import MultiSelectFrozenSetWidget
+from zope.formlib.widgets import MultiCheckBoxWidget
+from zope.formlib.widgets import OrderedMultiSelectWidget
 
 # Widgets that let you enter several items in a sequence
 # These widgets are multi-views on (sequence type, value type)
-from zope.app.form.browser.sequencewidget import SequenceWidget
-from zope.app.form.browser.sequencewidget import TupleSequenceWidget
-from zope.app.form.browser.sequencewidget import ListSequenceWidget
-from zope.app.form.browser.sequencewidget import SequenceDisplayWidget
+from zope.formlib.widgets import SequenceWidget
+from zope.formlib.widgets import TupleSequenceWidget
+from zope.formlib.widgets import ListSequenceWidget
+from zope.formlib.widgets import SequenceDisplayWidget
 
-from zope.app.form.browser.objectwidget import ObjectWidget
+from zope.formlib.widgets import ObjectWidget

Modified: zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/boolwidgets.py
===================================================================
--- zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/boolwidgets.py	2009-12-30 19:21:24 UTC (rev 107376)
+++ zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/boolwidgets.py	2009-12-30 19:46:00 UTC (rev 107377)
@@ -15,121 +15,12 @@
 
 $Id$
 """
-__docformat__ = 'restructuredtext'
+# implementation moved to zope.formlib.boolwidgets
 
-from zope.interface import implements
-from zope.schema.vocabulary import SimpleVocabulary
-
-from zope.formlib.widget import SimpleInputWidget, renderElement
-from zope.formlib.widget import DisplayWidget
-from zope.app.form.browser.i18n import _
-from zope.app.form.browser.itemswidgets import RadioWidget
-from zope.app.form.browser.itemswidgets import SelectWidget, DropdownWidget
-from zope.formlib.interfaces import IInputWidget
-
-
-class CheckBoxWidget(SimpleInputWidget):
-    """A checkbox widget used to display Bool fields.
+from zope.formlib.boolwidgets import (
+    CheckBoxWidget,
+    BooleanRadioWidget,
+    BooleanSelectWidget,
+    BooleanDropdownWidget,
+    BooleanDisplayWidget)
     
-    For more detailed documentation, including sample code, see
-    ``tests/test_checkboxwidget.py``.
-    """    
-    type = 'checkbox'
-    default = 0
-    extra = ''
-
-    def __init__(self, context, request):
-        super(CheckBoxWidget, self).__init__(context, request)
-        self.required = False
-
-    def __call__(self):
-        """Render the widget to HTML."""
-        value = self._getFormValue()
-        if value == 'on':
-            kw = {'checked': 'checked'}
-        else:
-            kw = {}
-        return "%s %s" % (
-            renderElement(self.tag,
-                          type='hidden',
-                          name=self.name+".used",
-                          id=self.name+".used",
-                          value=""
-                          ),
-            renderElement(self.tag,
-                          type=self.type,
-                          name=self.name,
-                          id=self.name,
-                          cssClass=self.cssClass,
-                          extra=self.extra,
-                          value="on",
-                          **kw),
-            )
-
-    def _toFieldValue(self, input):
-        """Convert from HTML presentation to Python bool."""
-        return input == 'on'
-
-    def _toFormValue(self, value):
-        """Convert from Python bool to HTML representation."""
-        return value and 'on' or ''
-
-    def hasInput(self):
-        """Check whether the field is represented in the form."""
-        return self.name + ".used" in self.request.form or \
-            super(CheckBoxWidget, self).hasInput()
-
-    def _getFormInput(self):
-        """Returns the form input used by `_toFieldValue`.
-        
-        Return values:
-        
-          ``'on'``  checkbox is checked
-          ``''``    checkbox is not checked
-          ``None``  form input was not provided
-
-        """
-        if self.request.get(self.name) == 'on':
-            return 'on'
-        elif self.name + '.used' in self.request:
-            return ''
-        else:
-            return None
-
-
-def BooleanRadioWidget(field, request, true=_('on'), false=_('off')):
-    vocabulary = SimpleVocabulary.fromItems( ((true, True), (false, False)) ) 
-    widget = RadioWidget(field, vocabulary, request)
-    widget.required = False
-    return widget
-
-
-def BooleanSelectWidget(field, request, true=_('on'), false=_('off')):
-    vocabulary = SimpleVocabulary.fromItems( ((true, True), (false, False)) )
-    widget = SelectWidget(field, vocabulary, request)
-    widget.size = 2
-    widget.required = False
-    return widget
-
-
-def BooleanDropdownWidget(field, request, true=_('on'), false=_('off')):
-    vocabulary = SimpleVocabulary.fromItems( ((true, True), (false, False)) )
-    widget = DropdownWidget(field, vocabulary, request)
-    widget.required = False
-    return widget
-
-
-_msg_true = _("True")
-_msg_false = _("False")
-
-class BooleanDisplayWidget(DisplayWidget):
-
-    def __call__(self):
-        if self._renderedValueSet():
-            value = self._data
-        else:
-            value = self.context.default
-        if value:
-            return _msg_true
-        else:
-            return _msg_false

Modified: zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/itemswidgets.py
===================================================================
--- zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/itemswidgets.py	2009-12-30 19:21:24 UTC (rev 107376)
+++ zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/itemswidgets.py	2009-12-30 19:46:00 UTC (rev 107377)
@@ -16,619 +16,33 @@
 $Id$
 """
 __docformat__ = 'restructuredtext'
-from xml.sax.saxutils import escape
 
-from zope import component
-from zope.interface import implements
-from zope.i18n import translate
-from zope.schema.interfaces import ValidationError, InvalidValue
-from zope.schema.interfaces import ConstraintNotSatisfied, ITitledTokenizedTerm
+# the implementation has moved to zope.formlib.itemswidgets
 
-from zope.formlib.widget import SimpleInputWidget, renderElement
-from zope.formlib.interfaces import IInputWidget, IDisplayWidget
-from zope.formlib.interfaces import ConversionError
-from zope.app.form.browser.i18n import _
-from zope.browserpage import ViewPageTemplateFile
-
-
-# For choices, we want to make the widget a view of the field and vocabulary.
-
-def ChoiceDisplayWidget(field, request):
-    return component.getMultiAdapter((field, field.vocabulary, request),
-                                     IDisplayWidget)
-
-def ChoiceInputWidget(field, request):
-    return component.getMultiAdapter((field, field.vocabulary, request),
-                                     IInputWidget)
-
-# for collections, we want to make the widget a view of the field and the
-# value_type.  If the value_type is None we may fall over.  We may
-# not be able to do any better than that.
-
-def CollectionDisplayWidget(field, request):
-    return component.getMultiAdapter((field, field.value_type, request),
-                                     IDisplayWidget)
-
-def CollectionInputWidget(field, request):
-    return component.getMultiAdapter((field, field.value_type, request),
-                                     IInputWidget)
-
-# for collections of choices, we want to make the widget a view of the field,
-# the value type, and the vocabulary.
-
-def ChoiceCollectionDisplayWidget(field, value_type, request):
-    return component.getMultiAdapter((field, value_type.vocabulary, request),
-                                     IDisplayWidget)
-
-def ChoiceCollectionInputWidget(field, value_type, request):
-    return component.getMultiAdapter((field, value_type.vocabulary, request),
-                                     IInputWidget)
-
-class TranslationHook(object):
-    """A mixin class that provides the translation capabilities."""
-
-    def translate(self, msgid):
-        return translate(msgid, context=self.request, default=msgid)
-
-class ItemsWidgetBase(TranslationHook, SimpleInputWidget):
-    """Convenience base class for widgets displaying items/choices."""
-
-    extra = ""
-
-    def __init__(self, field, vocabulary, request):
-        """Initialize the widget."""
-        # only allow this to happen for a bound field
-        assert field.context is not None
-        self.vocabulary = vocabulary
-        super(ItemsWidgetBase, self).__init__(field, request)
-        self.empty_marker_name = self.name + "-empty-marker"
-
-    def setPrefix(self, prefix):
-        """Set the prefixes for the field names of the form."""
-        super(ItemsWidgetBase, self).setPrefix(prefix)
-        # names for other information from the form
-        self.empty_marker_name = self.name + "-empty-marker"
-
-    def __call__(self):
-        """Render the widget to HTML."""
-        raise NotImplementedError(
-            "__call__() must be implemented by a subclass; use _getFormValue()"
-            )
-
-    def textForValue(self, term):
-        """Extract a string from the `term`.
-
-        The `term` must be a vocabulary tokenized term.
-
-        This can be overridden to support more complex `term`
-        objects. The token is returned here since it's the only thing
-        known to be a string, or str()able.
-
-        """
-        titled = ITitledTokenizedTerm(term, None)
-        if titled is None:
-            return term.token
-        return self.translate(titled.title)
-
-    def convertTokensToValues(self, tokens):
-        """Convert term tokens to the terms themselves.
-
-        Tokens are used in the HTML form to represent terms. This method takes
-        the form tokens and converts them back to terms.
-        """
-        values = []
-        for token in tokens:
-            try:
-                term = self.vocabulary.getTermByToken(token)
-            except LookupError, error:
-                raise InvalidValue("token %r not found in vocabulary" % token)
-            else:
-                values.append(term.value)
-        return values
-
-    def _emptyMarker(self):
-        """Mark the form so that empty selections are also valid."""
-        return '<input name="%s" type="hidden" value="1" />' % (
-            self.empty_marker_name)
-
-    def hasInput(self):
-        """Check whether we have any input."""
-        return (self.name in self.request.form or
-                self.empty_marker_name in self.request.form)
-
-    def _toFieldValue(self, input):
-        """See `SimpleInputWidget`"""
-        raise NotImplementedError(
-            "_toFieldValue(input) must be implemented by a subclass\n"
-            "It may be inherited from the mix-in classes SingleDataHelper\n"
-            "or MultiDataHelper")
-
-
-class SingleDataHelper(object):
-    """Mix-in helper class for getting the term from the HTML form.
-
-    This is used when we expect a single input, i.e. the Choice field.
-    """
-
-    def _toFieldValue(self, input):
-        if input:
-            try:
-                return self.convertTokensToValues([input])[0]
-            except InvalidValue, e:
-                raise ConversionError(_("Invalid value"), e)
-        else:
-            return self.context.missing_value
-
-    def hidden(self):
-        #XXX: _getFormValue() should return a string value that can be
-        #     used in a HTML form, but it doesn't. When
-        #     http://www.zope.org/Collectors/Zope3-dev/584 gets fixed
-        #     this hack should be reverted.
-        #     -- Bjorn Tillenius, 2006-04-12
-        value = self._getFormValue()
-        if value == self._missing:
-            form_value = ''
-        else:
-            form_value = self.vocabulary.getTerm(value).token
-        return renderElement(u'input',
-                             type='hidden',
-                             name=self.name,
-                             id=self.name,
-                             value=form_value,
-                             cssClass=self.cssClass,
-                             extra=self.extra)
-
-
-class MultiDataHelper(object):
-    """Mix-in helper class for getting the term from the HTML form.
-
-    This is used when we expect a multiple inputs, i.e. Sequence fields with a
-    Choice field as value_type.
-    """
-
-    def _toFieldValue(self, input):
-        """See SimpleInputWidget"""
-        if input is None:
-            input = []
-        elif not isinstance(input, list):
-            input = [input]
-        try:
-            values = self.convertTokensToValues(input)
-        except InvalidValue, e:
-            raise ConversionError(_("Invalid value"), e)
-
-        # All AbstractCollection fields have a `_type` attribute specifying
-        # the type of collection. Use it to generate the correct type,
-        # otherwise return a list.  TODO: this breaks encapsulation.
-        if hasattr(self.context, '_type'):
-            _type = self.context._type
-            if isinstance(_type, tuple):
-                _type = _type[0]
-            return _type(values)
-        else:
-            return values
-
-
-    def _getDefault(self):
-        # Return the default value for this widget;
-        # may be overridden by subclasses.
-        val = self.context.default
-        if val is None:
-            val = []
-        return val
-
-
-## Display-Widgets for Items-related fields.
-
-class ItemDisplayWidget(SingleDataHelper, ItemsWidgetBase):
-    """Simple single-selection display that can be used in many cases."""
-
-    def __init__(self, *args, **kw):
-        ItemsWidgetBase.__init__(self, *args, **kw)
-        self.required = False
-
-    _messageNoValue = _("item-missing-single-value-for-display", "")
-
-    def __call__(self):
-        """See IBrowserWidget."""
-        value = self._getFormValue()
-        if not value:
-            return self.translate(self._messageNoValue)
-        else:
-            term = self.vocabulary.getTerm(value)
-            return self.textForValue(term)
-
-
-class ItemsMultiDisplayWidget(MultiDataHelper, ItemsWidgetBase):
-    """Displays a sequence of items."""
-
-    def __init__(self, *args, **kw):
-        ItemsWidgetBase.__init__(self, *args, **kw)
-        self.required = False
-
-    _messageNoValue = _("vocabulary-missing-multiple-value-for-display", "")
-
-    itemTag = 'li'
-    tag = 'ol'
-
-    def __call__(self):
-        """See IBrowserWidget."""
-        value = self._getFormValue()
-        if value:
-            rendered_items = self.renderItems(value)
-            return renderElement(self.tag,
-                                 id=self.name,
-                                 cssClass=self.cssClass,
-                                 contents="\n".join(rendered_items),
-                                 extra=self.extra)
-        else:
-            return self.translate(self._messageNoValue)
-
-    def renderItems(self, value):
-        """Render items of sequence."""
-        items = []
-        cssClass = self.cssClass or ''
-        if cssClass:
-            cssClass += "-item"
-        tag = self.itemTag
-        for item in value:
-            term = self.vocabulary.getTerm(item)
-            items.append(renderElement(
-                tag,
-                cssClass=cssClass,
-                contents=escape(self.textForValue(term))))
-        return items
-
-class ListDisplayWidget(ItemsMultiDisplayWidget):
-    """Display widget for ordered multi-selection fields.
-
-    This can be used for both Sequence, List, and Tuple fields.
-    """
-    tag = 'ol'
-
-class SetDisplayWidget(ItemsMultiDisplayWidget):
-    """Display widget for unordered multi-selection fields.
-
-    This can be used for both Set field.
-    """
-    tag = 'ul'
-
-
-## Edit-Widgets for Items-related fields.
-
-# BBB Set to False to never display an item for the missing value if the field
-# is required, which was the behaviour of versions up to and including 3.5.0.
-EXPLICIT_EMPTY_SELECTION = True
-
-
-class ItemsEditWidgetBase(SingleDataHelper, ItemsWidgetBase):
-    """Widget Base for rendering item-related fields.
-
-    These widgets work with Choice fields and Sequence fields that have Choice
-    as value_type.
-    """
-    implements(IInputWidget)
-
-    size = 5
-    tag = 'select'
-
-    _displayItemForMissingValue = True
-
-    # Whether an empty selection should always be made explicit, i.e. even
-    # if the field is required.
-    explicit_empty_selection = False
-
-    def __init__(self, field, vocabulary, request):
-        """Initialize the widget."""
-        super(ItemsEditWidgetBase, self).__init__(field, vocabulary, request)
-
-    def setPrefix(self, prefix):
-        """Set the prefix of the input name.
-
-        Once we set the prefix of input field, we use the name of the input
-        field and the postfix '-query' for the associated query view.
-        """
-        super(ItemsEditWidgetBase, self).setPrefix(prefix)
-
-
-    def __call__(self):
-        """See IBrowserWidget."""
-        value = self._getFormValue()
-        contents = []
-        have_results = False
-
-        contents.append(self._div('value', self.renderValue(value)))
-        contents.append(self._emptyMarker())
-
-        return self._div(self.cssClass, "\n".join(contents))
-
-
-    def _div(self, cssClass, contents, **kw):
-        """Render a simple div tag."""
-        if contents:
-            return renderElement('div',
-                                 cssClass=cssClass,
-                                 contents="\n%s\n" % contents,
-                                 **kw)
-        return ""
-
-
-    def renderItemsWithValues(self, values):
-        """Render the list of possible values, with those found in
-        `values` being marked as selected."""
-
-        cssClass = self.cssClass
-
-        # multiple items with the same value are not allowed from a
-        # vocabulary, so that need not be considered here
-        rendered_items = []
-        count = 0
-
-        # Handle case of missing value
-        missing = self._toFormValue(self.context.missing_value)
-
-        if self._displayItemForMissingValue and (
-            not self.context.required or
-            EXPLICIT_EMPTY_SELECTION and
-            self.explicit_empty_selection and
-            missing in values and
-            self.context.default is None):
-
-            if missing in values:
-                render = self.renderSelectedItem
-            else:
-                render = self.renderItem
-
-            missing_item = render(count,
-                self.translate(self._messageNoValue),
-                missing,
-                self.name,
-                cssClass)
-            rendered_items.append(missing_item)
-            count += 1
-
-        # Render normal values
-        for term in self.vocabulary:
-            item_text = self.textForValue(term)
-
-            if term.value in values:
-                render = self.renderSelectedItem
-            else:
-                render = self.renderItem
-
-            rendered_item = render(count,
-                item_text,
-                term.token,
-                self.name,
-                cssClass)
-
-            rendered_items.append(rendered_item)
-            count += 1
-
-        return rendered_items
-
-    def renderItem(self, index, text, value, name, cssClass):
-        """Render an item for a particular `value`."""
-        return renderElement('option',
-                             contents=escape(text),
-                             value=value,
-                             cssClass=cssClass)
-
-    def renderSelectedItem(self, index, text, value, name, cssClass):
-        """Render an item for a particular `value` that is selected."""
-        return renderElement('option',
-                             contents=escape(text),
-                             value=value,
-                             cssClass=cssClass,
-                             selected='selected')
-
-
-class SelectWidget(ItemsEditWidgetBase):
-    """Provide a selection list for the item."""
-
-    _messageNoValue = _("vocabulary-missing-single-value-for-edit",
-                        "(no value)")
-
-    def renderValue(self, value):
-        rendered_items = self.renderItems(value)
-        contents = "\n%s\n" %"\n".join(rendered_items)
-        return renderElement('select',
-                             name=self.name,
-                             id=self.name,
-                             contents=contents,
-                             size=self.size,
-                             extra=self.extra)
-
-    def renderItems(self, value):
-        return self.renderItemsWithValues([value])
-
-
-class DropdownWidget(SelectWidget):
-    """Variation of the SelectWidget that uses a drop-down list."""
-    size = 1
-    explicit_empty_selection = True
-
-
-class RadioWidget(SelectWidget):
-    """Radio widget for single item choices.
-
-    This widget can be used when the number of selections is going
-    to be small.
-    """
-    orientation = "vertical"
-
-    _messageNoValue = _("vocabulary-missing-single-value-for-edit",
-                        "(no value)")
-
-    def renderItem(self, index, text, value, name, cssClass):
-        """Render an item of the list."""
-        return self._renderItem(index, text, value, name, cssClass)
-
-    def renderSelectedItem(self, index, text, value, name, cssClass):
-        """Render a selected item of the list."""
-        return self._renderItem(index, text, value, name, cssClass,
-                                checked=True)
-
-    def _renderItem(self, index, text, value, name, cssClass, checked=False):
-        kw = {}
-        if checked:
-            kw['checked'] = 'checked'
-        id = '%s.%s' % (name, index)
-        elem = renderElement(u'input',
-                             value=value,
-                             name=name,
-                             id=id,
-                             cssClass=cssClass,
-                             type='radio',
-                             **kw)
-        return renderElement(u'label',
-                             contents='%s&nbsp;%s' % (elem, text),
-                             **{'for': id})
-
-    def renderValue(self, value):
-        rendered_items = self.renderItems(value)
-        if self.orientation == 'horizontal':
-            return "&nbsp;&nbsp;".join(rendered_items)
-        else:
-            return "<br />".join(rendered_items)
-
-
-class ItemsMultiEditWidgetBase(MultiDataHelper, ItemsEditWidgetBase):
-    """Items widget supporting multiple selections."""
-
-    _messageNoValue = _("vocabulary-missing-multiple-value-for-edit",
-                        "(no values)")
-    _displayItemForMissingValue = False
-
-    def renderItems(self, value):
-        if value == self.context.missing_value:
-            values = []
-        else:
-            values = list(value)
-        return self.renderItemsWithValues(values)
-
-    def renderValue(self, value):
-        # All we really add here is the ':list' in the name argument
-        # and mutliple='multiple' to renderElement().
-        rendered_items = self.renderItems(value)
-        return renderElement(self.tag,
-                             name=self.name + ':list',
-                             id=self.name,
-                             multiple='multiple',
-                             size=self.size,
-                             contents="\n".join(rendered_items),
-                             extra=self.extra)
-
-    def hidden(self):
-        items = []
-        for item in self._getFormValue():
-            items.append(
-                renderElement(u'input',
-                              type='hidden',
-                              name=self.name+':list',
-                              id=self.name,
-                              value=self.vocabulary.getTerm(item).token,
-                              cssClass=self.cssClass,
-                              extra=self.extra))
-        return '\n'.join(items)
-
-
-class MultiSelectWidget(ItemsMultiEditWidgetBase):
-    """Provide a selection list for the list to be selected."""
-
-
-class MultiSelectSetWidget(MultiSelectWidget):
-    """Provide a selection list for the set to be selected."""
-
-    def _toFieldValue(self, input):
-        value = super(MultiSelectSetWidget, self)._toFieldValue(input)
-        if isinstance(value, list):
-            value = set(value)
-        return value
-
-
-class MultiSelectFrozenSetWidget(MultiSelectWidget):
-    """Provide a selection list for the set to be selected."""
-
-    def _toFieldValue(self, input):
-        value = super(MultiSelectFrozenSetWidget, self)._toFieldValue(input)
-        if isinstance(value, list):
-            value = frozenset(value)
-        return value
-
-class OrderedMultiSelectWidget(ItemsMultiEditWidgetBase):
-    """A multi-selection widget with ordering support."""
-
-    template = ViewPageTemplateFile('orderedSelectionList.pt')
-
-    def choices(self):
-        """Return a set of tuples (text, value) that are available."""
-        # Not all content objects must necessarily support the attributes
-        if hasattr(self.context.context, self.context.__name__):
-            available_values = self.context.get(self.context.context)
-        else:
-            available_values = []
-        return [{'text': self.textForValue(term), 'value': term.token}
-                for term in self.vocabulary
-                if term.value not in available_values]
-
-    def selected(self):
-        """Return a list of tuples (text, value) that are selected."""
-        # Get form values
-        values = self._getFormValue()
-        # Not all content objects must necessarily support the attributes
-        if hasattr(self.context.context, self.context.__name__):
-            # merge in values from content
-            for value in self.context.get(self.context.context):
-                if value not in values:
-                    values.append(value)
-
-        terms = [self.vocabulary.getTerm(value)
-                 for value in values]
-        return [{'text': self.textForValue(term), 'value': term.token}
-                for term in terms]
-
-    def __call__(self):
-        return self.template()
-
-
-class MultiCheckBoxWidget(ItemsMultiEditWidgetBase):
-    """Provide a list of checkboxes that provide the choice for the list."""
-
-    orientation = "vertical"
-
-    _joinButtonToMessageTemplate = u"%s&nbsp;%s"
-
-    def renderValue(self, value):
-        rendered_items = self.renderItems(value)
-        if self.orientation == 'horizontal':
-            return "&nbsp;&nbsp;".join(rendered_items)
-        else:
-            return "<br />".join(rendered_items)
-
-    def renderItem(self, index, text, value, name, cssClass):
-        """Render an item of the list."""
-        return self._renderItem(index, text, value, name, cssClass)
-
-    def renderSelectedItem(self, index, text, value, name, cssClass):
-        """Render a selected item of the list."""
-        return self._renderItem(index, text, value, name, cssClass,
-                                checked=True)
-
-    def _renderItem(self, index, text, value, name, cssClass, checked=False):
-        kw = {}
-        if checked:
-            kw['checked'] = 'checked'
-        id = '%s.%s' % (name, index)
-        elem = renderElement('input',
-                             type="checkbox",
-                             cssClass=cssClass,
-                             name=name,
-                             id=id,
-                             value=value,
-                             **kw)
-        contents = self._joinButtonToMessageTemplate % (elem, text)
-        return renderElement(u'label',
-                             contents=contents,
-                             **{'for': id})
-
+from zope.formlib.itemswidgets import (
+    ChoiceDisplayWidget,
+    ChoiceInputWidget,
+    CollectionDisplayWidget,
+    CollectionInputWidget,
+    ChoiceCollectionDisplayWidget,
+    ChoiceCollectionInputWidget,
+    TranslationHook,
+    ItemsWidgetBase,
+    SingleDataHelper,
+    MultiDataHelper,
+    ItemsWidgetBase,
+    ItemDisplayWidget,
+    ItemsMultiDisplayWidget,
+    ListDisplayWidget,
+    SetDisplayWidget,
+    ItemsEditWidgetBase,
+    EXPLICIT_EMPTY_SELECTION,
+    SelectWidget,
+    DropdownWidget,
+    RadioWidget,
+    ItemsMultiEditWidgetBase,
+    MultiSelectWidget,
+    MultiSelectSetWidget,
+    MultiSelectFrozenSetWidget,
+    OrderedMultiSelectWidget,
+    MultiCheckBoxWidget)

Deleted: zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/objectwidget.pt
===================================================================
--- zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/objectwidget.pt	2009-12-30 19:21:24 UTC (rev 107376)
+++ zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/objectwidget.pt	2009-12-30 19:46:00 UTC (rev 107377)
@@ -1,7 +0,0 @@
-<fieldset>
-  <legend tal:content="context/legendTitle"
-        i18n:translate="">The Legend</legend>
-  <div class="row" tal:repeat="widget context/subwidgets">
-    <metal:block use-macro="context/@@form_macros/widget_row" />
-  </div>
-</fieldset>

Modified: zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/objectwidget.py
===================================================================
--- zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/objectwidget.py	2009-12-30 19:21:24 UTC (rev 107376)
+++ zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/objectwidget.py	2009-12-30 19:46:00 UTC (rev 107377)
@@ -15,179 +15,8 @@
 
 $Id$
 """
-__docformat__ = 'restructuredtext'
+# implementation moved to zope.formlib.objectwidget
 
-from zope import component
-from zope.interface import implements
-from zope.schema import getFieldNamesInOrder
-
-from zope.formlib.interfaces import IInputWidget
-from zope.formlib.widget import InputWidget
-from zope.formlib.widget import BrowserWidget
-from zope.app.form.utility import setUpWidgets, applyWidgetsChanges
-from zope.browserpage import ViewPageTemplateFile
-from zope.app.form.browser.interfaces import IWidgetInputErrorView
-
-
-class ObjectWidgetView:
-
-    template = ViewPageTemplateFile('objectwidget.pt')
-
-    def __init__(self, context, request):
-        self.context = context
-        self.request = request
-
-    def __call__(self):
-        return self.template()
-
-
-class ObjectWidget(BrowserWidget, InputWidget):
-    """A widget over an Interface that contains Fields.
-
-    ``factory``
-
-      factory used to create content that this widget (field) represents
-
-    ``*_widget``
-
-      Optional CustomWidgets used to generate widgets for the fields in this
-      widget
-    """
-
-    implements(IInputWidget)
-
-    _object = None      # the object value (from setRenderedValue & request)
-    _request_parsed = False
-
-    def __init__(self, context, request, factory, **kw):
-        super(ObjectWidget, self).__init__(context, request)
-
-        # define view that renders the widget
-        self.view = ObjectWidgetView(self, request)
-
-        # factory used to create content that this widget (field)
-        # represents
-        self.factory = factory
-
-        # handle foo_widget specs being passed in
-        self.names = getFieldNamesInOrder(self.context.schema)
-        for k, v in kw.items():
-            if k.endswith('_widget'):
-                setattr(self, k, v)
-
-        # set up my subwidgets
-        self._setUpEditWidgets()
-
-    def setPrefix(self, prefix):
-        super(ObjectWidget, self).setPrefix(prefix)
-        self._setUpEditWidgets()
-
-    def _setUpEditWidgets(self):
-        # subwidgets need a new name
-        setUpWidgets(self, self.context.schema, IInputWidget,
-                         prefix=self.name, names=self.names,
-                         context=self.context)
-
-    def __call__(self):
-        return self.view()
-
-    def legendTitle(self):
-        return self.context.title or self.context.__name__
-
-    def getSubWidget(self, name):
-        return getattr(self, '%s_widget' % name)
-
-    def subwidgets(self):
-        return [self.getSubWidget(name) for name in self.names]
-
-    def hidden(self):
-        """Render the object as hidden fields."""
-        result = []
-        for name in self.names:
-            result.append(self.getSubwidget(name).hidden())
-        return "".join(result)
-
-    def error(self):
-        if self._error:
-            errormessages = []
-            keys = self._error.keys(); keys.sort()
-            for key in keys:
-                errormessages.append(str(key) + ': ')
-                errormessages.append(component.getMultiAdapter(
-                    (self._error[key], self.request),
-                    IWidgetInputErrorView).snippet())
-                errormessages.append(str(key) + ', ')
-            return ''.join(errormessages[0:-1])
-        return ""
-
-    def getInputValue(self):
-        """Return converted and validated widget data.
-
-        The value for this field will be represented as an `ObjectStorage`
-        instance which holds the subfield values as attributes. It will
-        need to be converted by higher-level code into some more useful
-        object (note that the default EditView calls `applyChanges`, which
-        does this).
-        """
-
-        errors = []
-        content = self.factory()
-        for name in self.names:
-            try:
-                setattr(content, name, self.getSubWidget(name).getInputValue())
-            except Exception, e:
-                errors.append(e)
-                if self._error is None:
-                    self._error = {}
-                
-                if name not in self._error:
-                    self._error[name] = e
-
-        if errors:
-            raise errors[0]
-
-        return content
-
-
-    def applyChanges(self, content):
-        field = self.context
-
-        # create our new object value
-        value = field.query(content, None)
-        if value is None:
-            # TODO: ObjectCreatedEvent here would be nice
-            value = self.factory()
-
-        # apply sub changes, see if there *are* any changes
-        # TODO: ObjectModifiedEvent here would be nice
-        changes = applyWidgetsChanges(self, field.schema, target=value,
-                                      names=self.names)
-
-        # if there's changes, then store the new value on the content
-        if changes:
-            field.set(content, value)
-        # TODO: If value implements ILocation, set name to field name and
-        # parent to content
-
-        return changes
-
-    def hasInput(self):
-        """Is there input data for the field
-
-        Return ``True`` if there is data and ``False`` otherwise.
-        """
-        for name in self.names:
-            if self.getSubWidget(name).hasInput():
-                return True
-        return False
-
-    def setRenderedValue(self, value):
-        """Set the default data for the widget.
-
-        The given value should be used even if the user has entered
-        data.
-        """
-        # re-call setupwidgets with the content
-        self._setUpEditWidgets()
-        for name in self.names:
-            self.getSubWidget(name).setRenderedValue(getattr(value, name, None))
+from zope.formlib.objectwidget import (
+    ObjectWidgetView,
+    ObjectWidget)

Deleted: zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/orderedSelectionList.pt
===================================================================
--- zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/orderedSelectionList.pt	2009-12-30 19:21:24 UTC (rev 107376)
+++ zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/orderedSelectionList.pt	2009-12-30 19:46:00 UTC (rev 107377)
@@ -1,198 +0,0 @@
-<script type="text/javascript">
-
-function moveItems(from, to)
-  {
-  // shortcuts for selection fields
-  var src = document.getElementById(from);
-  var tgt = document.getElementById(to);
-
-  if (src.selectedIndex == -1) selectionError();
-  else
-    {
-    // iterate over all selected items
-    // --> attribute "selectedIndex" doesn't support multiple selection.
-    // Anyway, it works here, as a moved item isn't selected anymore,
-    // thus "selectedIndex" indicating the "next" selected item :)
-    while (src.selectedIndex > -1)
-      if (src.options[src.selectedIndex].selected)
-        {
-        // create a new virtal object with values of item to copy
-        temp = new Option(src.options[src.selectedIndex].text,
-                      src.options[src.selectedIndex].value);
-        // append virtual object to targe
-        tgt.options[tgt.length] = temp;
-        // want to select newly created item
-        temp.selected = true;
-        // delete moved item in source
-        src.options[src.selectedIndex] = null;
-      }
-    }
-  }
-
-// move item from "from" selection to "to" selection
-function from2to(name)
-  {
-  moveItems(name+".from", name+".to");
-  copyDataForSubmit(name);
-  }
-
-// move item from "to" selection back to "from" selection
-function to2from(name)
-  {
-  moveItems(name+".to", name+".from");
-  copyDataForSubmit(name);
-  }
-
-function swapFields(a, b)
-  {
-  // swap text
-  var temp = a.text;
-  a.text = b.text;
-  b.text = temp;
-  // swap value
-  temp = a.value;
-  a.value = b.value;
-  b.value = temp;
-  // swap selection
-  temp = a.selected;
-  a.selected = b.selected;
-  b.selected = temp;
-  }
-
-// move selected item in "to" selection one up
-function moveUp(name)
-  {
-  // shortcuts for selection field
-  var toSel = document.getElementById(name+".to");
-
-  if (toSel.selectedIndex == -1)
-      selectionError();
-  else if (toSel.options[0].selected)
-      alert("Cannot move further up!");
-  else for (var i = 0; toSel.length > i; i++)
-    if (toSel.options[i].selected)
-      {
-      swapFields(toSel.options[i-1], toSel.options[i]);
-      copyDataForSubmit(name);
-      }
-  }
-
-// move selected item in "to" selection one down
-function moveDown(name)
-  {
-    // shortcuts for selection field
-    var toSel = document.getElementById(name+".to");
-
-    if (toSel.selectedIndex == -1) {
-        selectionError();
-    } else if (toSel.options[toSel.length-1].selected) {
-        alert("Cannot move further down!");
-    } else {
-      for (var i = toSel.length-1; i >= 0; i--) {
-        if (toSel.options[i].selected) {
-          swapFields(toSel.options[i+1], toSel.options[i]);
-        }
-      }
-      copyDataForSubmit(name);
-    }
-  }
-
-// copy each item of "toSel" into one hidden input field
-function copyDataForSubmit(name)
-  {
-  // shortcuts for selection field and hidden data field
-  var toSel = document.getElementById(name+".to");
-  var toDataContainer = document.getElementById(name+".toDataContainer");
-
-  // delete all child nodes (--> complete content) of "toDataContainer" span
-  while (toDataContainer.hasChildNodes())
-      toDataContainer.removeChild(toDataContainer.firstChild);
-
-  // create new hidden input fields - one for each selection item of
-  // "to" selection
-  for (var i = 0; toSel.options.length > i; i++)
-    {
-    // create virtual node with suitable attributes
-    var newNode = document.createElement("input");
-    var newAttr = document.createAttribute("name");
-    newAttr.nodeValue = name;
-    newNode.setAttributeNode(newAttr);
-
-    newAttr = document.createAttribute("type");
-    newAttr.nodeValue = "hidden";
-    newNode.setAttributeNode(newAttr);
-
-    newAttr = document.createAttribute("value");
-    newAttr.nodeValue = toSel.options[i].value;
-    newNode.setAttributeNode(newAttr);
-
-    // actually append virtual node to DOM tree
-    toDataContainer.appendChild(newNode);
-    }
-  }
-
-// error message for missing selection
-function selectionError()
-  {alert("Must select something!")}
-
-</script>
-
-<table border="0" class="ordered-selection-field">
-  <tr>
-    <td>
-      <select id="from" name="from" size="5" multiple=""
-          tal:attributes="name string:${view/name}.from;
-                          id string:${view/name}.from;
-                          size view/size"
-                          >
-        <option tal:repeat="entry view/choices"
-                tal:attributes="value entry/value"
-                tal:content="entry/text" i18n:translate=""/>
-      </select>
-    </td>
-    <td>
-      <button name="from2toButton" type="button" value=" -&gt;"
-          onclick="javascript:from2to()"
-          tal:attributes="onClick string:javascript:from2to('${view/name}')"
-          >&nbsp;-&gt;</button>
-      <br />
-      <button name="to2fromButton" type="button" value="&lt;- "
-          onclick="javascript:to2from()"
-          tal:attributes="onClick string:javascript:to2from('${view/name}')"
-          >&lt;-&nbsp;</button>
-    </td>
-    <td>
-      <select id="to" name="to" size="5" multiple=""
-          tal:attributes="name string:${view/name}.to;
-                          id string:${view/name}.to;
-                          size view/size">
-        <option tal:repeat="entry view/selected"
-                tal:attributes="value entry/value"
-                tal:content="entry/text" i18n:translate=""/>
-      </select>
-      <input name="foo-empty-marker" type="hidden"
-        tal:attributes="name string:${view/name}-empty-marker"/>
-      <span id="toDataContainer"
-            tal:attributes="id string:${view/name}.toDataContainer">
-        <script type="text/javascript" tal:content="string:
-          copyDataForSubmit('${view/name}');">
-          // initial copying of field "field.to" --> "field"
-          copyDataForSubmit("<i tal:replace="${view/name}"/>");
-        </script>
-      </span>
-    </td>
-    <td>
-      <button
-          name="upButton" type="button" value="^"
-          onclick="javascript:moveUp()"
-          tal:attributes="onClick string:javascript:moveUp('${view/name}')"
-          >^</button>
-      <br />
-      <button
-          name="downButton" type="button" value="v"
-          onclick="javascript:moveDown()"
-          tal:attributes="onClick string:javascript:moveDown('${view/name}')"
-          >v</button>
-    </td>
-  </tr>
-</table>

Deleted: zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/sequencewidget.pt
===================================================================
--- zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/sequencewidget.pt	2009-12-30 19:21:24 UTC (rev 107376)
+++ zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/sequencewidget.pt	2009-12-30 19:46:00 UTC (rev 107377)
@@ -1,29 +0,0 @@
-<table border="0" class="sequencewidget"
-  i18n:domain="zope">
-  <tr tal:repeat="widget view/widgets">
-    <td>
-      <input class="editcheck" type="checkbox"
-             tal:attributes="
-                 name string:${view/name}.remove_${repeat/widget/index}"
-             tal:condition="view/need_delete" />
-    </td>
-    <td>
-      <span tal:define="error widget/error"
-            tal:replace="structure error" tal:condition="error" />
-      <input tal:replace="structure widget" />
-    </td>
-  </tr>
-  <tr>
-    <td colspan="2">
-      <input type="submit" value="Remove selected items"
-             tal:condition="view/need_delete"
-             tal:attributes="name string:${view/name}.remove"
-             i18n:attributes="value remove-selected-items" />
-      <input type="submit" value="Add foo"
-             tal:condition="view/need_add"
-             tal:attributes="name string:${view/name}.add;
-                             value view/addButtonLabel" />
-    </td>
-  </tr>
-</table>
-<input tal:replace="structure view/marker" />

Modified: zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/sequencewidget.py
===================================================================
--- zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/sequencewidget.py	2009-12-30 19:21:24 UTC (rev 107376)
+++ zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/sequencewidget.py	2009-12-30 19:46:00 UTC (rev 107377)
@@ -15,301 +15,9 @@
 
 $Id$
 """
-__docformat__ = 'restructuredtext'
-
-from zope import component
-from zope.interface import implements
-from zope.i18n import translate
-from zope.schema.interfaces import ValidationError
-
-from zope.formlib.interfaces import IDisplayWidget, IInputWidget
-from zope.formlib.interfaces import WidgetInputError, MissingInputError
-from zope.formlib.widget import InputWidget
-from zope.app.form.browser.i18n import _
-from zope.formlib.widget import BrowserWidget
-from zope.formlib.widget import DisplayWidget, renderElement
-from zope.browserpage import ViewPageTemplateFile
-
-
-class SequenceWidget(BrowserWidget, InputWidget):
-    """A widget baseclass for a sequence of fields.
-
-    subwidget  - Optional CustomWidget used to generate widgets for the
-                 items in the sequence
-    """
-
-    implements(IInputWidget)
-
-    template = ViewPageTemplateFile('sequencewidget.pt')
-
-    _type = tuple
-
-    def __init__(self, context, field, request, subwidget=None):
-        super(SequenceWidget, self).__init__(context, request)
-        self.subwidget = subwidget
-
-        # The subwidgets are cached in this dict if preserve_widgets is True.
-        self._widgets = {}
-        self.preserve_widgets = False
-
-    def __call__(self):
-        """Render the widget"""
-        self._update()
-        return self.template()
-
-    def _update(self):
-        """Set various attributes for the template"""
-        sequence = self._getRenderedValue()
-        num_items = len(sequence)
-        self.need_add = (not self.context.max_length
-                         or num_items < self.context.max_length)
-        self.need_delete = num_items and num_items > self.context.min_length
-        self.marker = self._getPresenceMarker(num_items)
-
-    def widgets(self):
-        """Return a list of widgets to display"""
-        sequence = self._getRenderedValue()
-        result = []
-        for i, value in enumerate(sequence):
-            widget = self._getWidget(i)
-            widget.setRenderedValue(value)
-            result.append(widget)
-        return result
-
-    def addButtonLabel(self):
-        button_label = _('Add %s')
-        button_label = translate(button_label, context=self.request,
-                                 default=button_label)
-        title = self.context.title or self.context.__name__
-        title = translate(title, context=self.request, default=title)
-        return button_label % title
-
-
-    def _getWidget(self, i):
-        """Return a widget for the i-th number of the sequence.
-
-        Normally this method creates a new widget each time, but when
-        the ``preserve_widgets`` attribute is True, it starts caching
-        widgets.  We need it so that the errors on the subwidgets
-        would appear only if ``getInputValue`` was called.
-
-        ``getInputValue`` on the subwidgets gets called on each
-        request that has data.
-        """
-        if i not in self._widgets:
-            field = self.context.value_type
-            if self.subwidget is not None:
-                widget = self.subwidget(field, self.request)
-            else:
-                widget = component.getMultiAdapter(
-                    (field, self.request), IInputWidget)
-            widget.setPrefix('%s.%d.' % (self.name, i))
-            if not self.preserve_widgets:
-                return widget
-            self._widgets[i] = widget
-        return self._widgets[i]
-
-    def hidden(self):
-        """Render the list as hidden fields."""
-        # length of sequence info
-        sequence = self._getRenderedValue()
-        num_items = len(sequence)
-
-        # generate hidden fields for each value
-        parts = [self._getPresenceMarker(num_items)]
-        for i in range(num_items):
-            value = sequence[i]
-            widget = self._getWidget(i)
-            widget.setRenderedValue(value)
-            parts.append(widget.hidden())
-        return "\n".join(parts)
-
-    def _getRenderedValue(self):
-        """Returns a sequence from the request or _data"""
-        if self._renderedValueSet():
-            if self._data is self.context.missing_value:
-                sequence = []
-            else:
-                sequence = list(self._data)
-        elif self.hasInput():
-            sequence = self._generateSequence()
-        elif self.context.default is not None:
-            sequence = self.context.default
-        else:
-            sequence = []
-        # ensure minimum number of items in the form
-        while len(sequence) < self.context.min_length:
-            # Shouldn't this use self.field.value_type.missing_value,
-            # instead of None?
-            sequence.append(None)
-        return sequence
-
-    def _getPresenceMarker(self, count=0):
-        return ('<input type="hidden" name="%s.count" value="%d" />'
-                % (self.name, count))
-
-    def getInputValue(self):
-        """Return converted and validated widget data.
-
-        If there is no user input and the field is required, then a
-        ``MissingInputError`` will be raised.
-
-        If there is no user input and the field is not required, then
-        the field default value will be returned.
-
-        A ``WidgetInputError`` is raised in the case of one or more
-        errors encountered, inputting, converting, or validating the data.
-        """
-        if self.hasInput():
-            self.preserve_widgets = True
-            sequence = self._type(self._generateSequence())
-            if sequence != self.context.missing_value:
-                # catch and set field errors to ``_error`` attribute
-                try:
-                    self.context.validate(sequence)
-                except WidgetInputError, error:
-                    self._error = error
-                    raise self._error
-                except ValidationError, error:
-                    self._error = WidgetInputError(
-                        self.context.__name__, self.label, error)
-                    raise self._error
-            elif self.context.required:
-                raise MissingInputError(self.context.__name__,
-                                        self.context.title)
-            return sequence
-        raise MissingInputError(self.context.__name__, self.context.title)
-
-    # TODO: applyChanges isn't reporting "change" correctly (we're
-    # re-generating the sequence with every edit, and need to be smarter)
-    def applyChanges(self, content):
-        field = self.context
-        value = self.getInputValue()
-        change = field.query(content, self) != value
-        if change:
-            field.set(content, value)
-        return change
-
-    def hasInput(self):
-        """Is there input data for the field
-
-        Return ``True`` if there is data and ``False`` otherwise.
-        """
-        return (self.name + ".count") in self.request.form
-
-    def _generateSequence(self):
-        """Extract the values of the subwidgets from the request.
-
-        Returns a list of values.
-
-        This can only be called if self.hasInput() returns true.
-        """
-        if self.context.value_type is None:
-            # Why would this ever happen?
-            return []
-        # the marker field tells how many individual items were
-        # included in the input; we check for exactly that many input
-        # widgets
-        try:
-            count = int(self.request.form[self.name + ".count"])
-        except ValueError:
-            # could not convert to int; the input was not generated
-            # from the widget as implemented here
-            raise WidgetInputError(self.context.__name__, self.context.title)
-
-        # pre-populate
-        sequence = [None] * count
-
-        # now look through the request for interesting values
-        # in reverse so that we can remove items as we go
-        removing = self.name + ".remove" in self.request.form
-        for i in reversed(range(count)):
-            widget = self._getWidget(i)
-            if widget.hasValidInput():
-                # catch and set sequence widget errors to ``_error`` attribute
-                try:
-                    sequence[i] = widget.getInputValue()
-                except WidgetInputError, error:
-                    self._error = error
-                    raise self._error
-
-            remove_key = "%s.remove_%d" % (self.name, i)
-            if remove_key in self.request.form and removing:
-                del sequence[i]
-
-        # add an entry to the list if the add button has been pressed
-        if self.name + ".add" in self.request.form:
-            # Should this be using self.context.value_type.missing_value
-            # instead of None?
-            sequence.append(None)
-
-        return sequence
-
-
-class TupleSequenceWidget(SequenceWidget):
-    _type = tuple
-
-
-class ListSequenceWidget(SequenceWidget):
-    _type = list
-
-
-# Basic display widget
-
-class SequenceDisplayWidget(DisplayWidget):
-
-    _missingValueMessage = _("sequence-value-not-provided",
-                             u"(no value available)")
-
-    _emptySequenceMessage = _("sequence-value-is-empty",
-                              u"(no values)")
-
-    tag = "ol"
-    itemTag = "li"
-    cssClass = "sequenceWidget"
-    extra = ""
-
-    def __init__(self, context, field, request, subwidget=None):
-        super(SequenceDisplayWidget, self).__init__(context, request)
-        self.subwidget = subwidget
-
-    def __call__(self):
-        # get the data to display:
-        if self._renderedValueSet():
-            data = self._data
-        else:
-            data = self.context.get(self.context.context)
-
-        # deal with special cases:
-        if data == self.context.missing_value:
-            return translate(self._missingValueMessage, self.request)
-        data = list(data)
-        if not data:
-            return translate(self._emptySequenceMessage, self.request)
-
-        parts = []
-        for i, item in enumerate(data):
-            widget = self._getWidget(i)
-            widget.setRenderedValue(item)
-            s = widget()
-            if self.itemTag:
-                s = "<%s>%s</%s>" % (self.itemTag, s, self.itemTag)
-            parts.append(s)
-        contents = "\n".join(parts)
-        if self.tag:
-            contents = "\n%s\n" % contents
-            contents = renderElement(self.tag,
-                                     cssClass=self.cssClass,
-                                     extra=self.extra,
-                                     contents=contents)
-        return contents
-
-    def _getWidget(self, i):
-        field = self.context.value_type
-        if self.subwidget is not None:
-            widget = self.subwidget(field, self.request)
-        else:
-            widget = component.getMultiAdapter(
-                (field, self.request), IDisplayWidget)
-        widget.setPrefix('%s.%d.' % (self.name, i))
-        return widget
+# implementation moved to zope.formlib.sequencewidget
+from zope.formlib.sequencewidget import (
+    SequenceWidget,
+    TupleSequenceWidget,
+    ListSequenceWidget,
+    SequenceDisplayWidget)

Modified: zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/tests/test_itemswidget.py
===================================================================
--- zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/tests/test_itemswidget.py	2009-12-30 19:21:24 UTC (rev 107376)
+++ zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/tests/test_itemswidget.py	2009-12-30 19:46:00 UTC (rev 107377)
@@ -331,14 +331,14 @@
              u'<option value="token3">Three</option>'])
         try:
             # test BBB starting with 3.6.0
-            zope.app.form.browser.itemswidgets.EXPLICIT_EMPTY_SELECTION = False
+            zope.formlib.itemswidgets.EXPLICIT_EMPTY_SELECTION = False
             self.assertEqual(
                 widget.renderItems(widget._toFormValue(widget.context.missing_value)),
                 [u'<option value="token1">One</option>',
                  u'<option value="token2">Two</option>',
                  u'<option value="token3">Three</option>'])
         finally:
-            zope.app.form.browser.itemswidgets.EXPLICIT_EMPTY_SELECTION = True
+            zope.formlib.itemswidgets.EXPLICIT_EMPTY_SELECTION = True
 
 
 class RadioWidgetTest(ItemsEditWidgetBaseTest):

Modified: zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/textwidgets.py
===================================================================
--- zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/textwidgets.py	2009-12-30 19:21:24 UTC (rev 107376)
+++ zope.app.form/branches/faassen-zaf/src/zope/app/form/browser/textwidgets.py	2009-12-30 19:46:00 UTC (rev 107377)
@@ -15,671 +15,28 @@
 
 $Id$
 """
-__docformat__ = 'restructuredtext'
-
-import decimal
-from xml.sax import saxutils
-from zope.interface import implements
-from zope.datetime import parseDatetimetz
-from zope.datetime import DateTimeError
-from zope.i18n.format import DateTimeParseError
-
-from zope.formlib.interfaces import IInputWidget, ConversionError
-from zope.app.form.browser.i18n import _
-from zope.app.form.browser.interfaces import ITextBrowserWidget
-from zope.formlib.widget import SimpleInputWidget, renderElement
-from zope.formlib.widget import DisplayWidget
-
-
-def escape(str):
-    if str is not None:
-        str = saxutils.escape(str)
-    return str
-
-class TextWidget(SimpleInputWidget):
-    """Text widget.
-
-    Single-line text (unicode) input
-
-    >>> from zope.publisher.browser import TestRequest
-    >>> from zope.schema import TextLine
-    >>> field = TextLine(__name__='foo', title=u'on')
-    >>> request = TestRequest(form={'field.foo': u'Bob'})
-    >>> widget = TextWidget(field, request)
-    >>> widget.hasInput()
-    True
-    >>> widget.getInputValue()
-    u'Bob'
-
-    >>> def normalize(s):
-    ...   return '\\n  '.join(filter(None, s.split(' ')))
-
-    >>> print normalize( widget() )
-    <input
-      class="textType"
-      id="field.foo"
-      name="field.foo"
-      size="20"
-      type="text"
-      value="Bob"
-      />
-
-    >>> print normalize( widget.hidden() )
-    <input
-      class="hiddenType"
-      id="field.foo"
-      name="field.foo"
-      type="hidden"
-      value="Bob"
-      />
-
-    Calling `setRenderedValue` will change what gets output:
-
-    >>> widget.setRenderedValue("Barry")
-    >>> print normalize( widget() )
-    <input
-      class="textType"
-      id="field.foo"
-      name="field.foo"
-      size="20"
-      type="text"
-      value="Barry"
-      />
-
-    Check that HTML is correctly encoded and decoded:
-
-    >>> request = TestRequest(
-    ...     form={'field.foo': u'<h1>&copy;</h1>'})
-    >>> widget = TextWidget(field, request)
-    >>> widget.getInputValue()
-    u'<h1>&copy;</h1>'
-
-    >>> print normalize( widget() )
-    <input
-      class="textType"
-      id="field.foo"
-      name="field.foo"
-      size="20"
-      type="text"
-      value="&lt;h1&gt;&amp;copy;&lt;/h1&gt;"
-      />
-    """
-
-    implements(ITextBrowserWidget)
-
-    default = ''
-    displayWidth = 20
-    displayMaxWidth = ""
-    extra = ''
-    style = ''
-    convert_missing_value = True
-
-    def __init__(self, *args):
-        super(TextWidget, self).__init__(*args)
-
-    def __call__(self):
-        value = self._getFormValue()
-        if value is None or value == self.context.missing_value:
-            value = ''
-
-        kwargs = {'type': self.type,
-                  'name': self.name,
-                  'id': self.name,
-                  'value': value,
-                  'cssClass': self.cssClass,
-                  'style': self.style,
-                  'size': self.displayWidth,
-                  'extra': self.extra}
-        if self.displayMaxWidth:
-            kwargs['maxlength'] = self.displayMaxWidth # TODO This is untested.
-
-        return renderElement(self.tag, **kwargs)
-
-    def _toFieldValue(self, input):
-        if self.convert_missing_value and input == self._missing:
-            value = self.context.missing_value
-        else:
-            # We convert everything to unicode. This might seem a bit crude,
-            # but anything contained in a TextWidget should be representable
-            # as a string. Note that you always have the choice of overriding
-            # the method.
-            try:
-                value = unicode(input)
-            except ValueError, v:
-                raise ConversionError(_("Invalid text data"), v)
-        return value
-
-
-class Bytes(SimpleInputWidget):
-
-    def _toFieldValue(self, input):
-        value = super(Bytes, self)._toFieldValue(input)
-        if type(value) is unicode:
-            try:
-                value = value.encode('ascii')
-            except UnicodeError, v:
-                raise ConversionError(_("Invalid textual data"), v)
-        return value
-
-class BytesWidget(Bytes, TextWidget):
-    """Bytes widget.
-
-    Single-line data (string) input
-
-    >>> from zope.publisher.browser import TestRequest
-    >>> from zope.schema import BytesLine
-    >>> field = BytesLine(__name__='foo', title=u'on')
-    >>> request = TestRequest(form={'field.foo': u'Bob'})
-    >>> widget = BytesWidget(field, request)
-    >>> widget.hasInput()
-    True
-    >>> widget.getInputValue()
-    'Bob'
-    """
-
-class BytesDisplayWidget(DisplayWidget):
-    """Bytes display widget"""
-
-    def __call__(self):
-        if self._renderedValueSet():
-            content = self._data
-        else:
-            content = self.context.default
-        return renderElement("pre", contents=escape(content))
-
-class ASCII(Bytes):
-    """ASCII"""
-
-
-class ASCIIWidget(BytesWidget):
-    """ASCII widget.
-
-    Single-line data (string) input
-    """
-
-class ASCIIDisplayWidget(BytesDisplayWidget):
-    """ASCII display widget"""
-
-class URIDisplayWidget(DisplayWidget):
-    """URI display widget.
-
-    :ivar linkTarget:
-      The value of the ``target`` attribute for the generated hyperlink.
-      If this is not set, no ``target`` attribute is generated.
-
-    """
-
-    linkTarget = None
-
-    def __call__(self):
-        if self._renderedValueSet():
-            content = self._data
-        else:
-            content = self.context.default
-        if not content:
-            # If there is no content it is not useful to render an anchor.
-            return ''
-        content = escape(content)
-        kw = dict(contents=content, href=content)
-        if self.linkTarget:
-            kw["target"] = self.linkTarget
-        return renderElement("a", **kw)
-
-
-class TextAreaWidget(SimpleInputWidget):
-    """TextArea widget.
-
-    Multi-line text (unicode) input.
-
-    >>> from zope.publisher.browser import TestRequest
-    >>> from zope.schema import Text
-    >>> field = Text(__name__='foo', title=u'on')
-    >>> request = TestRequest(form={'field.foo': u'Hello\\r\\nworld!'})
-    >>> widget = TextAreaWidget(field, request)
-    >>> widget.hasInput()
-    True
-    >>> widget.getInputValue()
-    u'Hello\\nworld!'
-
-    >>> def normalize(s):
-    ...   return '\\n  '.join(filter(None, s.split(' ')))
-
-    >>> print normalize( widget() )
-    <textarea
-      cols="60"
-      id="field.foo"
-      name="field.foo"
-      rows="15"
-      >Hello\r
-    world!</textarea>
-
-    >>> print normalize( widget.hidden() )
-    <input
-      class="hiddenType"
-      id="field.foo"
-      name="field.foo"
-      type="hidden"
-      value="Hello&#13;&#10;world!"
-      />
-
-    Calling `setRenderedValue` will change what gets output:
-
-    >>> widget.setRenderedValue("Hey\\ndude!")
-    >>> print normalize( widget() )
-    <textarea
-      cols="60"
-      id="field.foo"
-      name="field.foo"
-      rows="15"
-      >Hey\r
-    dude!</textarea>
-
-    Check that HTML is correctly encoded and decoded:
-
-    >>> request = TestRequest(
-    ...     form={'field.foo': u'<h1>&copy;</h1>'})
-    >>> widget = TextAreaWidget(field, request)
-    >>> widget.getInputValue()
-    u'<h1>&copy;</h1>'
-
-    >>> print normalize( widget() )
-    <textarea
-      cols="60"
-      id="field.foo"
-      name="field.foo"
-      rows="15"
-      >&lt;h1&gt;&amp;copy;&lt;/h1&gt;</textarea>
-
-    There was a but which caused the content of <textarea> tags not to be
-    rendered correctly when there was a conversion error. Make sure the quoting
-    works correctly::
-
-    >>> from zope.schema import Text
-    >>> field = Text(__name__='description', title=u'Description')
-
-    >>> from zope.formlib.interfaces import ConversionError
-    >>> class TestTextAreaWidget(TextAreaWidget):
-    ...     def _toFieldValue(self, input):
-    ...         if 'foo' in input:
-    ...             raise ConversionError("I don't like foo.")
-    ...         return input
-    ...
-
-    >>> request = TestRequest(form={'field.description': u'<p>bar</p>'})
-    >>> widget = TestTextAreaWidget(field, request)
-    >>> widget.getInputValue()
-    u'<p>bar</p>'
-    >>> print normalize( widget() )
-    <textarea
-      cols="60"
-      id="field.description"
-      name="field.description"
-      rows="15"
-      >&lt;p&gt;bar&lt;/p&gt;</textarea>
-
-    >>> request = TestRequest(form={'field.description': u'<p>foo</p>'})
-    >>> widget = TestTextAreaWidget(field, request)
-    >>> try:
-    ...     widget.getInputValue()
-    ... except ConversionError, error:
-    ...     print error.doc()
-    I don't like foo.
-    >>> print normalize( widget() )
-    <textarea
-      cols="60"
-      id="field.description"
-      name="field.description"
-      rows="15"
-      >&lt;p&gt;foo&lt;/p&gt;</textarea>
-    """
-
-    default = ""
-    width = 60
-    height = 15
-    extra = ""
-    style = ''
-
-    def _toFieldValue(self, value):
-        value = super(TextAreaWidget, self)._toFieldValue(value)
-        if value:
-            try:
-                value = unicode(value)
-            except ValueError, v:
-                raise ConversionError(_("Invalid unicode data"), v)
-            else:
-                value = value.replace("\r\n", "\n")
-        return value
-
-    def _toFormValue(self, value):
-        value = super(TextAreaWidget, self)._toFormValue(value)
-        if value:
-            value = value.replace("\n", "\r\n")
-        else:
-            value = u''
-
-        return value
-
-    def __call__(self):
-        return renderElement("textarea",
-                             name=self.name,
-                             id=self.name,
-                             cssClass=self.cssClass,
-                             rows=self.height,
-                             cols=self.width,
-                             style=self.style,
-                             contents=escape(self._getFormValue()),
-                             extra=self.extra)
-
-class BytesAreaWidget(Bytes, TextAreaWidget):
-    """BytesArea widget.
-
-    Multi-line string input.
-
-    >>> from zope.publisher.browser import TestRequest
-    >>> from zope.schema import Bytes
-    >>> field = Bytes(__name__='foo', title=u'on')
-    >>> request = TestRequest(form={'field.foo': u'Hello\\r\\nworld!'})
-    >>> widget = BytesAreaWidget(field, request)
-    >>> widget.hasInput()
-    True
-    >>> widget.getInputValue()
-    'Hello\\nworld!'
-    """
-
-class ASCIIAreaWidget(ASCII, TextAreaWidget):
-    """ASCIIArea widget.
-
-    Multi-line string input.
-
-    >>> from zope.publisher.browser import TestRequest
-    >>> from zope.schema import ASCII
-    >>> field = ASCII(__name__='foo', title=u'on')
-    >>> request = TestRequest(form={'field.foo': u'Hello\\r\\nworld!'})
-    >>> widget = ASCIIAreaWidget(field, request)
-    >>> widget.hasInput()
-    True
-    >>> widget.getInputValue()
-    'Hello\\nworld!'
-    """
-
-class PasswordWidget(TextWidget):
-    """Password Widget"""
-
-    type = 'password'
-
-    def __call__(self):
-        displayMaxWidth = self.displayMaxWidth or 0
-        if displayMaxWidth > 0:
-            return renderElement(self.tag,
-                                 type=self.type,
-                                 name=self.name,
-                                 id=self.name,
-                                 value='',
-                                 cssClass=self.cssClass,
-                                 style=self.style,
-                                 size=self.displayWidth,
-                                 maxlength=displayMaxWidth,
-                                 extra=self.extra)
-        else:
-            return renderElement(self.tag,
-                                 type=self.type,
-                                 name=self.name,
-                                 id=self.name,
-                                 value='',
-                                 cssClass=self.cssClass,
-                                 style=self.style,
-                                 size=self.displayWidth,
-                                 extra=self.extra)
-
-    def _toFieldValue(self, input):
-        try:
-            existing = self.context.get(self.context.context)
-        except AttributeError:
-            existing = False
-        if (not input) and existing:
-            return self.context.UNCHANGED_PASSWORD
-        return super(PasswordWidget, self)._toFieldValue(input)
-
-    def hidden(self):
-        raise NotImplementedError(
-            'Cannot get a hidden tag for a password field')
-
-
-class FileWidget(TextWidget):
-    """File Widget"""
-
-    type = 'file'
-
-    def __call__(self):
-        displayMaxWidth = self.displayMaxWidth or 0
-        hidden = renderElement(self.tag,
-                               type='hidden',
-                               name=self.name+".used",
-                               id=self.name+".used",
-                               value="")
-        if displayMaxWidth > 0:
-            elem = renderElement(self.tag,
-                                 type=self.type,
-                                 name=self.name,
-                                 id=self.name,
-                                 cssClass=self.cssClass,
-                                 size=self.displayWidth,
-                                 maxlength=displayMaxWidth,
-                                 extra=self.extra)
-        else:
-            elem = renderElement(self.tag,
-                                 type=self.type,
-                                 name=self.name,
-                                 id=self.name,
-                                 cssClass=self.cssClass,
-                                 size=self.displayWidth,
-                                 extra=self.extra)
-        return "%s %s" % (hidden, elem)
-
-    def _toFieldValue(self, input):
-        if input is None or input == '':
-            return self.context.missing_value
-        try:
-            seek = input.seek
-            read = input.read
-        except AttributeError, e:
-            raise ConversionError(_('Form input is not a file object'), e)
-        else:
-            seek(0)
-            data = read()
-            if data or getattr(input, 'filename', ''):
-                return data
-            else:
-                return self.context.missing_value
-
-    def hasInput(self):
-        return ((self.name+".used" in self.request.form)
-                or
-                (self.name in self.request.form)
-                )
-
-class IntWidget(TextWidget):
-    """Integer number widget.
-
-    Let's make sure that zeroes are rendered properly:
-
-    >>> from zope.schema import Int
-    >>> field = Int(__name__='foo', title=u'on')
-    >>> widget = IntWidget(field, None)
-    >>> widget.setRenderedValue(0)
-
-    >>> 'value="0"' in widget()
-    True
-
-    """
-
-    displayWidth = 10
-
-    def _toFieldValue(self, input):
-        if input == self._missing:
-            return self.context.missing_value
-        else:
-            try:
-                return int(input)
-            except ValueError, v:
-                raise ConversionError(_("Invalid integer data"), v)
-
-
-class FloatWidget(TextWidget):
-    implements(IInputWidget)
-    displayWidth = 10
-
-    def _toFieldValue(self, input):
-        if input == self._missing:
-            return self.context.missing_value
-        else:
-            try:
-                return float(input)
-            except ValueError, v:
-                raise ConversionError(_("Invalid floating point data"), v)
-
-class DecimalWidget(TextWidget):
-    implements(IInputWidget)
-    displayWidth = 10
-
-    def _toFieldValue(self, input):
-        if input == self._missing:
-            return self.context.missing_value
-        else:
-            try:
-                return decimal.Decimal(input)
-            except decimal.InvalidOperation, v:
-                raise ConversionError(_("Invalid decimal data"), v)
-
-    def _toFormValue(self, value):
-        if value == self.context.missing_value:
-            value = self._missing
-        else:
-            return unicode(value)
-
-
-class DatetimeWidget(TextWidget):
-    """Datetime entry widget."""
-
-    displayWidth = 20
-
-    def _toFieldValue(self, input):
-        if input == self._missing:
-            return self.context.missing_value
-        else:
-            try:
-                # TODO: Currently datetimes return in local (server)
-                # time zone if no time zone information was given.
-                # Maybe offset-naive datetimes should be returned in
-                # this case? (DV)
-                return parseDatetimetz(input)
-            except (DateTimeError, ValueError, IndexError), v:
-                raise ConversionError(_("Invalid datetime data"), v)
-
-class DateWidget(DatetimeWidget):
-    """Date entry widget.
-    """
-
-    def _toFieldValue(self, input):
-        v = super(DateWidget, self)._toFieldValue(input)
-        if v != self.context.missing_value:
-            v = v.date()
-        return v
-
-class DateI18nWidget(TextWidget):
-    """I18n date entry widget.
-
-    The `displayStyle` attribute may be set to control the formatting of the
-    value.
-
-    `displayStyle` must be one of 'full', 'long', 'medium', 'short',
-    or None ('' is accepted an an alternative to None to support
-    provision of a value from ZCML).
-    """
-
-    _category = "date"
-
-    displayWidth = 20
-
-    displayStyle = None
-
-    def _toFieldValue(self, input):
-        if input == self._missing:
-            return self.context.missing_value
-        else:
-            try:
-                formatter = self.request.locale.dates.getFormatter(
-                    self._category, (self.displayStyle or None))
-                return formatter.parse(input)
-            except (DateTimeParseError, ValueError), v:
-                raise ConversionError(_("Invalid datetime data"),
-                    "%s (%r)" % (v, input))
-
-    def _toFormValue(self, value):
-        value = super(DateI18nWidget, self)._toFormValue(value)
-        if value:
-            formatter = self.request.locale.dates.getFormatter(
-                self._category, (self.displayStyle or None))
-            value = formatter.format(value)
-        return value
-
-class DatetimeI18nWidget(DateI18nWidget):
-    """I18n datetime entry widget.
-
-    The `displayStyle` attribute may be set to control the formatting of the
-    value.
-
-    `displayStyle` must be one of 'full', 'long', 'medium', 'short',
-    or None ('' is accepted an an alternative to None to support
-    provision of a value from ZCML).
-
-    NOTE: If you need timezone information you need to set `displayStyle`
-    to either 'long' or 'full' since other display styles just ignore it.
-    """
-
-    _category = "dateTime"
-
-class DateDisplayWidget(DisplayWidget):
-    """Date display widget.
-
-    The `cssClass` and `displayStyle` attributes may be set to control
-    the formatting of the value.
-
-    `displayStyle` must be one of 'full', 'long', 'medium', 'short',
-    or None ('' is accepted an an alternative to None to support
-    provision of a value from ZCML).
-    """
-
-    cssClass = "date"
-    displayStyle = None
-
-    _category = "date"
-
-    def __call__(self):
-        if self._renderedValueSet():
-            content = self._data
-        else:
-            content = self.context.default
-        if content == self.context.missing_value:
-            return ""
-        formatter = self.request.locale.dates.getFormatter(
-            self._category, (self.displayStyle or None))
-        content = formatter.format(content)
-        return renderElement("span", contents=escape(content),
-                             cssClass=self.cssClass)
-
-
-class DatetimeDisplayWidget(DateDisplayWidget):
-    """Datetime display widget.
-
-    The `cssClass` and `displayStyle` attributes may be set to control
-    the formatting of the value.
-
-    `displayStyle` must be one of 'full', 'long', 'medium', 'short',
-    or None ('' is accepted an an alternative to None to support
-    provision of a value from ZCML).
-    """
-
-    cssClass = "dateTime"
-
-    _category = "dateTime"
+# implementation moved to zope.formlib.textwidgets
+from zope.formlib.textwidgets import (
+    escape,
+    TextWidget,
+    Bytes,
+    BytesWidget,
+    BytesDisplayWidget,
+    ASCII,
+    ASCIIWidget,
+    ASCIIDisplayWidget,
+    URIDisplayWidget,
+    TextAreaWidget,
+    BytesAreaWidget,
+    ASCIIAreaWidget,
+    PasswordWidget,
+    FileWidget,
+    IntWidget,
+    FloatWidget,
+    DecimalWidget,
+    DatetimeWidget,
+    DateWidget,
+    DateI18nWidget,
+    DatetimeI18nWidget,
+    DateDisplayWidget,
+    DatetimeDisplayWidget)



More information about the checkins mailing list