-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce marker interfaces for marking widget classes according
to their factory signature (arguments to __init__).
- Loading branch information
0 parents
commit 685bbbb
Showing
2 changed files
with
336 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
############################################################################## | ||
# | ||
# Copyright (c) 2004 Zope Corporation and Contributors. | ||
# All Rights Reserved. | ||
# | ||
# This software is subject to the provisions of the Zope Public License, | ||
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. | ||
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED | ||
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS | ||
# FOR A PARTICULAR PURPOSE. | ||
# | ||
############################################################################## | ||
"""Browser widgets | ||
$Id$ | ||
""" | ||
__docformat__ = 'restructuredtext' | ||
|
||
from zope.app.form.browser.widget import BrowserWidget, DisplayWidget | ||
from zope.app.form.browser.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 | ||
from zope.app.form.browser.textwidgets import IntWidget, FloatWidget | ||
from zope.app.form.browser.textwidgets import DatetimeWidget, DateWidget | ||
from zope.app.form.browser.textwidgets import DatetimeDisplayWidget | ||
from zope.app.form.browser.textwidgets import DateDisplayWidget | ||
from zope.app.form.browser.textwidgets import BytesDisplayWidget | ||
|
||
# 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 | ||
|
||
# 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 | ||
|
||
# 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 | ||
|
||
# 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 | ||
|
||
# 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 MultiCheckBoxWidget | ||
from zope.app.form.browser.itemswidgets 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.app.form.browser.objectwidget import ObjectWidget | ||
|
||
# mark items and sequence widgets with the correct factory interfaces | ||
from zope.interface import directlyProvides | ||
from zope.app.form.interfaces import IVocabularyWidgetFactory | ||
from zope.app.form.interfaces import ISequenceWidgetFactory | ||
|
||
for widget_class in (ItemDisplayWidget, ItemsMultiDisplayWidget, | ||
SetDisplayWidget, ListDisplayWidget, SelectWidget, | ||
DropdownWidget, RadioWidget, MultiSelectWidget, | ||
MultiSelectSetWidget, MultiCheckBoxWidget, | ||
OrderedMultiSelectWidget): | ||
directlyProvides(widget_class, IVocabularyWidgetFactory) | ||
|
||
for widget_class in (SequenceWidget, TupleSequenceWidget, | ||
ListSequenceWidget, SequenceDisplayWidget): | ||
directlyProvides(widget_class, ISequenceWidgetFactory) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,246 @@ | ||
############################################################################## | ||
# | ||
# Copyright (c) 2002 Zope Corporation and Contributors. | ||
# All Rights Reserved. | ||
# | ||
# This software is subject to the provisions of the Zope Public License, | ||
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. | ||
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED | ||
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS | ||
# FOR A PARTICULAR PURPOSE. | ||
# | ||
############################################################################## | ||
"""Validation Exceptions | ||
$Id$ | ||
""" | ||
__docformat__ = 'restructuredtext' | ||
|
||
from zope.schema.interfaces import ValidationError | ||
from zope.component.interfaces import IView, IViewFactory | ||
from zope.interface import Attribute, Interface, implements | ||
from zope.schema import Bool | ||
from zope.app.exception.interfaces import UserError | ||
|
||
class IWidgetInputError(Interface): | ||
"""Placeholder for a snippet View""" | ||
|
||
def doc(): | ||
"""Returns a string that represents the error message.""" | ||
|
||
class WidgetInputError(UserError): | ||
"""One or more user input errors occurred.""" | ||
|
||
implements(IWidgetInputError) | ||
|
||
def __init__(self, field_name, widget_title, errors=None): | ||
"""Initialize Error | ||
`errors` is a ``ValidationError`` or a list of ValidationError objects | ||
""" | ||
UserError.__init__(self, field_name, widget_title, errors) | ||
self.field_name = field_name | ||
self.widget_title = widget_title | ||
self.errors = errors | ||
|
||
def doc(self): | ||
# XXX this duck typing is to get the code working. See | ||
# collector issue 372 | ||
if isinstance(self.errors, basestring): | ||
return self.errors | ||
elif getattr(self.errors, 'doc', None) is not None: | ||
return self.errors.doc() | ||
return '' | ||
|
||
|
||
class MissingInputError(WidgetInputError): | ||
"""Required data was not supplied.""" | ||
|
||
|
||
class ConversionError(Exception): | ||
"""A conversion error occurred.""" | ||
|
||
implements(IWidgetInputError) | ||
|
||
def __init__(self, error_name, original_exception=None): | ||
Exception.__init__(self, error_name, original_exception) | ||
self.error_name = error_name | ||
self.original_exception = original_exception | ||
|
||
def doc(self): | ||
return self.error_name | ||
|
||
InputErrors = WidgetInputError, ValidationError, ConversionError | ||
|
||
|
||
class ErrorContainer(Exception): | ||
"""A base error class for collecting multiple errors.""" | ||
|
||
def append(self, error): | ||
self.args += (error, ) | ||
|
||
def __len__(self): | ||
return len(self.args) | ||
|
||
def __iter__(self): | ||
return iter(self.args) | ||
|
||
def __getitem__(self, i): | ||
return self.args[i] | ||
|
||
def __str__(self): | ||
return "\n".join( | ||
["%s: %s" % (error.__class__.__name__, error) | ||
for error in self.args] | ||
) | ||
|
||
__repr__ = __str__ | ||
|
||
class WidgetsError(ErrorContainer): | ||
"""A collection of errors from widget processing. | ||
widgetValues is a map containing the list of values that were obtained | ||
from the widgets, keyed by field name. | ||
""" | ||
|
||
def __init__(self, errors, widgetsData={}): | ||
ErrorContainer.__init__(self, *errors) | ||
self.widgetsData = widgetsData | ||
|
||
class IWidget(IView): | ||
"""Generically describes the behavior of a widget. | ||
Note that this level must be still presentation independent. | ||
""" | ||
|
||
name = Attribute( | ||
"""The unique widget name | ||
This must be unique within a set of widgets.""") | ||
|
||
label = Attribute( | ||
"""The widget label. | ||
Label may be translated for the request.""") | ||
|
||
hint = Attribute( | ||
"""A hint regarding the use of the widget. | ||
Hints are traditionally rendered using tooltips in GUIs, but may be | ||
rendered differently depending on the UI implementation. | ||
Hint may be translated for the request.""") | ||
|
||
visible = Attribute( | ||
"""A flag indicating whether or not the widget is visible.""") | ||
|
||
def setRenderedValue(value): | ||
"""Set the value to be rendered by the widget. | ||
Calling this method will override any values provided by the user. | ||
For input widgets (`IInputWidget` implementations), calling | ||
this sets the value that will be rendered even if there is | ||
already user input. | ||
""" | ||
|
||
def setPrefix(prefix): | ||
"""Set the name prefix used for the widget | ||
The widget name is used to identify the widget's data within | ||
input data. For example, for HTTP forms, the widget name is | ||
used for the form key. | ||
""" | ||
|
||
class IWidgetFactory(IViewFactory): | ||
"""Create a widget.""" | ||
|
||
class ISequenceWidgetFactory(IWidgetFactory): | ||
"""Create a sequence widget. | ||
A widget factory should provide this interface to indicate that | ||
its call signature is different from other widget factories.""" | ||
|
||
def __call__(context, field, request): | ||
"""Creates a sequence widget with ``field`` being the list element | ||
field type.""" | ||
|
||
class IVocabularyWidgetFactory(IWidgetFactory): | ||
"""Create a vocabulary widget. | ||
A widget factory should provide this interface to indicate that | ||
its call signature is different from other widget factories.""" | ||
|
||
def __call__(field, vocabulary, request): | ||
"""Creates a vocabulary widget.""" | ||
|
||
class IInputWidget(IWidget): | ||
"""A widget for editing a field value.""" | ||
|
||
required = Bool( | ||
title=u"Required", | ||
description=u"""If True, widget should be displayed as requiring input. | ||
By default, this value is the field's 'required' attribute. This | ||
field can be set to False for widgets that always provide input (e.g. | ||
a checkbox) to avoid unnecessary 'required' UI notations. | ||
""") | ||
|
||
def getInputValue(): | ||
"""Return value suitable for the widget's field. | ||
The widget must return a value that can be legally assigned to | ||
its bound field or otherwise raise ``WidgetInputError``. | ||
The return value is not affected by `setRenderedValue()`. | ||
""" | ||
|
||
def applyChanges(content): | ||
"""Validate the user input data and apply it to the content. | ||
Return a boolean indicating whether a change was actually applied. | ||
This raises an error if there is no user input. | ||
""" | ||
|
||
def hasInput(): | ||
"""Returns ``True`` if the widget has input. | ||
Input is used by the widget to calculate an 'input value', which is | ||
a value that can be legally assigned to a field. | ||
Note that the widget may return ``True``, indicating it has input, but | ||
still be unable to return a value from `getInputValue`. Use | ||
`hasValidInput` to determine whether or not `getInputValue` will return | ||
a valid value. | ||
A widget that does not have input should generally not be used | ||
to update its bound field. Values set using | ||
`setRenderedValue()` do not count as user input. | ||
A widget that has been rendered into a form which has been | ||
submitted must report that it has input. If the form | ||
containing the widget has not been submitted, the widget | ||
shall report that it has no input. | ||
""" | ||
|
||
def hasValidInput(): | ||
"""Returns ``True`` is the widget has valid input. | ||
This method is similar to `hasInput` but it also confirms that the | ||
input provided by the user can be converted to a valid field value | ||
based on the field constraints. | ||
""" | ||
|
||
class IDisplayWidget(IWidget): | ||
"""A widget for displaying a field value.""" | ||
|
||
required = Bool( | ||
title=u"Required", | ||
description=u"""If True, widget should be displayed as requiring input. | ||
Display widgets should never be required. | ||
""") |