[Zope3-checkins] CVS: Zope3/src/zope/app/form - utility.py:1.22 widget.py:1.6

Richard Jones richard@commonground.com.au
Sun, 13 Jul 2003 02:47:57 -0400


Update of /cvs-repository/Zope3/src/zope/app/form
In directory cvs.zope.org:/tmp/cvs-serv31581/src/zope/app/form

Modified Files:
	utility.py widget.py 
Log Message:
Implemented Object field types, and ObjectWidget to go with it.
Object fields have Fields on them, and when included in a form view, their
sub-fields fully participate in the form generate and editing. You'd use
this kinda thing for generating an Address field.

The change required the removal of the apply_update method on EditView. It is
replaced by the calling of applyChanges on each widget (facilitated by the 
applyWidgetsChanges function of zope.app.form.utility).

To make this sane, the ObjectWidget must be used via CustomWidget so we can
indicate which factory is to be called to generate the container for the
Object's fields. ObjectWidget and SequenceWidget also allow overriding of
the widgets used to render their sub-fields.

If this is all confusing, then see the new widgets.txt help file in the
zope/app/browser/form/ directory, and it may or may not help :)


=== Zope3/src/zope/app/form/utility.py 1.21 => 1.22 ===
--- Zope3/src/zope/app/form/utility.py:1.21	Wed Jun 18 06:10:25 2003
+++ Zope3/src/zope/app/form/utility.py	Sun Jul 13 02:47:21 2003
@@ -253,6 +253,33 @@
 
     return False
 
+def applyWidgetsChanges(view, content, schema, strict=True,
+        names=None, set_missing=True, do_not_raise=False,
+        exclude_readonly=False):
+    """Apply changes in widgets to the object."""
+    errors = []
+
+    changed = False
+    for name, field in _fieldlist(names, schema):
+        widget = getattr(view, name+'_widget')
+        if exclude_readonly and field.readonly:
+            continue
+        if widget.haveData():
+            try:
+                changed = widget.applyChanges(content) or changed
+            except InputErrors, v:
+                errors.append(v)
+        elif strict and field.required:
+            err = MissingInputError(name, widget.title, 'the field is required')
+            errors.append(err)
+        elif set_missing:
+            field.set(content, field.missing_value)
+
+    if errors and not do_not_raise:
+        raise WidgetsError(*errors)
+
+    return changed
+
 def getWidgetsData(view, schema, strict=True, names=None, set_missing=True,
                    do_not_raise=False, exclude_readonly=False):
     """Collect the user-entered data defined by a schema
@@ -304,7 +331,7 @@
                                             'the field is required')
                           )
         elif set_missing:
-            result[name] = None # XXX field.missing_value
+            result[name] = field.missing_value
 
     if errors and not do_not_raise:
         raise WidgetsError(*errors)
@@ -397,7 +424,7 @@
             errors.append(MissingInputError(name, name,
                                             'the field is required'))
         elif set_missing:
-            result[name] = None # XXX field.missing_value
+            result[name] = field.missing_value
 
     if errors and not do_not_raise:
         raise WidgetsError(*errors)


=== Zope3/src/zope/app/form/widget.py 1.5 => 1.6 ===
--- Zope3/src/zope/app/form/widget.py:1.5	Wed Jun  4 07:13:48 2003
+++ Zope3/src/zope/app/form/widget.py	Sun Jul 13 02:47:21 2003
@@ -56,20 +56,33 @@
     def getData(self):
         raise TypeError("getData has not been implemented")
 
+    def validate(self):
+        raise TypeError("validate has not been implemented")
+
+    def applyChanges(self, content):
+        raise TypeError("applyChanges has not been implemented")
+
     title = property(lambda self: self.context.title)
 
     required = property(lambda self: self.context.required)
 
+# XXX CustomWidget *should* be called CustomWidgetFactory
 class CustomWidget:
     """Custom Widget."""
     implements(IViewFactory)
 
-    def __init__(self, widget, **kw):
-        self.widget = widget
+    def __init__(self, *args, **kw):
+        self._widget_factory = args[0]
+        if len(args) > 1:
+            self.args = args[1:]
+        else:
+            self.args = ()
         self.kw = kw
 
     def __call__(self, context, request):
-        instance = self.widget(context, request)
+        args = (context, request) + self.args
+        instance = self._widget_factory(*args)
         for item in self.kw.items():
             setattr(instance, item[0], item[1])
         return instance
+