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()

We need a test context and request, marked with the ``IFormLayer`` interface to
make z3c.form happy:

    >>> from zope.publisher.browser import TestRequest
    >>> from z3c.form import interfaces
    >>> context = Context()
    >>> request = TestRequest(environ={'AUTHENTICATED_USER': 'user1'}, skin=interfaces.IFormLayer)

Let us try to render this, to demonstrate that the widgets will be properly
set up.

    >>> 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 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']
