[Zope3-checkins] CVS: Zope3/lib/python/Zope/App/Forms/Browser - add.py:1.2 EditView.py:1.5 meta.zcml:1.3

Jim Fulton jim@zope.com
Thu, 19 Dec 2002 15:16:01 -0500


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

Modified Files:
	EditView.py meta.zcml 
Added Files:
	add.py 
Log Message:

Added autogenerated add views.

Here's an example zcml directive that defines an add view with no
additional zpt or python code:

  <form:add
      schema = ".interfaces.IViewConfiguration"
      name= "ViewConfiguration"
      content_factory = ".view.ViewConfiguration"
      keyword_arguments = "forInterface presentationType factoryName viewName"
      set_before_add = "layer"
      label = "Configure a view" 
      permission="Zope.ManageServices" 
      fields="forInterface viewName presentationType
              factoryName layer title status description"
      />

This is a pretty complicated example.

To do: document this directive. :)



=== Zope3/lib/python/Zope/App/Forms/Browser/add.py 1.1 => 1.2 ===
--- /dev/null	Thu Dec 19 15:16:01 2002
+++ Zope3/lib/python/Zope/App/Forms/Browser/add.py	Thu Dec 19 15:15:30 2002
@@ -0,0 +1,215 @@
+##############################################################################
+#
+# 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$
+"""
+
+import sys
+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:
+            if name in data:
+                kw[str(name)] = data[name]
+
+        content = self._factory(*args, **kw)
+
+        errors = []
+
+        for name in self._set_before_add:
+            if name in data:
+                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:
+            if name in data:
+                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, 'edit.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
+
+    else:
+        
+        set_after_add = leftover
+
+    return [
+        Action(
+        discriminator = ('http://namespaces.zope.org/form/add', name, layer),
+        callable = AddViewFactory,
+        args = (name, schema, label, permission, layer, template, 'edit.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.5 ===
--- 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 19 15:15:30 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.3 ===
--- 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 19 15:15:30 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>