Metadata-Version: 1.0
Name: plone.autoform
Version: 1.2
Summary: Tools to construct z3c.form forms
Home-page: http://code.google.com/p/dexterity
Author: Martin Aspeli
Author-email: optilude@gmail.com
License: LGPL
Description: ==============
        plone.autoform
        ==============
        
        .. contents:: Contents
        
        This package provides tools to construct `z3c.form`_ forms out of hints stored
        in tagged values on schema interfaces. A special form base class is used to
        set up the ``fields`` and ``groups`` properties on form instances. It also
        contains a "display form" implementation that is compatible with Zope 2
        page templates, and with some convenience features for rendering widgets in
        view mode.
        
        The tagged values are stored under a various keys. These can be found in
        the ``plone.autoform.interfaces`` module. They support:
        
        * changing a field to 'display' or 'hidden' mode
        * omitting fields
        * re-ordering fields relative to one another
        * placing fields into fieldsets (groups)
        * changing the widget of a field
        * displaying a field conditionally based on a permission
        
        There are several ways to set the form data:
        
        * Manually, by using ``setTaggedValue()`` on an interface.
        * By loading the schema from a `plone.supermodel`_ XML file and using the 
          ``form:`` prefix
        * By using the directives from ``plone.autoform.directives`` while defining
          a schema in Python.
        
        To use the automatic form setup, mix in the following base class in your
        forms::
        
            >>> from plone.autoform.form import AutoExtensibleForm
        
        and then provide the ``schema``` (a schema interface) and optionally the
        ``additionalSchemata`` (a list of schema interfaces) attributes on your form::
        
            >>> class MyForm(AutoExtensibleForm, form.EditForm):
            ...     schema = IMySchema
            ...     additionalSchemata = (ISchemaOne, ISchemaTwo,)
            ...     
            ...     # ...
        
        For dynamic forms, you could of course make ``schema`` and 
        ``additionalSchemata`` into properties.
        
        To use the display form, create a view like:
        
            >>> from plone.autoform.view import WidgetsView
            >>> class MyView(WidgetsView):
            ...     schema = IMySchema
            ...     additionalSchemata = (ISchemaOne, ISchemaTwo,)
            ...     
            ...     # ...
        
        To render the form, do not override ``__call__()``. Instead, either implement
        the ``render()`` method, set an ``index`` attribute to a page template or
        other callable, or use the ``template`` attribute of the ``<browser:page />``
        ZCML directive when registering the view.
        
        In the template, you can use the following variables:
        
        * ``view/w`` is a dictionary of all widgets, including those from non-default
          fieldsets (by contrast, the ``widgets`` variable contains only those
          widgets in the default fieldset). The keys are the field names, and the
          values are widget instances. To render a widget (in display mode), you can
          do ``tal:replace="structure view/w/myfield/render" />``.
        * ``view/fieldsets`` is a dictionary of all fieldsets (not including the
          default fieldset, i.e. those widgets not placed into a fieldset). They keys
          are the fieldset names, and the values are the fieldset form instances,
          which in turn have variables like ``widgets`` given a list of all widgets.
        
        See ```autoform.txt``` for details on how to use the form generation,
        ``view.txt`` for details on the widgets view, and ``supermodel.txt`` for
        information on the ``form`` XML namespace in a `plone.supermodel`_ schema
        file.
        
        .. _z3c.form: http://pypi.python.org/pypi/z3c.form
        .. _plone.z3cform: http://pypi.python.org/pypi/plone.z3cform
        .. _plone.supermodel: http://pypi.python.org/pypi/plone.supermodel
        .. _plone.directives.form: http://pypi.python.org/pypi/plone.directives.form
        
        ==================
        Form setup details
        ==================
        
        This package provides tools to construct z3c.form forms out of hints stored
        in tagged values on schema interfaces. A special form base class is used to
        set up the 'fields' and 'groups' properties on form instances.
        
        The tagged values are stored under keys represented by the following 
        constants:
        
            >>> from plone.autoform.interfaces import OMITTED_KEY
            >>> from plone.autoform.interfaces import WIDGETS_KEY
            >>> from plone.autoform.interfaces import MODES_KEY
            >>> from plone.autoform.interfaces import ORDER_KEY
            >>> from plone.autoform.interfaces import READ_PERMISSIONS_KEY
            >>> from plone.autoform.interfaces import WRITE_PERMISSIONS_KEY
        
        In addition, field groups are constructed from plone.supermodel fieldsets,
        which are also stored in tagged values, under the following constant:
        
            >>> from plone.supermodel.interfaces import FIELDSETS_KEY
        
        There are several ways to set the form data:
        
        * Manually, by using setTaggedValue() on an interface.
        * By loading the schema from a plone.supermodel XML file. This package
          provides a schema handler for the 'form' prefix that can be used to
          incorporate form hints. See supermodel.txt for details.
        * By using the grok directives in the plone.directives.form package.
            
        For the purposes of this test, we'll set the form data manually.
        
        Test setup
        ----------
        
        First, let's load this package's ZCML so that we can run the tests:
            >>> configuration = """\
            ... <configure xmlns="http://namespaces.zope.org/zope">
            ...
            ...     <include package="Products.Five" file="configure.zcml" />
            ...     <include package="plone.autoform" />
            ...
            ... </configure>
            ... """
            >>> from StringIO import StringIO
            >>> from zope.configuration import xmlconfig
            >>> xmlconfig.xmlconfig(StringIO(configuration))
        
        We also need a few sample interfaces:
        
            >>> from zope.interface import Interface
            >>> from zope import schema
        
            >>> class ITestSchema(Interface):
            ...     one = schema.TextLine(title=u"One")
            ...     two = schema.TextLine(title=u"Two")
            ...     three = schema.TextLine(title=u"Three")
            ...     four = schema.TextLine(title=u"Four")
            ...     five = schema.TextLine(title=u"Five")
            ...     six = schema.TextLine(title=u"Six")
        
            >>> class ISupplementarySchema(Interface):
            ...     one = schema.TextLine(title=u"One")
            ...     two = schema.TextLine(title=u"Two")
        
            >>> class IOtherSchema(Interface):
            ...     three = schema.TextLine(title=u"Three")
            ...     four = schema.TextLine(title=u"Four")
            ...     five = schema.TextLine(title=u"Five")
            ...     six = schema.TextLine(title=u"Six")
        
        And a test context and request, marked with the ``IFormLayer`` interface to
        make z3c.form happy:
        
            >>> from zope.publisher.browser import TestRequest
            >>> from z3c.form.interfaces import IFormLayer
            >>> context = object()
            >>> request = TestRequest(environ={'AUTHENTICATED_USER': 'user1'}, skin=IFormLayer)
        
        Note that we need to pretend that we have authenticated a user. Without this,
        the permission checks will be turned off. This is to support setting up a form
        pre-traversal in the ++widget++ namespace in plone.z3cform.
        
        And finally, a form:
        
            >>> from z3c.form.interfaces import IForm, IEditForm
            >>> from plone.autoform.form import AutoExtensibleForm
            >>> from z3c.form import form, button
            >>> class TestForm(AutoExtensibleForm, form.Form):
            ...     schema = ITestSchema
            ...     additionalSchemata = (ISupplementarySchema, IOtherSchema,)
            ...     
            ...     ignoreContext = True
        
        This form is in input mode:
        
            >>> TestForm.mode
            'input'
        
        Adding form data
        ----------------
        
        Form data can be held under the following keys:
        
            OMITTED_KEY -- A list of (interface, fieldName, boolean) triples. If the
                third value evaluates to true, the field with the given fieldName will
                be omitted from forms providing the given interface.
            
            MODES_KEY -- A list of (interface, fieldName, mode string) triples. A mode
                string may be one of the z3c.form widget modes, including 'hidden',
                'input', and 'display'.  The field will be rendered using a widget in
                the specified mode on forms providing the given interface.
            
            WIDGETS_KEY -- A dict of fieldName => widget. The widget can be
                the dotted name of a z3c.form field widget factory, or an actual
                instance of one.
                
            ORDER_KEY -- A list of (fieldName, direction, relative_to) triples.
                direction can be one of 'before' or 'after'. relative_to can be '*'
                (any/all fields), or the name of a field to move the given field 
                before or after in the form.
            
            READ_PERMISSIONS_KEY -- A dict of fieldName => permission id. When a 
                form is in 'display' mode, the field will be omitted unless the user
                has the given permission in the form's context. The permission id
                should be a Zope 3 style IPermission utility name, not a Zope 2
                permission string.
        
            WRITE_PERMISSIONS_KEY -- A dict of fieldName => permission id. When a 
                form is in 'input' mode, the field will be omitted unless the user
                has the given permission in the form's context. The permission id
                should be a Zope 3 style IPermission utility name, not a Zope 2
                permission string.
        
        Note that 'order' directives are processed after all schemata in the form are
        set up. Ordering will start by going through the additionalSchemata in order.
        The form's base schema is processed last.
        
        This means that the last ordering directive to be run is the last item in the
        list in the form's base schema. Hence, this can be used to override any
        ordering information from additional schemata.
        
        The fieldName should never contain a prefix or a dot. However, the
        relative_to name under ORDER_KEY should contain a prefixed name. The default
        form schema will not have a prefix, but additional schemata will have a prefix
        constructed from their ``__identifier__`` (full dotted name). To explicitly
        reference a field in the current schema (or a base schema), use a leading
        dot, e.g. ".title" would refer to the "title" field in the current schema,
        whereas "title" would refer to the "title" field in the form's base schema.
        
        Fieldset data is kept under the key defined in the constant ``FIELDSETS_KEY``.
        This contains a list of ``plone.supermodel.model.Fieldset`` instances.
        
        At this point, there is no form data. When the form is updated, the 'fields'
        and 'groups' properties will be set.
        
            >>> test_form = TestForm(context, request)
            >>> test_form.update()
            >>> test_form.fields.keys()
            ['one', 'two', 'three', 'four', 'five', 'six',
             'ISupplementarySchema.one', 'ISupplementarySchema.two',
             'IOtherSchema.three', 'IOtherSchema.four', 'IOtherSchema.five', 'IOtherSchema.six']
            >>> test_form.groups
            ()
        
        Note how we have all the fields from all the schemata, and that the fields
        from the additional schemata have been prefixed with the schema dotted name.
        
        Let us now set up some form data.
        
        Omitted fields are listed like this:
        
            >>> ITestSchema.setTaggedValue(OMITTED_KEY,
            ...                            ((IForm, 'four', True),
            ...                             (Interface, 'four', False),
            ...                             (Interface, 'five', False),
            ...                             (Interface, 'five', True))
            ...                           )
        
        Field modes can be set like this:
        
            >>> ITestSchema.setTaggedValue(MODES_KEY,
            ...                            ((Interface, 'one', 'display'),
            ...                             (IEditForm, 'one', 'display'),
            ...                             (IForm, 'one', 'hidden'),
            ...                             (Interface, 'two', 'display'))
            ...                           )
        
        Widgets can be specified either by a dotted name string or an actual instance:
        
            >>> from z3c.form.browser.password import PasswordFieldWidget
            >>> ITestSchema.setTaggedValue(WIDGETS_KEY, {'two': PasswordFieldWidget})
            >>> IOtherSchema.setTaggedValue(WIDGETS_KEY, {'five': 'z3c.form.browser.password.PasswordFieldWidget'})
        
        Fields can be moved like this:
        
            >>> IOtherSchema.setTaggedValue(ORDER_KEY, [('four', 'before', 'ISupplementarySchema.one'),
            ...                                         ('five', 'after', '.six',)])
        
            >>> ISupplementarySchema.setTaggedValue(ORDER_KEY, [('one', 'before', '*'),
            ...                                                 ('two', 'before', 'one')])
        
            >>> ITestSchema.setTaggedValue(ORDER_KEY,          [('one', 'after', 'two')])
        
        Note how the second value of each tuple refers to the full name with a prefix,
        so the field 'two' from ``ISupplementarySchema`` is moved before the field
        'one' from the default (un-prefixed) ITestSchema. However, we move
        ``IOtherSchema``'s field 'five' after the field 'six' in the same schema by
        using a shortcut: '.six' is equivalent to 'IOtherSchema.six' in this case.
        
        Field permissions can be set like this:
        
            >>> ITestSchema.setTaggedValue(WRITE_PERMISSIONS_KEY, { 'five': u'dummy.PermissionOne',
            ...                                                      'six': u'five.ManageSite'})
        
        Note that if a permission is not found, the field will be allowed.
        
        Finally, fieldsets are configured like this:
        
            >>> from plone.supermodel.model import Fieldset
            >>> ITestSchema.setTaggedValue(FIELDSETS_KEY, 
            ...                                 [Fieldset('fieldset1', fields=['three'],
            ...                                           label=u"Fieldset one",
            ...                                           description=u"Description of fieldset one")])
            >>> IOtherSchema.setTaggedValue(FIELDSETS_KEY, [Fieldset('fieldset1', fields=['three'])])
        
        Note how the label/description need only be specified once.
        
        The results of all of this can be seen below:
        
            >>> test_form = TestForm(context, request)
            >>> test_form.update()
            >>> test_form.fields.keys()
            ['IOtherSchema.four',
             'ISupplementarySchema.one',
             'ISupplementarySchema.two',
             'two',
             'one',
             'five',
             'IOtherSchema.six',
             'IOtherSchema.five']
        
        The field ``ISupplementarySchema['one']`` was moved to the top of the form,
        but then ``IOtherSchema['four']`` was moved before this one again.
        ``ITestSchema['one']`` was moved after ``ITestSchema['two']``.
        ``ISupplementarySchema['two']`` was then moved before ``ITestSchema['one']``,
        coming between ``ITestSchema['one']`` and ``ITestSchema['two']``.
        
        ``ITestSchema['one']`` was hidden and ``ITestSchema['two']`` was put into
        display mode:
        
            >>> test_form.widgets['one'].mode
            'hidden'
            >>> test_form.widgets['two'].mode
            'display'
        
        ``ITestSchema['two']`` and ``IOtherSchema['five']`` were both given a password
        widget - one by instance, the other by dotted name:
        
            >>> test_form.widgets['two']
            <PasswordWidget 'form.widgets.two'>
        
            >>> test_form.widgets['IOtherSchema.five']
            <PasswordWidget 'form.widgets.IOtherSchema.five'>
        
        There is one group corresponding to the fieldset where we put two fields. It
        has taken the label and description from the first definition.
        
            >>> len(test_form.groups)
            1
            >>> test_form.groups[0].label
            u'Fieldset one'
            >>> test_form.groups[0].description
            u'Description of fieldset one'
            >>> test_form.groups[0].fields.keys()
            ['three', 'IOtherSchema.three']
        
        Pre-traversal
        -------------
        
        plone.z3cform installs a ``++widget++`` namespace to allow traversal to
        widgets. Unfortunately, traversal happens before authentication. Thus, all
        security checks (read/write permissions) will fail.
        
        To work around this, we ignore security checks if no authenticated user is
        set in the request. Previously, we added one to the test request. If we
        run the same tests without an authenticated user, the field 'six' should
        return.
        
            >>> request = TestRequest(skin=IFormLayer)
        
            >>> test_form = TestForm(context, request)
            >>> test_form.update()
            >>> test_form.fields.keys()
            ['IOtherSchema.four',
             'ISupplementarySchema.one',
             'ISupplementarySchema.two',
             'two',
             'one',
             'five',
             'six',
             'IOtherSchema.six',
             'IOtherSchema.five']
        
        Automatic field sets
        --------------------
        
        It is possible to create fieldsets automatically, on the principle of one
        fieldset per schema. In this case, the fieldset name is the schema name,
        the schema docstring becomes the schema description, and all fields in that
        schema that are not explicitly assigned to another fieldset, will be in the
        the per-schema fieldset.
        
            >>> class Basics(Interface):
            ...     """Basic metadata"""
            ...     title = schema.TextLine(title=u"Title")
            ...     description = schema.TextLine(title=u"Description")
            ...     creation_date = schema.Date(title=u"Creation date")
            ...     hidden_secret = schema.TextLine(title=u"Hidden secret!")
        
        Let's change some field settings to ensure that they are still processed,
        and move the creation_date field to another fieldset, which we will define
        in full.
        
            >>> Basics.setTaggedValue(MODES_KEY, [(Interface, 'hidden_secret', 'hidden')])
            >>> Basics.setTaggedValue(FIELDSETS_KEY, [Fieldset('Dates', label="Cool dates", fields=['creation_date'])])
            
            >>> class Dates(Interface):
            ...     """Date information"""
            ...     start_date = schema.Date(title=u"Start date")
            ...     end_date = schema.Date(title=u"End date")
            
            >>> class Ownership(Interface):
            ...     """Ownership information"""
            ...     owner = schema.Date(title=u"The owner")
        
        We can make a form of these schemata. For the sake of this demo, we'll also
        set ``ignorePrefix`` to true, so that the form fields don't get a prefix. Note
        that this may cause clashes if fields in different schemata share a name.
        
            >>> class CombiForm(AutoExtensibleForm, form.Form):
            ...     schema = Basics
            ...     additionalSchemata = (Dates, Ownership,)
            ...     
            ...     ignoreContext = True
            ...     ignorePrefix = True
            ...     autoGroups = True
        
            >>> combi_form = CombiForm(context, request)
            >>> combi_form.update()
        
        The default fields are those from the base schema, minus the one moved to
        another fieldset.
        
            >>> combi_form.fields.keys()
            ['title', 'description', 'hidden_secret']
            
            >>> combi_form.widgets['hidden_secret'].mode
            'hidden'
            
        Each additional schema then has its own fields. Note that setting the 'dates'
        fieldset in the base schema had the effect of giving a more specific
        label to the automatically created group for the Dates schema.
            
            >>> [(g.__name__, g.label, g.description, g.fields.keys(),) for g in combi_form.groups]
            [('Dates', 'Cool dates', None, ['creation_date', 'start_date', 'end_date']),
             ('Ownership', 'Ownership', 'Ownership information', ['owner'])]
        
        ==================
        Widget-aware views
        ==================
        
        This package provides a view mixin class that can be used like a display form.
        The view is set up with widgets based on schema interfaces and/or form fields,
        and are available in 'display' mode.
        
        First, let's load this package's ZCML so that we can run the tests:
        
            >>> configuration = """\
            ... <configure xmlns="http://namespaces.zope.org/zope">
            ...
            ...     <include package="Products.Five" file="configure.zcml" />
            ...     <include package="plone.autoform" />
            ...     
            ... </configure>
            ... """
            >>> from StringIO import StringIO
            >>> from zope.configuration import xmlconfig
            >>> xmlconfig.xmlconfig(StringIO(configuration))
        
        As with auto-forms, the widgets come from a primary schema interface, and
        optionally one or more secondary interfaces. Let's define two.
        
            >>> from zope.interface import Interface
            >>> from zope import schema
            >>> class IDefaultSchema(Interface):
            ...     title = schema.TextLine(title=u"Title")
            ...     body = schema.Text(title=u"Body")
        
            >>> class ISecondarySchema(Interface):
            ...     summary = schema.Text(title=u"Summary")
        
        Let us also annotate these with some field hints, putting 'summary' into a
        secondary schema.
        
            >>> from plone.supermodel.interfaces import FIELDSETS_KEY
            >>> from plone.supermodel.model import Fieldset
            >>> ISecondarySchema.setTaggedValue(FIELDSETS_KEY, [Fieldset('secondary', fields=['summary'])])
        
        A display form normally operates on a given context, although you could set
        ``ignoreContext = True`` and/or implement ``getContent()`` if applicable. The
        schema interfaces need to be provided by or adaptable from the context. For
        the purposes of this test, we'll just make them directly provided.
        
            >>> from zope.interface import implements
            >>> class Context(object):
            ...     implements(IDefaultSchema, ISecondarySchema)
            ...     title = u""
            ...     body = u""
            ...     summary = u""
        
        We can now define a display form view. This should sub class or mix in
        WidgetsView. It must define either an ``index`` callable (usually a page
        template set by the ``<browser:page />`` directive) or override the ``render``
        method. It should also set the ``schema`` and ``additionalSchemata`` properties
        as required, using class variables, instance variables or properties.
        
            >>> from plone.autoform.view import WidgetsView
            >>> class TestView(WidgetsView):
            ...     schema = IDefaultSchema
            ...     additionalSchemata = (ISecondarySchema,)
            ...     def render(self):
            ...         return u"<div>My title widget says %s</div>" % self.w['title'].render()
        
        Let us try to render this, to demonstrate that the widgets will be properly
        set up.
        
            >>> from z3c.form.testing import TestRequest
            >>> context = Context()
            >>> request = TestRequest()
        
            >>> context.title = u"Test title"
            >>> context.body = u"Body"
            >>> context.summary = u"Summary"
        
            >>> view = TestView(context, request)
            >>> print view()
            <div>My title widget says <span id="form-widgets-title"
                  class="text-widget required textline-field">Test title</span>
            </div>
        
        More generally, the view supports the contract of display forms. After being
        updated, we have access to widgets in the default fieldset:
        
            >>> view.widgets.items()
            [('title', <TextWidget 'form.widgets.title'>),
             ('body', <TextAreaWidget 'form.widgets.body'>)]
        
        There is also a shortcut to allow access to any widget by (possibly prefixed)
        name:
        
            >>> view.w.items()
            [('body', <TextAreaWidget 'form.widgets.body'>), 
             ('ISecondarySchema.summary', <TextAreaWidget 'form.widgets.ISecondarySchema.summary'>), 
             ('title', <TextWidget 'form.widgets.title'>)]
        
        You can also see fieldsets (groups) either in order:
        
            >>> view.groups
            (<plone.z3cform.fieldsets.group.Group object at ...>,)
        
        or looked up by name:
        
            >>> view.fieldsets.items()
            [('secondary', <plone.z3cform.fieldsets.group.Group object at ...>)]
        
        Note how the schema name is used as a prefix to all additional schemata. If
        you wish to flatten the namespace, you can set ignorePrefix to true:
        
            >>> view = TestView(context, request)
            >>> view.ignorePrefix = True
            >>> view.update()
            >>> view.w.items()
            [('body', <TextAreaWidget 'form.widgets.body'>), 
             ('summary', <TextAreaWidget 'form.widgets.summary'>), 
             ('title', <TextWidget 'form.widgets.title'>)]
        
        For supporting widget traversal it is necessary that after updating
        the form the widgets are present:
        
            >>> view2 = TestView(context, request)
            >>> view2.update()
            >>> view2.widgets
            <z3c.form.field.FieldWidgets object at ...>
            >>> view2.widgets.keys()
            ['title', 'body']
        
        ===================
        Supermodel handlers
        ===================
        
        This package contains handlers for two plone.supermodel namespaces: ``form``,
        which can be used to set widgets, omitted fields, field modes and field
        order, and ``security``, which can be used to set field read and write
        permissions.
        
        Test setup
        ----------
        
        First, let's load this package's ZCML so that we can run the tests:
        
            >>> configuration = """\
            ... <configure xmlns="http://namespaces.zope.org/zope">
            ...
            ...     <include package="Products.Five" file="configure.zcml" />
            ...     <include package="plone.autoform" />
            ...     
            ... </configure>
            ... """
            >>> from StringIO import StringIO
            >>> from zope.configuration import xmlconfig
            >>> xmlconfig.xmlconfig(StringIO(configuration))
        
        XML sample
        ----------
        
        Next, let's define a sample model that exercises the various ``form`` and
        ``security`` attributes.
        
            >>> schema = """\
            ... <?xml version="1.0" encoding="UTF-8"?>
            ... <model xmlns="http://namespaces.plone.org/supermodel/schema"
            ...        xmlns:form="http://namespaces.plone.org/supermodel/form"
            ...        xmlns:security="http://namespaces.plone.org/supermodel/security">
            ...     <schema>
            ...         <field type="zope.schema.TextLine" name="one"
            ...                 form:omitted="true"
            ...                 form:after="two"
            ...                 security:read-permission="zope2.View"
            ...                 security:write-permission="cmf.ModifyPortalContent">
            ...             <title>One</title>
            ...         </field>
            ...         <field type="zope.schema.TextLine" name="two"
            ...                form:mode="hidden">
            ...             <title>Two</title>
            ...         </field>
            ...         <field type="zope.schema.TextLine" name="three"
            ...                 form:before="two"
            ...                 form:widget="z3c.form.browser.password.PasswordFieldWidget"
            ...                 form:validator="plone.autoform.tests.test_utils.TestValidator"
            ...                 form:omitted="z3c.form.interfaces.IForm:true z3c.form.interfaces.IEditForm:false"
            ...                 form:mode="z3c.form.interfaces.IEditForm:input">
            ...             <title>Three</title>
            ...         </field>
            ...     </schema>
            ... </model>
            ... """
        
        Notes:
        
        * To omit a field from all forms, use ``form:omitted="true"``.  To omit a field
          only from some forms, specify a form interface like
          ``form:omitted="z3c.form.interfaces.IForm:true"``. Multiple interface:value
          settings may be specified, separated by spaces.
        * To re-order fields, use ``form:after`` or ``form:before``. The value should
          be either ``'*'``, to put the field first/last in the form, or the name of a
          another field. Use ``'.fieldname'`` to refer to field in the current schema
          (or a base schema). Use a fully prefixed name (e.g.
          ``'my.package.ISomeSchema'``) to refer to a field in another schema. Use an
          unprefixed name to refer to a field in the default schema for the form.
        * To turn a field into a view mode or hidden field, use ``form:mode``.  The
          mode may be set for only some forms by specifying a form interface in the
          same manner as for ``form:omitted``.
        * To set a custom widget for a field, use ``form:widget`` to give a fully
          qualified name to the field widget factory.
        * To set a custom validator for a field, use ``form:validator`` to give a fully
          qualified name to the field validator factory.
        * To set a read or write permission, use ``security:read-permission`` or
          ``security:write-permission``. The value should be the name of an 
          ``IPermission`` utility.
        
        We can load this using plone.supermodel:
        
            >>> from plone.supermodel import loadString
            >>> model = loadString(schema)
        
        The interface defined in the model should now have the relevant form data:
        
            >>> from plone.autoform.interfaces import OMITTED_KEY, WIDGETS_KEY, \
            ...     MODES_KEY, ORDER_KEY, READ_PERMISSIONS_KEY, WRITE_PERMISSIONS_KEY
            >>> model.schema.getTaggedValue(WIDGETS_KEY)
            {'three': 'z3c.form.browser.password.PasswordFieldWidget'}
            >>> model.schema.getTaggedValue(OMITTED_KEY)
            [(<InterfaceClass zope.interface.Interface>, 'one', 'true'), (<InterfaceClass z3c.form.interfaces.IForm>, 'three', 'true'), (<InterfaceClass z3c.form.interfaces.IEditForm>, 'three', 'false')]
            >>> model.schema.getTaggedValue(ORDER_KEY)
            [('one', 'after', 'two'), ('three', 'before', 'two')]
            >>> model.schema.getTaggedValue(MODES_KEY)
            [(<InterfaceClass z3c.form.interfaces.IEditForm>, 'three', 'input'), (<InterfaceClass zope.interface.Interface>, 'two', 'hidden')]
            >>> model.schema.getTaggedValue(READ_PERMISSIONS_KEY)
            {'one': 'zope2.View'}
            >>> model.schema.getTaggedValue(WRITE_PERMISSIONS_KEY)
            {'one': 'cmf.ModifyPortalContent'}
        
        See autoform.txt for details on how this form data is used to manipulate
        form layout.
        
        Form directives
        ---------------
        
        In addition to using XML, the tagged values used to control autoform's behavior
        can instead be set up using "directives" called while defining a schema in
        Python.
        
        Below is an example that exercises the various directives::
        
            from z3c.form.interfaces import IEditForm
            from plone.supermodel import model
            from plone.autoform import directives as form
            from plone.app.z3cform.wysiwyg import WysiwygFieldWidget
        
            class IMySchema(model.Schema):
            
                # Add a new fieldset and put the 'footer' and 'dummy' fields in it.
                # If the same fieldset is defined multiple times, the definitions
                # will be merged, with the label from the first fieldset taking
                # precedence.
                
                model.fieldset('extra', 
                        label=u"Extra info",
                        fields=['footer', 'dummy']
                    )
                
                title = schema.TextLine(
                        title=u"Title"
                    )
                
                summary = schema.Text(
                        title=u"Summary",
                        description=u"Summary of the body",
                        readonly=True
                    )
                
                form.widget(body='plone.app.z3cform.wysiwyg.WysiwygFieldWidget')
                model.primary('body')
                body = schema.Text(
                        title=u"Body text",
                        required=False,
                        default=u"Body text goes here"
                    )
                
                
                form.widget(footer=WysiwygFieldWidget)
                footer = schema.Text(
                        title=u"Footer text",
                        required=False
                    )
                
                form.omitted('dummy')
                dummy = schema.Text(
                        title=u"Dummy"
                    )
                
                form.omitted('edit_only')
                form.no_omit(IEditForm, 'edit_only')
                edit_only = schema.TextLine(
                        title = u'Only included on edit forms',
                    )
                
                form.mode(secret='hidden')
                form.mode(IEditForm, secret='input')
                secret = schema.TextLine(
                        title=u"Secret",
                        default=u"Secret stuff (except on edit forms)"
                    )
                
                form.order_before(not_last='summary')
                not_last = schema.TextLine(
                        title=u"Not last",
                    )
                
        
        Here, we have placed the directives immediately before the fields they
        affect, but they could be placed anywhere in the interface body. All the
        directives can take multiple values, usually in the form
        ``fieldname='value'``.
        
        The ``omitted()``, ``no_omit``, and ``primary()`` directives take a list of
        field names instead. The ``widget()`` directive allows widgets to be set either
        as a dotted name, or using an imported field widget factory. The
        ``order_before()`` directive has a  corresponding ``order_after()`` directive.
        
        Changelog
        =========
        
        1.2 (2012-04-15)
        ----------------
        
        - Moved form schema directives here from plone.directives.form, and
          reimplemented them as plone.supermodel directives to avoid depending on
          grok.  Included directives: omitted, no_omit, mode, widget, order_before,
          order_after, read_permission, write_permission
          [davisagli]
        
        1.1 - 2012-02-20
        ----------------
        
        - Added the AutoObjectSubForm class to support form hints for
          object widget subforms.
          [jcbrand]
        
        1.0 - 2011-05-13
        ----------------
        
        - Raise a NotImplementedError instead of NotImplemented as that is not
          an exception but meant for comparisons and is not callable.
          [maurits]
        
        
        1.0b7 - 2011-04-29
        ------------------
        
        - Check to make sure that interfaces and field widgets resolved by the
          supermodel handler are of the correct type.
          [elro]
        
        - Add form:validator support for supermodel.
          [elro]
        
        - Fix issue where permission checks were not applied correctly to schemas being
          added with prefixes.
          [davisagli]
        
        - Add MANIFEST.in.
          [WouterVH]
        
        
        1.0b6 - 2011-02-11
        ------------------
        
        - Fix WidgetsView so that _update and update do not clash.
          [elro]
        
        - Fix view.txt doctest to test actual behaviour, not artifacts from test setup.
          [elro]
        
        
        1.0b5 - 2011-01-11
        ------------------
        
        - Use five.ManageSite permission to check field permissions. We'll avoid
          sniffing for Five/CMFCore permissions.zcml difference between Zope 2.12 and
          2.13. [esteele]
        
        
        1.0b4 - 2010-08-05
        ------------------
        
        - Fixed widget traversal for WidgetsView
          http://groups.google.com/group/dexterity-development/browse_frm/thread/280016ece3ed1462
          [29.08.2010, jbaumann]
        
        - Make field permission checks use the field mode rather than the form mode.
          Fixes http://code.google.com/p/dexterity/issues/detail?id=110
          [optilude]
        
        - Removed some dead code.
          Fixes http://code.google.com/p/dexterity/issues/detail?id=132
          [optilude, shywolf9982]
        
        
        1.0b3 - 2010-04-20
        ------------------
        
        - Properly handle the 'omitted' tagged value when it is set to 'false' for a
          field.
          [davisagli]
        
        - Make it possible to set the 'omitted' and 'mode' settings only for particular
          form interfaces.
          [davisagli]
        
        - Do not omit read-only fields when rendering a form in DISPLAY mode.
          http://code.google.com/p/dexterity/issues/detail?id=118
          [mj]
        
        
        1.0b2 - 2009-07-12
        ------------------
        
        - Changed API methods and arguments to mixedCase to be more consistent with
          the rest of Zope. This is a non-backwards-compatible change. Our profuse
          apologies, but it's now or never. :-/
        
          If you find that you get import errors or unknown keyword arguments in your
          code, please change names from foo_bar too fooBar, e.g. process_fields()
          becomes processFields().
        
          Note in particular that the additional_schemata property is now called 
          additionalSchemata. If you have implemented this property yourself, you will
          need to rename it!
          [optilude]
        
        
        1.0b1 - 2009-04-17
        ------------------
        
        - Initial release
        
        
Keywords: plone form z3c.form
Platform: UNKNOWN
Classifier: Framework :: Plone
Classifier: Programming Language :: Python
Classifier: Topic :: Software Development :: Libraries :: Python Modules
