Index: main/waeup.kofa/trunk/src/waeup/kofa/widgets/phonewidget.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/widgets/phonewidget.py	(revision 7839)
+++ main/waeup.kofa/trunk/src/waeup/kofa/widgets/phonewidget.py	(revision 7840)
@@ -29,4 +29,5 @@
 
 """
+import grok
 import re
 import copy
@@ -76,5 +77,5 @@
     extension = None
 
-    def __init__(self, context, number=None):
+    def __init__(self, context=None, number=None):
         """Set countrycode, areacode, and extension line from number.
         """
@@ -246,2 +247,132 @@
         """See zope.formlib.interfaces.IBrowserWidget"""
         return self.template()
+
+from zope.formlib.objectwidget import ObjectWidget
+from zope.schema import Object
+from waeup.kofa.widgets.objectwidget import KofaObjectWidget, ObjectWidgetView
+from zc.sourcefactory.contextual import BasicContextualSourceFactory
+
+
+
+class KofaPhoneWidgetView(ObjectWidgetView):
+    template = ViewPageTemplateFile('phonewidget2.pt')
+
+class PhoneWidget2(KofaObjectWidget):
+
+    _fake_value = None
+
+    def __init__(self, context, request, **kw):
+        self._fake_context = Object(IPhoneData, __name__=context.__name__)
+        super(PhoneWidget2, self).__init__(
+            self._fake_context, request, PhoneWidgetData, **kw)
+        return
+
+    def _to_fake_value(value):
+        return PhoneWidgetData(None, value.number)
+
+    def _from_fake_value(value):
+        return value.number
+
+    def _getView(self, request):
+        return KofaPhoneWidgetView(self, request)
+
+from zope.formlib.textwidgets import TextWidget, renderElement
+from zope.component import getUtility
+from zope.interface import Invalid
+from zope.formlib.interfaces import WidgetInputError, MissingInputError
+
+class IInternationalPhonePrefixes(Interface):
+    """A dict of international phone number prefixes.
+    """
+
+INT_PHONE_PREFIXES = {
+        'Germany': '49',
+        'Nigeria': '234',
+        'U.S.': '1',
+        }
+
+class PhonePrefixes(grok.GlobalUtility):
+    grok.implements(IInternationalPhonePrefixes)
+
+    _data = INT_PHONE_PREFIXES.items()
+
+    def title_value_list(self):
+        return sorted([('%s (+%s)' % (x,y), y)
+                       for x,y in self._data])
+
+class PhoneWidget2(TextWidget):
+
+    subwidget_names = ('country', 'area', 'ext')
+
+    #_missing = '--'
+
+    def _renderPrefixWidget(self, value):
+        prefixes = getUtility(
+            IInternationalPhonePrefixes).title_value_list()
+        options = []
+        for ptitle, pval in prefixes:
+            selected = ''
+            if value == pval:
+                selected = ' selected="selected" '
+            options.append(
+                '<option value="%s"%s>%s</option>' % (pval, selected, ptitle))
+        options = '\n'.join(options)
+        return '<select id="%s" name="%s" size="1" class="span4">\n%s\n</select>' % (
+            '%s.%s' % (self.name, 'country'),
+            '%s.%s' % (self.name, 'country'),
+            options)
+
+    def __call__(self):
+        value = self._getFormValue()
+        if value is None or value == self.context.missing_value:
+            value = ''
+        if len(value.split('-')) < 2:
+            value = '--' + value
+        subvalues = value.split('-', 2)
+
+        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.
+        fields = []
+        for num, subname in enumerate(self.subwidget_names):
+            if num == 0:
+                select = self._renderPrefixWidget(subvalues[num])
+                fields.append(select)
+                continue
+                print select
+            kwargs.update(name = '%s.%s' % (self.name, subname))
+            kwargs.update(id=kwargs['name'])
+            # kwargs.update(cssClass = '%s %s' % (self.cssClass, 'span1'))
+            kwargs.update(cssClass = '%s %s' % ('', 'span2'))
+            kwargs.update(value = subvalues[num])
+            fields.append(renderElement(self.tag, **kwargs))
+        return '-'.join(fields)
+
+    def _getFormInput(self):
+        """Returns current form input.
+
+        The value returned must be in a format that can be used as the 'input'
+        argument to `_toFieldValue`.
+
+        The default implementation returns the form value that corresponds to
+        the widget's name. Subclasses may override this method if their form
+        input consists of more than one form element or use an alternative
+        naming convention.
+        """
+        result = '-'.join(
+            [self.request.get('%s.%s' % (self.name, name))
+             for name in self.subwidget_names])
+        return result
+
+    def hasInput(self):
+        for name in self.subwidget_names:
+            if '%s.%s' % (self.name, name) not in self.request.form:
+                return False
+        return True
Index: main/waeup.kofa/trunk/src/waeup/kofa/widgets/tests/test_phonewidget.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/widgets/tests/test_phonewidget.py	(revision 7839)
+++ main/waeup.kofa/trunk/src/waeup/kofa/widgets/tests/test_phonewidget.py	(revision 7840)
@@ -26,5 +26,6 @@
 # XXX: could we possibly get rid of zope.app.testing?
 from zope.app.testing.setup import placefulSetUp, placefulTearDown
-from zope.component import provideAdapter
+from zope.component import provideAdapter, getGlobalSiteManager
+from zope.formlib import form
 from zope.formlib.exception import WidgetInputErrorView
 from zope.formlib.interfaces import (
@@ -48,5 +49,6 @@
         title = u'Phone',
         description = u'Phone number (not required)',
-        required = False,)
+        required = False,
+        missing_value = u'')
 
     baz = schema.TextLine(
@@ -54,8 +56,13 @@
         description = u'Required phone with a default',
         required = True,
-        default=u'234--')
+        #default=u'234--'
+        )
 
 class SampleContent:
     implements(ISampleContent)
+
+    foo = None
+    bar = 'bar'
+    baz = None
 
 class PhoneWidgetTests(unittest.TestCase):
@@ -497,2 +504,107 @@
              u' value=""  />\n'))
         return
+
+import zope.formlib
+from zope import schema
+from zope.formlib.tests.test_functional_objectwidget import (
+    Test, PlacelessSetup, VerifyResults, traversingSetUp, xmlconfig,
+    PageTemplate, os, DefaultTraversable
+    )
+from zope.formlib.tests.test_functional_textwidget import(
+    FunctionalWidgetTestCase, patternExists)
+from zope.formlib.widgets import TextWidget
+from zope.component import adapts
+from zope.interface import implements
+from zope.traversing.interfaces import ITraversable
+from waeup.kofa.widgets.phonewidget import PhoneWidget2, PhonePrefixes
+
+class SampleForm(form.EditForm):
+    form_fields = form.fields(ISampleContent)
+    form_fields['foo'].custom_widget = PhoneWidget2
+    form_fields['bar'].custom_widget = PhoneWidget2
+    form_fields['baz'].custom_widget = PhoneWidget2
+
+class PhoneWidget2Tests(FunctionalWidgetTestCase):
+
+    widgets = [
+        (ITextLine, TextWidget),
+        ]
+
+    def setUp(self):
+        super(PhoneWidget2Tests, self).setUp()
+        self.gsm = getGlobalSiteManager()
+        self.reg_prefixes = PhonePrefixes()
+        self.gsm.registerUtility(self.reg_prefixes)
+        return
+
+    def tearDown(self):
+        self.gsm.unregisterUtility(self.reg_prefixes)
+        return
+
+    def test_display_editform(self):
+        content = SampleContent()
+        request = TestRequest()
+        html = SampleForm(content, request)()
+        # foo.country, foo.area and foo.ext exist
+        self.assert_(patternExists(
+            '<select .* name="form.foo.country".*>', html))
+        self.assert_(patternExists(
+            '<input .* name="form.foo.area".* value="".*>', html))
+        self.assert_(patternExists(
+            '<input .* name="form.foo.ext".* value="".*>', html))
+        return
+
+    def test_submit_editform(self):
+        # we can submit an edit form
+        content = SampleContent()
+        request = TestRequest()
+
+        # submit edit view
+        request.form['form.foo.country'] = u'123'
+        request.form['form.foo.area'] = u'456'
+        request.form['form.foo.ext'] = u'7890'
+        request.form['form.actions.apply'] = u''
+        SampleForm(content, request)()
+
+        # check new values in object
+        self.assertEqual(content.foo, u'123-456-7890')
+        return
+
+    def test_invalid_type(self):
+        # there is no invalid type for textline-based input
+        content = SampleContent()
+        request = TestRequest()
+
+        # submit invalid type for text line
+        request.form['form.foo.country'] = '123'
+        request.form['form.foo.area'] = '456'
+        request.form['form.foo.ext'] = '7890'
+        request.form['form.actions.apply'] = u''
+        html = SampleForm(content, request)()
+
+        # We don't have a invalid field value
+        # since we convert the value to unicode
+        self.assert_('Object is of wrong type.' not in html)
+        return
+
+    def test_missing_value(self):
+        content = SampleContent()
+        request = TestRequest()
+
+        request.form['form.foo.country'] = u'123'
+        request.form['form.foo.area'] = u'456'
+        request.form['form.foo.ext'] = u'7890'
+        request.form['form.bar.country'] = u''
+        request.form['form.bar.area'] = u''
+        request.form['form.bar.ext'] = u''
+        request.form['form.baz.country'] = u''
+        request.form['form.baz.area'] = u''
+        request.form['form.baz.ext'] = u''
+        request.form['form.actions.apply'] = u''
+        SampleForm(content, request)()
+
+        # check new values in object
+        self.assertEqual(content.foo, u'123-456-7890')
+        self.assertEqual(content.bar, u'--') # default missing value
+        self.assertEqual(content.baz, u'--')
+        return
