[Zope3-checkins] CVS: Zope3/lib/python/Zope/App/Forms - Utility.py:1.2 Exceptions.py:1.3 IWidget.py:1.4 Widget.py:1.4

Jim Fulton jim@zope.com
Mon, 28 Oct 2002 18:53:01 -0500


Update of /cvs-repository/Zope3/lib/python/Zope/App/Forms
In directory cvs.zope.org:/tmp/cvs-serv12652/lib/python/Zope/App/Forms

Modified Files:
	Exceptions.py IWidget.py Widget.py 
Added Files:
	Utility.py 
Log Message:
Merged the form (Zope.App.Forms) changes from the
Zope3-Banagalore-TTW-Branch branch.

See IWidget and IBrwoserWidget for important changes to those
interfaces.

See Utility.py for a number of functions for managing schema-driven
forms. These will ultimately replace FormViews, which will, I hope,
soon be deprecated.


=== Zope3/lib/python/Zope/App/Forms/Utility.py 1.1 => 1.2 ===
--- /dev/null	Mon Oct 28 18:53:01 2002
+++ Zope3/lib/python/Zope/App/Forms/Utility.py	Mon Oct 28 18:52:31 2002
@@ -0,0 +1,146 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+# 
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+# 
+##############################################################################
+"""Form utility functions
+
+In Zope 2's formulator, forms provide a basic mechanism for
+organizating collections of fields and providing unsert interfaces for
+them, especially editing interfaces.
+
+In Zope 3, formulator's forms are replaced by Schema (See
+Zope.Schema). In addition, the Formulator fields have been replaced by
+schema filds and form widgets. Schema fields just express the sematics
+of data values. They contain no presentation logic or parameters.
+Widgets are views on fields that take care of presentation. The widget
+view names represent styles that can be selected by applications to
+customise the presentation. There can also be custom widgets with
+specific parameters.
+
+This module provides some utility functions that provide some of the
+functionality of formulator forms that isn't handled by schema,
+fields, or widgets.
+
+$Id$
+"""
+__metaclass__ = type
+
+from Zope.ComponentArchitecture import getView, getDefaultViewName
+from Zope.Schema.IField import IField
+from Zope.App.Forms.IWidget import IWidget
+from Zope.App.Forms.Exceptions import WidgetsError
+from Zope.Proxy.ContextWrapper import ContextWrapper
+
+
+def setUpWidget(view, name, field, value=None):
+    """Set up a single view widget
+
+    The widget will be an attribute of the view. If there is already
+    an attribute of the given name, it must be a widget and it will be
+    initialized with the given value if not None.
+
+    If there isn't already a view attribute of the given name, then a
+    widget will be created and assigned to the attribute.
+    """
+
+    # Has a (custom) widget already been defined?
+    widget = getattr(view, name, None)
+    if widget is None:
+        # There isn't already a widget, create one
+        field = ContextWrapper(field, view.context, name=name)
+        vname = getDefaultViewName(field, view.request)
+        widget = getView(field, vname, view.request)
+        setattr(view, name, widget)
+    else:
+        # We have an attribute of the right name, it it really a widget
+        if not IWidget.isImplementedBy(widget):
+            raise TypeError(
+                "The %s view attribute named, %s, should be a widget, "
+                "but isn't."
+                % (view.__class__.__name__, name))
+
+    if value is not None:
+        widget.setData(value)
+
+def setUpWidgets(view, schema, **kw):
+    """Set up widgets for the fields defined by a schema
+
+    Initial data is provided by keyword arguments.
+    """
+    
+    for name in schema:
+        field = schema[name]
+        if IField.isImplementedBy(field):
+            # OK, we really got a field
+            setUpWidget(view, name, field, kw.get(name))
+
+def setUpEditWidgets(view, schema, content=None):
+    """Set up widgets for the fields defined by a schema
+
+    Initial data is provided by content object attributes.
+    No initial data is provided if the content lacks a named
+    attribute, or if the named attribute value is None.
+    """
+    if content is None:
+        content = view.context
+
+    for name in schema:
+        field = schema[name]
+        if IField.isImplementedBy(field):
+            # OK, we really got a field
+            setUpWidget(view, name, field, getattr(content, name, None))
+
+def getWidgetsData(view, schema):
+    """Collect the user-entered data defined by a schema
+
+    Data is collected from view widgets. For every field in the
+    schema, we look for a view of the same name and get it's data.
+
+    The data are returned in a mapping from field name to value.
+    """
+
+    result = {}
+    errors = []
+
+    for name in schema:
+        field = schema[name]
+        if IField.isImplementedBy(field):
+            # OK, we really got a field
+            try:
+                result[name] = getattr(view, name).getData()
+            except Exception, v:
+                errors.append(v)
+
+    if errors:
+        raise WidgetsError(*errors)
+    
+    return result
+
+def getWidgetsDataForContent(view, schema, content=None):
+    """Collect the user-entered data defined by a schema
+
+    Data is collected from view widgets. For every field in the
+    schema, we look for a view of the same name and get it's data.
+
+    The data are assigned to the given content object.
+    """
+    data = getWidgetsData(view, schema)
+    
+    if content is None:
+        content = view.context
+
+    for name in schema:
+        field = schema[name]
+        if IField.isImplementedBy(field):
+            # OK, we really got a field
+            setattr(content, name, getattr(view, name).getData())
+


=== Zope3/lib/python/Zope/App/Forms/Exceptions.py 1.2 => 1.3 ===
--- Zope3/lib/python/Zope/App/Forms/Exceptions.py:1.2	Wed Oct  9 09:53:54 2002
+++ Zope3/lib/python/Zope/App/Forms/Exceptions.py	Mon Oct 28 18:52:31 2002
@@ -37,3 +37,28 @@
         self.error_name = error_name
         self.original_exception = original_exception
 
+
+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(map(str, self.args))
+
+    __repr__ = __str__
+
+class WidgetsError(ErrorContainer):
+    """A collection of errors from widget processing.
+    """


=== Zope3/lib/python/Zope/App/Forms/IWidget.py 1.3 => 1.4 ===
--- Zope3/lib/python/Zope/App/Forms/IWidget.py:1.3	Wed Oct  9 09:26:06 2002
+++ Zope3/lib/python/Zope/App/Forms/IWidget.py	Mon Oct 28 18:52:31 2002
@@ -51,4 +51,9 @@
 
         This is the text that will be used to label the widget.
         """
+    def setData(value):
+        """Set the default data for the widget.
 
+        The given value should only be used if the user hasn't entered
+        any data and the data should be a valid data for the field.
+        """


=== Zope3/lib/python/Zope/App/Forms/Widget.py 1.3 => 1.4 ===
--- Zope3/lib/python/Zope/App/Forms/Widget.py:1.3	Sat Sep  7 12:18:48 2002
+++ Zope3/lib/python/Zope/App/Forms/Widget.py	Mon Oct 28 18:52:31 2002
@@ -19,8 +19,10 @@
 from Zope.App.Forms.Exceptions import WidgetInputError
 
 class Widget(object):
-    """I do not know what will be in this class, but it provides an extra
-    layer."""
+    """Mix-in class providing some functionality common accross view types
+    """
+
+
     __implements__ = IWidget
 
     def __init__(self, context, request):