[Zope3-checkins] CVS: Zope3/src/zope/app/browser/form - __init__.py:1.1.2.1 add.py:1.1.2.1 configure.zcml:1.1.2.1 edit.pt:1.1.2.1 editview.py:1.1.2.1 meta.zcml:1.1.2.1 subedit.pt:1.1.2.1 submit.py:1.1.2.1 widget.py:1.1.2.1

Jim Fulton jim@zope.com
Mon, 23 Dec 2002 14:31:09 -0500


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

Added Files:
      Tag: NameGeddon-branch
	__init__.py add.py configure.zcml edit.pt editview.py 
	meta.zcml subedit.pt submit.py widget.py 
Log Message:
Initial renaming before debugging

=== Added File Zope3/src/zope/app/browser/form/__init__.py ===
#
# This file is necessary to make this directory a package.


=== Added File Zope3/src/zope/app/browser/form/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/23 19:31:07 jim Exp $
"""

import sys
from zope.event import publish
from zope.app.event.objectevent import ObjectCreatedEvent
from zope.app.interfaces.forms import WidgetsError
from zope.app.form.utility import setUpWidgets, getWidgetsData
from zope.app.form.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.component.view import provideView
from zope.publisher.interfaces.browser import IBrowserPresentation
from zope.app.pagetemplate.simpleviewclass import SimpleViewClass
from zope.app.browser.form.submit import Update
from zope.app.browser.form.editview import EditView, _normalize
from zope.app.interfaces.container 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),
        )
        ]




=== Added File Zope3/src/zope/app/browser/form/configure.zcml ===
<zopeConfigure
   xmlns='http://namespaces.zope.org/zope'
   xmlns:browser='http://namespaces.zope.org/browser'
   package="Zope.App.Forms.Views.Browser"
>

  <!-- Form Widget View Directives -->
  <browser:defaultView for="zope.schema.interfaces.IField" name="edit" />

  <browser:view
      permission="Zope.Public"
      allowed_interface="zope.app.interfaces.browser.form.IBrowserWidget"
      for="zope.schema.interfaces.ITextLine"
      name="edit"
      factory="zope.app.browser.form.widget.TextWidget" />

  <browser:view
      permission="Zope.Public"
      allowed_interface="zope.app.interfaces.browser.form.IBrowserWidget"
      for="zope.schema.interfaces.IText"
      name="edit"
      factory="zope.app.browser.form.widget.TextAreaWidget" />

  <browser:view
      permission="Zope.Public"
      allowed_interface="zope.app.interfaces.browser.form.IBrowserWidget"
      for="zope.schema.interfaces.IBytesLine"
      name="edit"
      factory="zope.app.browser.form.widget.BytesWidget" />

  <browser:view
      permission="Zope.Public"
      allowed_interface="zope.app.interfaces.browser.form.IBrowserWidget"
      for="zope.schema.interfaces.IBytes"
      name="edit"
      factory="zope.app.browser.form.widget.BytesAreaWidget" />

  <browser:view
      permission="Zope.Public"
      allowed_interface="zope.app.interfaces.browser.form.IBrowserWidget"
      for="zope.schema.interfaces.IInt"
      name="edit"
      factory="zope.app.browser.form.widget.IntWidget" />

  <browser:view
      permission="Zope.Public"
      allowed_interface="zope.app.interfaces.browser.form.IBrowserWidget"
      for="zope.schema.interfaces.IFloat"
      name="edit"
      factory="zope.app.browser.form.widget.FloatWidget" />

  <browser:view
      permission="Zope.Public"
      allowed_interface="zope.app.interfaces.browser.form.IBrowserWidget"
      for="zope.schema.interfaces.IBool"
      name="edit"
      factory="zope.app.browser.form.widget.CheckBoxWidget" />

  <browser:view
      permission="Zope.Public"
      allowed_interface="zope.app.interfaces.browser.form.IBrowserWidget"
      for="zope.schema.interfaces.ITuple"
      name="edit"
      factory="zope.app.browser.form.widget.TextAreaWidget" />

  <browser:view
      permission="Zope.Public"
      allowed_interface="zope.app.interfaces.browser.form.IBrowserWidget"
      for="zope.schema.interfaces.IList"
      name="edit"
      factory="zope.app.browser.form.widget.TextAreaWidget" />

  <!-- Default simple display view -->
  <browser:view
      permission="Zope.Public"
      allowed_interface="zope.app.interfaces.browser.form.IBrowserWidget"
      for="zope.schema.interfaces.IField"
      name="display"
      factory="zope.app.browser.form.widget.DisplayWidget" />
  
</zopeConfigure>


=== Added File Zope3/src/zope/app/browser/form/edit.pt ===
<html metal:use-macro="views/standard_macros/dialog">
  <body>
  <div metal:fill-slot="body">

  <div metal:define-macro="body">

    <form action="." tal:attributes="action request/URL" method="POST"
          enctype="multipart/form-data"
          >

      <div metal:define-macro="formbody">

        <h3 tal:condition="view/label"
            tal:content="view/label"
            metal:define-slot="heading"
            >Edit something</h3>

        <p tal:define="status view/update"
           tal:condition="status"
           tal:content="status" />

        <div tal:condition="view/errors">
           <ul>
              <li tal:repeat="error view/errors">
                 <strong tal:content="error/__class__">
                    Error Type</strong>:
                 <span tal:content="error">Error text</span>
              </li>
           </ul>
        </div>

        <div metal:define-slot="extra_info" tal:replace="nothing">
        </div>

        <table width="100%" border="0">
        <tr metal:define-slot="extra_top" tal:replace="nothing">
            <td>Extra top</td>
            <td><input type="text" style="width:100%" /></td>
        </tr>
        <tr metal:define-macro="widget_rows" tal:repeat="widget view/widgets"
            tal:content="structure widget/row">
            <td>Name</td>
            <td><input type="text" style="width:100%" /></td>
        </tr>
        <tr metal:define-slot="extra_bottom" tal:replace="nothing">
            <td>Extra bottom</td>
            <td><input type="text" style="width:100%" /></td>
        </tr>
        </table>

      </div>

      <input type="submit"  value="Refresh" />
      <input type="submit" name="UPDATE_SUBMIT"  value="Save Changes" />

    </form>

  </div>

  </div>
  </body>

</html>


=== Added File Zope3/src/zope/app/browser/form/editview.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: editview.py,v 1.1.2.1 2002/12/23 19:31:07 jim Exp $
"""

