Index: /main/waeup.sirp/trunk/src/waeup/sirp/widgets/phonewidget.py
===================================================================
--- /main/waeup.sirp/trunk/src/waeup/sirp/widgets/phonewidget.py	(revision 7342)
+++ /main/waeup.sirp/trunk/src/waeup/sirp/widgets/phonewidget.py	(revision 7342)
@@ -0,0 +1,203 @@
+##
+## phonewidget.py
+## $Id$
+##
+"""A phone number widget.
+
+This widget is an input widget (not made for display forms but for
+edit and add forms).
+
+It can be used for :class:`zope.schema.TextLine` fields but has to be
+requested by the form manually (otherwise the regular TextLine widget
+will be used for rendering).
+
+The code was mainly taken from usphone implementation in z3c.widget
+(which was designed for outdated zope.app.form (instead of
+zope.formlib or newer form libs). Therefore some modifications were
+neccessary and it might look a bit overloaded.
+"""
+import re
+from waeup.sirp import MessageFactory as _
+from zope import schema
+from zope.browserpage import ViewPageTemplateFile
+from zope.component import getMultiAdapter
+from zope.formlib import form
+from zope.formlib.interfaces import IBrowserWidget, IWidgetInputErrorView
+from zope.formlib.interfaces import IInputWidget, WidgetInputError
+from zope.formlib.widget import SimpleInputWidget
+from zope.interface import Interface, implements
+
+class IPhoneData(Interface):
+    """A schema used to generate a Phone widget."""
+
+    country = schema.TextLine(
+        title=_('Country Code'),
+        description=_('The country code of the phone number.'),
+        min_length=1,
+        constraint=re.compile(r'^[0-9]+$').search,
+        required=True)
+
+    area = schema.TextLine(
+        title=_('Area Code'),
+        description=_('The area code of the phone number.'),
+        min_length=1,
+        constraint=re.compile(r'^[0-9]+$').search,
+        required=True)
+
+    extension = schema.TextLine(
+        title=_('Direct Line'),
+        description=_('The direct line of the phone number.'),
+        min_length=3,
+        constraint=re.compile(r'^[0-9]{3,}$').search,
+        required=True)
+
+
+class PhoneWidgetData(object):
+    """Phone number data"""
+    implements(IPhoneData)
+
+    country = None
+    area = None
+    extension = None
+
+    def __init__(self, context, number=None):
+        self.context = context
+        if number is not None:
+            # XXX: We have to provide something more tolerant
+            self.country, self.area, self.extension = number.split('-')
+            return
+            try:
+                self.country, self.area, self.extension = number.split('-')
+            except ValueError:
+                replacement = '1-1-%s' % (number.replace('-', ''),)
+                self.country, self.area, self.extension = replacement.split(
+                    '-', 2)
+
+    @property
+    def number(self):
+        return u'-'.join((self.country, self.area, self.extension))
+
+
+class PhoneWidget(SimpleInputWidget):
+    """Phone Number Widget"""
+    implements(IBrowserWidget, IInputWidget)
+
+    template = ViewPageTemplateFile('phonewidget.pt')
+    _prefix = 'field.'
+    _error = None
+    widgets = {}
+
+    # See zope.formlib.interfaces.IWidget
+    name = None
+    visible = True
+
+    def __init__(self, field, request):
+        super(PhoneWidget, self).__init__(field, request)
+        value = field.query(field.context)
+        self._generateSubWidgets()
+        return
+
+    def _generateSubWidgets(self):
+        """Create the three subwidgets.
+        """
+        value = self.context.query(self.context.context)
+        adapters = {}
+        adapters[IPhoneData] = PhoneWidgetData(self, value)
+        self.widgets = form.setUpEditWidgets(
+            form.FormFields(IPhoneData),
+            self.name, value, self.request, adapters=adapters)
+        self.widgets['country'].displayWidth = 3
+        self.widgets['area'].displayWidth = 5
+        self.widgets['extension'].displayWidth = 10
+        return
+
+    def setRenderedValue(self, value):
+        """See zope.formlib.interfaces.IWidget"""
+        if isinstance(value, unicode):
+            country, area, extension = value.split('-')
+            self.widgets['country'].setRenderedValue(country)
+            self.widgets['area'].setRenderedValue(area)
+            self.widgets['extension'].setRenderedValue(extension)
+
+
+    def setPrefix(self, prefix):
+        """See zope.formlib.interfaces.IWidget"""
+        # Set the prefix locally
+        if not prefix.endswith("."):
+            prefix += '.'
+        self._prefix = prefix
+        self.name = prefix + self.context.__name__
+        # Now distribute it to the sub-widgets
+        self._generateSubWidgets()
+        return
+
+    def getInputValue(self):
+        """See zope.formlib.interfaces.IInputWidget"""
+        self._error = None
+        try:
+            return u'-'.join((
+                self.widgets['country'].getInputValue(),
+                self.widgets['area'].getInputValue(),
+                self.widgets['extension'].getInputValue() ))
+        except ValueError, v:
+            self._error = WidgetInputError(
+                self.context.__name__, self.label, _(v))
+            raise self._error
+        except WidgetInputError, e:
+            self._error = e
+            raise e
+
+    def applyChanges(self, content):
+        """See zope.formlib.interfaces.IInputWidget"""
+        field = self.context
+        new_value = self.getInputValue()
+        old_value = field.query(content, self)
+        # The selection has not changed
+        if new_value == old_value:
+            return False
+        field.set(content, new_value)
+        return True
+
+    def hasInput(self):
+        """See zope.formlib.interfaces.IInputWidget"""
+        return (self.widgets['country'].hasInput() and
+                (self.widgets['area'].hasInput() and
+                 self.widgets['extension'].hasInput()))
+
+
+    def hasValidInput(self):
+        """See zope.formlib.interfaces.IInputWidget"""
+        return (self.widgets['country'].hasValidInput() and
+            self.widgets['area'].hasValidInput() and
+            self.widgets['extension'].hasValidInput())
+
+
+    def hidden(self):
+        """See zope.formlib.interfaces.IBrowserWidget"""
+        output = []
+        output.append(self.widgets['country'].hidden())
+        output.append(self.widgets['area'].hidden())
+        output.append(self.widgets['extension'].hidden())
+        return '\n'.join(output)
+
+
+    def error(self):
+        """See zope.formlib.interfaces.IBrowserWidget"""
+        if self._error:
+            return getMultiAdapter(
+                (self._error, self.request),
+                IWidgetInputErrorView).snippet()
+        country_error = self.widgets['country'].error()
+        if country_error:
+            return country_error
+        area_error = self.widgets['area'].error()
+        if area_error:
+            return area_error
+        extension_error = self.widgets['extension'].error()
+        if extension_error:
+            return extension_error
+        return ""
+
+    def __call__(self):
+        """See zope.formlib.interfaces.IBrowserWidget"""
+        return self.template()
