[Zope3-checkins] CVS: Zope3/lib/python/Zope/App/Forms/Browser - add.py:1.1.2.1 EditView.py:1.4.2.1 meta.zcml:1.2.2.1

Jim Fulton jim@zope.com
Thu, 12 Dec 2002 13:33:55 -0500


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

Modified Files:
      Tag: AdapterAndView-branch
	EditView.py meta.zcml 
Added Files:
      Tag: AdapterAndView-branch
	add.py 
Log Message:
Added a generic schema-driven add view.

We have unit tests, but we still need to test it in practice.



=== Added File Zope3/lib/python/Zope/App/Forms/Browser/add.py ===
##############################################################################
#
# 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: add.py,v 1.1.2.1 2002/12/12 18:33:54 jim Exp $
"""

from Zope.Event import publish
from Zope.Event.ObjectEvent import ObjectCreatedEvent
from Zope.App.Forms.Exceptions import WidgetsError
from Zope.App.Forms.Utility import setUpWidgets, getWidgetsData
from Zope.App.Forms.Utility import haveWidgetsData, fieldNames
from Zope.Configuration.Action import Action
from Zope.App.PageTemplate.ViewPageTemplateFile import ViewPageTemplateFile
from Zope.Security.Checker import defineChecker, NamesChecker
from Zope.ComponentArchitecture.GlobalViewService import provideView
from Zope.Publisher.Browser.IBrowserPresentation import IBrowserPresentation
from Zope.App.PageTemplate.SimpleViewClass import SimpleViewClass
from Zope.App.Forms.Browser.StandardSubmit import Update
from EditView import EditView, _normalize
from Zope.App.OFS.Container.IAdding import IAdding

class AddView(EditView):
    """Simple edit-view base class

    Subclasses should provide a schema attribute defining the schema
    to be edited.
    """

    def __init__(self, context, request):
        super(EditView, self).__init__(context, request)
        setUpWidgets(self, self.schema, names=self.fieldNames)

    def apply_update(self, data):
        """Apply data updates

        Return true if data were unchanged and false otherwise.
        This sounds backwards, but it allows lazy implementations to
        avoid tracking changes.
        """

        args = []
        for name in self._arguments:
            args.append(data[name])

        kw = {}
        for name in self._keyword_arguments:
            kw[name] = data[name]

        content = self._factory(*args, **kw)

        errors = []

        for name in self._set_before_add:
            try:
                setattr(content, name, data[name])
            except:
                # Yes, I want a bare except here to catch all errors and
                # include them in the error list
                errors.append(sys.exc_info()[1])

        if errors:
            raise WidgetsError(*errors)

        publish(content, ObjectCreatedEvent(content))

        try:
            content = self.context.add(content)
        except:
            errors.append(sys.exc_info()[1])
            raise WidgetsError(*errors)
            

        for name in self._set_after_add:
            try:
                setattr(content, name, data[name])
            except:
                # Yes, I want a bare except here to catch all errors and
                # include them in the error list
                errors.append(sys.exc_info()[1])

        if errors:
            raise WidgetsError(*errors)

        return content

    def update(self):
        if Update in self.request:
            try:
                data = getWidgetsData(self, self.schema,
                                      required=0, names=self.fieldNames)
                content = self.apply_update(data)
            except WidgetsError, errors:
                self.errors = errors
                return u"An error occured."
            except Exception, v:
                self.errors = (v, )
                return u"An error occured."

            self.request.response.redirect(self.context.nextURL())


def AddViewFactory(name, schema, label, permission, layer,
                   template, default_template, bases, for_,
                   fields, content_factory, arguments,
                   keyword_arguments, set_before_add, set_after_add):

    class_  = SimpleViewClass(
        template,
        used_for = schema, bases = bases
        )

    class_.schema = schema
    class_.label = label
    class_.fieldNames = fields
    class_._factory = content_factory
    class_._arguments = arguments
    class_._keyword_arguments = keyword_arguments
    class_._set_before_add = set_before_add
    class_._set_after_add = set_after_add
    
    class_.generated_form = ViewPageTemplateFile(default_template)

    defineChecker(class_,
                  NamesChecker(
                    ("__call__", "__getitem__", "browserDefault"),
                    permission,
                    )
                  )

    provideView(for_, name, IBrowserPresentation, class_, layer)
    
def add(_context, name, schema, label, content_factory, 
        permission = 'Zope.Public', layer = "default",
        class_ = None, for_ = None,
        template = None, omit=None, fields=None,
        arguments='', keyword_arguments='',
        set_before_add='', set_after_add=''):

    content_factory = _context.resolve(content_factory)

    (schema, for_, bases, template, fields,
     ) = _normalize(
        _context, schema, for_, class_, template, 'add.pt', fields, omit,
        AddView)

    leftover = fields

    if arguments:
        arguments = arguments.split()
        missing = [n for n in arguments if n not in fields]
        if missing:
            raise ValueError("Some arguments are not included in the form",
                             missing)
        leftover = [n for n in leftover if n not in arguments]

    if keyword_arguments:
        keyword_arguments = keyword_arguments.split()
        missing = [n for n in keyword_arguments if n not in fields]
        if missing:
            raise ValueError(
                "Some keyword_arguments are not included in the form",
                missing)
        leftover = [n for n in leftover if n not in keyword_arguments]

    if set_before_add:
        set_before_add = set_before_add.split()
        missing = [n for n in set_before_add if n not in fields]
        if missing:
            raise ValueError(
                "Some set_before_add are not included in the form",
                missing)
        leftover = [n for n in leftover if n not in set_before_add]

    if set_after_add:
        set_after_add = set_after_add.split()
        missing = [n for n in set_after_add if n not in fields]
        if missing:
            raise ValueError(
                "Some set_after_add are not included in the form",
                missing)
        leftover = [n for n in leftover if n not in set_after_add]

    set_after_add += leftover

    return [
        Action(
        discriminator = ('http://namespaces.zope.org/form/add', name, layer),
        callable = AddViewFactory,
        args = (name, schema, label, permission, layer, template, 'add.pt',
                bases,
                IAdding, fields, content_factory, arguments,
                keyword_arguments, set_before_add, set_after_add),
        )
        ]




=== Zope3/lib/python/Zope/App/Forms/Browser/EditView.py 1.4 => 1.4.2.1 ===
--- Zope3/lib/python/Zope/App/Forms/Browser/EditView.py:1.4	Wed Dec 11 08:55:59 2002
+++ Zope3/lib/python/Zope/App/Forms/Browser/EditView.py	Thu Dec 12 13:33:54 2002
@@ -151,7 +151,7 @@
                   
 
 def _normalize(_context, schema_, for_, class_, template, default_template,
-               fields, omit):
+               fields, omit, view=EditView):
     schema = _context.resolve(schema_)
 
     if for_ is None:
@@ -160,9 +160,9 @@
         for_ = _context.resolve(for_)
 
     if class_ is None:
-        bases = (EditView, )
+        bases = (view, )
     else:
-        bases = (_context.resolve(class_), EditView)
+        bases = (_context.resolve(class_), view)
         
 
     if template is not None:


=== Zope3/lib/python/Zope/App/Forms/Browser/meta.zcml 1.2 => 1.2.2.1 ===
--- Zope3/lib/python/Zope/App/Forms/Browser/meta.zcml:1.2	Wed Dec 11 08:55:59 2002
+++ Zope3/lib/python/Zope/App/Forms/Browser/meta.zcml	Thu Dec 12 13:33:54 2002
@@ -14,6 +14,14 @@
        handler=".EditView.subedit"
        />
 
+    <directive
+       name="add" 
+       attributes="name schema label for layer permission class
+                   template content_factory argument keyword_arguments
+                   set_before_add set_after_add"
+       handler=".add."
+       />
+
   </directives>
 
 </zopeConfigure>