[Zope3-checkins] CVS: Zope3/src/zope/app/form - __init__.py:1.2 configure.zcml:1.2 utility.py:1.2 widget.py:1.2

Jim Fulton jim@zope.com
Wed, 25 Dec 2002 09:13:53 -0500


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

Added Files:
	__init__.py configure.zcml utility.py widget.py 
Log Message:
Grand renaming:

- Renamed most files (especially python modules) to lower case.

- Moved views and interfaces into separate hierarchies within each
  project, where each top-level directory under the zope package
  is a separate project.

- Moved everything to src from lib/python.

  lib/python will eventually go away. I need access to the cvs
  repository to make this happen, however.

There are probably some bits that are broken. All tests pass
and zope runs, but I haven't tried everything. There are a number
of cleanups I'll work on tomorrow.



=== Zope3/src/zope/app/form/__init__.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:53 2002
+++ Zope3/src/zope/app/form/__init__.py	Wed Dec 25 09:12:52 2002
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.


=== Zope3/src/zope/app/form/configure.zcml 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:53 2002
+++ Zope3/src/zope/app/form/configure.zcml	Wed Dec 25 09:12:52 2002
@@ -0,0 +1,3 @@
+<zopeConfigure xmlns='http://namespaces.zope.org/zope'>
+
+</zopeConfigure>


=== Zope3/src/zope/app/form/utility.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:53 2002
+++ Zope3/src/zope/app/form/utility.py	Wed Dec 25 09:12:52 2002
@@ -0,0 +1,230 @@
+##############################################################################
+#
+# 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 fields 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.component import getView, getDefaultViewName
+from zope.schema.interfaces import IField
+from zope.app.interfaces.forms import IWidget
+from zope.app.interfaces.forms import WidgetsError, MissingInputError
+from zope.component.interfaces import IViewFactory
+
+
+def setUpWidget(view, name, field, value=None, prefix=None,
+                force=0, vname=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 = field.bind(view.context)
+        if vname is None:
+            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 IViewFactory.isImplementedBy(widget):
+            # This is a view factory, probably a custom widget.
+            # Try to make it into a widget.
+            field = field.bind(view.context)
+            widget = widget(field, view.request)
+            if IWidget.isImplementedBy(widget):
+                # Yee ha! We have a widget now, save it
+                setattr(view, name, 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 prefix:
+        widget.setPrefix(prefix)
+
+    if value is not None and (force or not widget.haveData()):
+        widget.setData(value)
+
+def fieldNames(schema):
+
+    names = []
+    for name in schema:
+        field = schema[name]
+        if IField.isImplementedBy(field):
+            names.append((field.order, name))
+
+    names.sort()
+
+    return [name[1] for name in names]
+
+def setUpWidgets(view, schema, prefix=None, force=0,
+                 initial={}, names=None):
+    """Set up widgets for the fields defined by a schema
+
+    """
+
+    for name in (names or schema):
+        field = schema[name]
+        if IField.isImplementedBy(field):
+            # OK, we really got a field
+            setUpWidget(view, name, field, initial.get(name),
+                        prefix=prefix, force=force)
+
+def setUpEditWidgets(view, schema, content=None, prefix=None, force=0,
+                     names=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 (names or schema):
+        field = schema[name]
+        if IField.isImplementedBy(field):
+            # OK, we really got a field
+            if field.readonly:
+                vname = 'display'
+            else:
+                vname = 'edit'
+
+            try:
+                value = getattr(content, name)
+            except AttributeError, v:
+                if v.__class__ != AttributeError:
+                    raise
+                value = None
+
+            setUpWidget(view, name, field, value,
+                        prefix = prefix, force = force, vname = vname)
+
+def haveWidgetsData(view, schema, names=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 returned in a mapping from field name to value.
+    """
+
+    for name in (names or schema):
+        field = schema[name]
+        if IField.isImplementedBy(field):
+            # OK, we really got a field
+            if  getattr(view, name).haveData():
+                return True
+
+    return False
+
+def getWidgetsData(view, schema, required=1, names=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 returned in a mapping from field name to value.
+
+    If the required argument is true, then all of the data defined by
+    the schema will be returned. If some required data are missing
+    from the input, an error will be raised.
+
+    """
+
+    result = {}
+    errors = []
+
+    for name in (names or schema):
+        field = schema[name]
+        if IField.isImplementedBy(field):
+            # OK, we really got a field
+            widget = getattr(view, name)
+            if widget.haveData():
+                try:
+                    result[name] = widget.getData()
+                except Exception, v:
+                    errors.append(v)
+            elif required and field.required:
+                raise MissingInputError(
+                    widget.name, widget.title, name)
+
+    if errors:
+        raise WidgetsError(*errors)
+
+    return result
+
+def getWidgetsDataForContent(view, schema, content=None, required=0,
+                             names=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.
+
+    If the required argument is true, then all of the data defined by
+    the schema will be set, at least for required fields. If some data
+    for required fields are missing from the input, an error will be
+    raised.
+
+    """
+
+    data = getWidgetsData(view, schema, required, names)
+
+    if content is None:
+        content = view.context
+
+    errors = []
+
+    for name in data:
+        # OK, we really got a field
+        try:
+            setattr(content, name, data[name])
+        except Exception, v:
+            errors.append(v)
+
+    if errors:
+        raise WidgetsError(*errors)


=== Zope3/src/zope/app/form/widget.py 1.1 => 1.2 ===
--- /dev/null	Wed Dec 25 09:13:53 2002
+++ Zope3/src/zope/app/form/widget.py	Wed Dec 25 09:12:52 2002
@@ -0,0 +1,76 @@
+##############################################################################
+#
+# Copyright (c) 2001, 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.
+#
+##############################################################################
+"""
+$Id$
+"""
+from zope.app.interfaces.forms import IWidget
+from zope.schema.interfaces import ValidationError
+from zope.app.interfaces.forms import WidgetInputError
+from zope.component.interfaces import IViewFactory
+
+class Widget(object):
+    """Mix-in class providing some functionality common accross view types
+    """
+
+
+    __implements__ = IWidget
+
+    _prefix = 'field.'
+    _data = None
+
+    def __init__(self, context, request):
+        self.context = context
+        self.request = request
+        self.name = self._prefix + context.__name__
+
+    # See IWidget
+    propertyNames = []
+
+    def getValue(self, name):
+        'See IWidget'
+        if name in self.propertyNames:
+            return getattr(self, name, None)
+
+    def setPrefix(self, prefix):
+        if not prefix.endswith("."):
+            prefix += '.'
+        self._prefix = prefix
+        self.name = prefix + self.context.__name__
+
+    def setData(self, value):
+        self._data = value
+
+    def haveData(self):
+        raise TypeError("haveData has not been implemented")
+
+    def getData(self):
+        raise TypeError("haveData has not been implemented")
+
+    title = property(lambda self: self.context.title)
+
+    required = property(lambda self: self.context.required)
+
+class CustomWidget(object):
+    """Custom Widget."""
+    __implements__ = IViewFactory
+
+    def __init__(self, widget, **kw):
+        self.widget = widget
+        self.kw = kw
+
+    def __call__(self, context, request):
+        instance = self.widget(context, request)
+        for item in self.kw.items():
+            setattr(instance, item[0], item[1])
+        return instance