from datetime import datetime
from zope.event import publish
from zope.app.event.objectevent import ObjectModifiedEvent
from zope.publisher.browser import BrowserView
from Zope.App.Forms.Views.Browser import Widget
from zope.app.interfaces.forms import WidgetsError
from zope.app.form.utility import setUpEditWidgets, getWidgetsData
from zope.app.form.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.component.view import provideView
from zope.publisher.interfaces.browser import IBrowserPresentation
from zope.app.pagetemplate.simpleviewclass import SimpleViewClass
from zope.app.browser.form.submit import Update


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

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

    errors = ()
    label = ''

    # Fall-back field names computes from schema
    fieldNames = property(lambda self: fieldNames(self.schema))
        
    def __init__(self, context, request):
        super(EditView, self).__init__(context, request)
        setUpEditWidgets(self, self.schema, names=self.fieldNames)

    def setPrefix(self, prefix):
        for widget in self.widgets():
            widget.setPrefix(prefix)

    def widgets(self):
        return [getattr(self, name)
                for name in 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.
        """
            
        content = self.context

        errors = []
        unchanged = True

        for name in data:
            # OK, we really got a field
            try:
                newvalue = data[name]

                # We want to see if the data changes. Unfortunately,
                # we don't know enough to know that we won't get some
                # strange error, so we'll carefully ignore errors and
                # assume we should update the data if we can't be sure
                # it's the same.

                change = True
                try:
                    # Use self as a marker
                    change = getattr(content, name, self) != newvalue
                except:
                    pass

                if change:
                    setattr(content, name, data[name])
                    unchanged = False

            except Exception, v:
                errors.append(v)

        if errors:
            raise WidgetsError(*errors)

        if not unchanged:
            publish(content, ObjectModifiedEvent(content))

        return unchanged

    def update(self):
        if Update in self.request:
            unchanged = True
            try:
                data = getWidgetsData(self, self.schema,
                                      required=0, names=self.fieldNames)
                unchanged = 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."
            else:
                setUpEditWidgets(self, self.schema, force=1,
                                 names=self.fieldNames)
                if not unchanged:
                    return "Updated %s" % datetime.utcnow()

        return ''


def EditViewFactory(name, schema, label, permission, layer,
                    template, default_template, bases, for_, fields,
                    fulledit_path=None, fulledit_label=None):

    class_  = SimpleViewClass(
        template,
        used_for = schema, bases = bases
        )
    class_.schema = schema
    class_.label = label
    class_.fieldNames = fields

    class_.fulledit_path = fulledit_path
    if fulledit_path and (fulledit_label is None):
        fulledit_label = "Full edit"
        
    class_.fulledit_label = fulledit_label

    class_.generated_form = ViewPageTemplateFile(default_template)

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

    provideView(for_, name, IBrowserPresentation, class_, layer)
                  

def _normalize(_context, schema_, for_, class_, template, default_template,
               fields, omit, view=EditView):
    schema = _context.resolve(schema_)

    if for_ is None:
        for_ = schema
    else:
        for_ = _context.resolve(for_)

    if class_ is None:
        bases = (view, )
    else:
        bases = (_context.resolve(class_), view)
        

    if template is not None:
        template = _context.path(template)
    else:
        template = default_template

    template = str(template)

    names = fieldNames(schema)
    
    if fields:
        fields = fields.split()
        for name in fields:
            if name not in names:
                raise ValueError("Field name %s is not in schema %s",
                                 name, schema_)
    else:
        fields = names

    if omit:
        omit = omit.split()
        for name in omit:
            if name not in names:
                raise ValueError("Field name %s is not in schema %s",
                                 name, schema_)
        fields = [name for name in fields if name not in omit]

    return schema, for_, bases, template, fields

def edit(_context, name, schema, label,
              permission = 'Zope.Public', layer = "default",
              class_ = None, for_ = None,
              template = None, omit=None, fields=None):

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

    return [
        Action(
        discriminator = ('http://namespaces.zope.org/form/edit',
                         name, for_, layer),
        callable = EditViewFactory,
        args = (name, schema, label, permission, layer, template, 'edit.pt',
                bases,
                for_, fields),
        )
        ]

def subedit(_context, name, schema, label,
              permission = 'Zope.Public', layer = "default",
              class_ = None, for_ = None,
              template = None, omit=None, fields=None,
              fulledit=None, fulledit_label=None):

    (schema, for_, bases, template, fields,
     ) = _normalize(
        _context, schema, for_, class_, template, 'subedit.pt', fields, omit)
    
    return [
        Action(
        discriminator = ('http://namespaces.zope.org/form/subedit',
                         name, for_, layer),
        callable = EditViewFactory,
        args = (name, schema, label, permission, layer, template, 'subedit.pt',
                bases,
                for_, fields, fulledit, fulledit_label),
        )
        ]




=== Added File Zope3/src/zope/app/browser/form/meta.zcml ===
<zopeConfigure xmlns='http://namespaces.zope.org/zope'>

  <directives namespace="http://namespaces.zope.org/form">

    <directive
       name="edit" 
       attributes="name schema label for layer permission class template"
       handler="zope.app.browser.form.editview.edit"
       />

    <directive
       name="subedit" 
       attributes="name schema label for layer permission class template
                   fulledit fulledit_label"
       handler="zope.app.browser.form.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="zope.app.browser.form.add.add"
       />

  </directives>

</zopeConfigure>


=== Added File Zope3/src/zope/app/browser/form/subedit.pt ===
<div metal:define-macro="formbody">
  <span tal:condition="view/label"
      tal:content="view/label"
      metal:define-slot="heading"
      >
Edit something
  </span>
  <p tal:condition="view/fulledit_label">
    <a tal:attributes="href
         string:${context/@@absolute_url}/${view/fulledit_path}"
       tal:content="view/fulledit_label">Full edit</a>
  </p>
  <p tal:define="status view/update"
     tal:condition="status"
     tal:content="status" />

  <div tal:condition="view/errors">
     <ul>
        <li tal:repeat="error view/errors">
           <strong tal:content="error/__class__">
              Error Type</strong>:
           <span tal:content="error">Error text</span>
        </li>
     </ul>
  </div>

  <div metal:define-slot="extra_info" tal:replace="nothing">
  </div>

  <table width="100%" border="0">
  <tr metal:define-slot="extra_top" tal:replace="nothing">
      <td>Extra top</td>
      <td><input type="text" style="width:100%" /></td>
  </tr>
  <tr metal:define-macro="widget_rows" tal:repeat="widget view/widgets"
      tal:content="structure widget/row">
      <td>Name</td>
      <td><input type="text" style="width:100%" /></td>
  </tr>
  <tr metal:define-slot="extra_bottom" tal:replace="nothing">
      <td>Extra bottom</td>
      <td><input type="text" style="width:100%" /></td>
  </tr>
  </table>

</div>


=== Added File Zope3/src/zope/app/browser/form/submit.py ===
##############################################################################
#
# 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.
# 
##############################################################################
"""Standard submit button names

Update -- Name of the standard update submit button


$Id: submit.py,v 1.1.2.1 2002/12/23 19:31:07 jim Exp $
"""

Update = "UPDATE_SUBMIT"


=== Added File Zope3/src/zope/app/browser/form/widget.py === (530/630 lines abridged)
##############################################################################
#
# 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: widget.py,v 1.1.2.1 2002/12/23 19:31:07 jim Exp $
"""

__metaclass__ = type

import sys
from types import ListType, TupleType
ListTypes = (ListType, TupleType)
from zope.component import getAdapter
from zope.proxy.introspection import removeAllProxies
from zope.publisher.browser import BrowserView
from zope.app.interfaces.browser.form import IBrowserWidget
from zope.app.form.widget import Widget
from zope.app.interfaces.forms import ConversionError, WidgetInputError, MissingInputError
from zope.schema.interfaces import ValidationError


class BrowserWidget(Widget, BrowserView):
    """A field widget that knows how to display itself as HTML."""

    __implements__ = IBrowserWidget

    propertyNames = (Widget.propertyNames + 
                     ['tag', 'type', 'cssClass', 'extra'])
    
    tag = 'input'
    type = 'text'
    cssClass = ''
    extra = ''
    _missing = None

    def haveData(self):
        if (self.name) in self.request.form:
            return self._convert(self.request[self.name]) is not None
        return False


[-=- -=- -=- 530 lines omitted -=- -=- -=-]

                              type = "checkbox",
                              cssClass = cssClass,
                              name = name,
                              value = value) + text
    
    def renderSelectedItem(self, text, value, name, cssClass):
        return renderElement('input',
                              type = "checkbox",
                              cssClass = cssClass,
                              name = name,
                              value = value,
                              checked = None) + text


# XXX Note, some HTML quoting is needed in renderTag and renderElement.

def renderTag(tag, **kw):
    """Render the tag. Well, not all of it, as we may want to / it."""
    attr_list = []

    # special case handling for cssClass
    if 'cssClass' in kw:
        if kw['cssClass'] != "":
            attr_list.append('class="%s"' % kw['cssClass'])
        del kw['cssClass']

    # special case handling for extra 'raw' code
    if 'extra' in kw:
        extra = kw['extra'] # could be empty string but we don't care
        del kw['extra']
    else:
        extra = ""

    # handle other attributes
    for key, value in kw.items():
        if value == None:
            value = key
        attr_list.append('%s="%s"' % (key, str(value)))
            
    attr_str = " ".join(attr_list)
    return "<%s %s %s" % (tag, attr_str, extra)


def renderElement(tag, **kw):
    if 'contents' in kw:
        contents = kw['contents']
        del kw['contents']
        return "%s>%s</%s>" % (apply(renderTag, (tag,), kw), contents, tag)
    else:
        return apply(renderTag, (tag,), kw) + " />"