source: main/waeup.sirp/trunk/src/waeup/sirp/widgets/phonewidget.py @ 7344

Last change on this file since 7344 was 7342, checked in by uli, 13 years ago

Add tests for the new phone widget.

File size: 6.6 KB
Line 
1##
2## phonewidget.py
3## $Id$
4##
5"""A phone number widget.
6
7This widget is an input widget (not made for display forms but for
8edit and add forms).
9
10It can be used for :class:`zope.schema.TextLine` fields but has to be
11requested by the form manually (otherwise the regular TextLine widget
12will be used for rendering).
13
14The code was mainly taken from usphone implementation in z3c.widget
15(which was designed for outdated zope.app.form (instead of
16zope.formlib or newer form libs). Therefore some modifications were
17neccessary and it might look a bit overloaded.
18"""
19import re
20from waeup.sirp import MessageFactory as _
21from zope import schema
22from zope.browserpage import ViewPageTemplateFile
23from zope.component import getMultiAdapter
24from zope.formlib import form
25from zope.formlib.interfaces import IBrowserWidget, IWidgetInputErrorView
26from zope.formlib.interfaces import IInputWidget, WidgetInputError
27from zope.formlib.widget import SimpleInputWidget
28from zope.interface import Interface, implements
29
30class IPhoneData(Interface):
31    """A schema used to generate a Phone widget."""
32
33    country = schema.TextLine(
34        title=_('Country Code'),
35        description=_('The country code of the phone number.'),
36        min_length=1,
37        constraint=re.compile(r'^[0-9]+$').search,
38        required=True)
39
40    area = schema.TextLine(
41        title=_('Area Code'),
42        description=_('The area code of the phone number.'),
43        min_length=1,
44        constraint=re.compile(r'^[0-9]+$').search,
45        required=True)
46
47    extension = schema.TextLine(
48        title=_('Direct Line'),
49        description=_('The direct line of the phone number.'),
50        min_length=3,
51        constraint=re.compile(r'^[0-9]{3,}$').search,
52        required=True)
53
54
55class PhoneWidgetData(object):
56    """Phone number data"""
57    implements(IPhoneData)
58
59    country = None
60    area = None
61    extension = None
62
63    def __init__(self, context, number=None):
64        self.context = context
65        if number is not None:
66            # XXX: We have to provide something more tolerant
67            self.country, self.area, self.extension = number.split('-')
68            return
69            try:
70                self.country, self.area, self.extension = number.split('-')
71            except ValueError:
72                replacement = '1-1-%s' % (number.replace('-', ''),)
73                self.country, self.area, self.extension = replacement.split(
74                    '-', 2)
75
76    @property
77    def number(self):
78        return u'-'.join((self.country, self.area, self.extension))
79
80
81class PhoneWidget(SimpleInputWidget):
82    """Phone Number Widget"""
83    implements(IBrowserWidget, IInputWidget)
84
85    template = ViewPageTemplateFile('phonewidget.pt')
86    _prefix = 'field.'
87    _error = None
88    widgets = {}
89
90    # See zope.formlib.interfaces.IWidget
91    name = None
92    visible = True
93
94    def __init__(self, field, request):
95        super(PhoneWidget, self).__init__(field, request)
96        value = field.query(field.context)
97        self._generateSubWidgets()
98        return
99
100    def _generateSubWidgets(self):
101        """Create the three subwidgets.
102        """
103        value = self.context.query(self.context.context)
104        adapters = {}
105        adapters[IPhoneData] = PhoneWidgetData(self, value)
106        self.widgets = form.setUpEditWidgets(
107            form.FormFields(IPhoneData),
108            self.name, value, self.request, adapters=adapters)
109        self.widgets['country'].displayWidth = 3
110        self.widgets['area'].displayWidth = 5
111        self.widgets['extension'].displayWidth = 10
112        return
113
114    def setRenderedValue(self, value):
115        """See zope.formlib.interfaces.IWidget"""
116        if isinstance(value, unicode):
117            country, area, extension = value.split('-')
118            self.widgets['country'].setRenderedValue(country)
119            self.widgets['area'].setRenderedValue(area)
120            self.widgets['extension'].setRenderedValue(extension)
121
122
123    def setPrefix(self, prefix):
124        """See zope.formlib.interfaces.IWidget"""
125        # Set the prefix locally
126        if not prefix.endswith("."):
127            prefix += '.'
128        self._prefix = prefix
129        self.name = prefix + self.context.__name__
130        # Now distribute it to the sub-widgets
131        self._generateSubWidgets()
132        return
133
134    def getInputValue(self):
135        """See zope.formlib.interfaces.IInputWidget"""
136        self._error = None
137        try:
138            return u'-'.join((
139                self.widgets['country'].getInputValue(),
140                self.widgets['area'].getInputValue(),
141                self.widgets['extension'].getInputValue() ))
142        except ValueError, v:
143            self._error = WidgetInputError(
144                self.context.__name__, self.label, _(v))
145            raise self._error
146        except WidgetInputError, e:
147            self._error = e
148            raise e
149
150    def applyChanges(self, content):
151        """See zope.formlib.interfaces.IInputWidget"""
152        field = self.context
153        new_value = self.getInputValue()
154        old_value = field.query(content, self)
155        # The selection has not changed
156        if new_value == old_value:
157            return False
158        field.set(content, new_value)
159        return True
160
161    def hasInput(self):
162        """See zope.formlib.interfaces.IInputWidget"""
163        return (self.widgets['country'].hasInput() and
164                (self.widgets['area'].hasInput() and
165                 self.widgets['extension'].hasInput()))
166
167
168    def hasValidInput(self):
169        """See zope.formlib.interfaces.IInputWidget"""
170        return (self.widgets['country'].hasValidInput() and
171            self.widgets['area'].hasValidInput() and
172            self.widgets['extension'].hasValidInput())
173
174
175    def hidden(self):
176        """See zope.formlib.interfaces.IBrowserWidget"""
177        output = []
178        output.append(self.widgets['country'].hidden())
179        output.append(self.widgets['area'].hidden())
180        output.append(self.widgets['extension'].hidden())
181        return '\n'.join(output)
182
183
184    def error(self):
185        """See zope.formlib.interfaces.IBrowserWidget"""
186        if self._error:
187            return getMultiAdapter(
188                (self._error, self.request),
189                IWidgetInputErrorView).snippet()
190        country_error = self.widgets['country'].error()
191        if country_error:
192            return country_error
193        area_error = self.widgets['area'].error()
194        if area_error:
195            return area_error
196        extension_error = self.widgets['extension'].error()
197        if extension_error:
198            return extension_error
199        return ""
200
201    def __call__(self):
202        """See zope.formlib.interfaces.IBrowserWidget"""
203        return self.template()
Note: See TracBrowser for help on using the repository browser.