============
ObjectWidget
============

The `ObjectWidget` widget is about rendering a schema's fields as a single
widget.

There are way too many preconditions to exercise the `ObjectWidget` as it
relies heavily on the from and widget framework. It renders the sub-widgets in
a sub-form.

In order to not overwhelm you with our set of well-chosen defaults,
all the default component registrations have been made prior to doing those
examples:

  >>> from z3c.form import testing
  >>> testing.setupFormDefaults()

  >>> import zope.component

  >>> from z3c.form import datamanager
  >>> zope.component.provideAdapter(datamanager.DictionaryField)


  >>> from z3c.form.testing import IMySubObject
  >>> from z3c.form.testing import IMySecond
  >>> from z3c.form.testing import MySubObject
  >>> from z3c.form.testing import MySecond

  >>> import z3c.form.object
  >>> zope.component.provideAdapter(z3c.form.object.SubformAdapter)
  >>> zope.component.provideAdapter(z3c.form.object.ObjectConverter)

  >>> from z3c.form.error import MultipleErrorViewSnippet
  >>> zope.component.provideAdapter(MultipleErrorViewSnippet)

As for all widgets, the objectwidget must provide the new `IWidget`
interface:

  >>> from zope.interface.verify import verifyClass
  >>> from z3c.form import interfaces
  >>> import z3c.form.browser.object

  >>> verifyClass(interfaces.IWidget, z3c.form.browser.object.ObjectWidget)
  True

The widget can be instantiated only using the request:

  >>> from z3c.form.testing import TestRequest
  >>> request = TestRequest()
  >>> widget = z3c.form.browser.object.ObjectWidget(request)

Before rendering the widget, one has to set the name and id of the widget:

  >>> widget.id = 'widget-id'
  >>> widget.name = 'widget.name'

Also, stand-alone widgets need to ignore the context:

  >>> widget.ignoreContext = True

There is no life for ObjectWidget without a schema to render:

  >>> widget.update()
  Traceback (most recent call last):
  ...
  ValueError: <ObjectWidget 'widget.name'> .field is None,
              that's a blocking point

This schema is specified by the field:

  >>> from z3c.form.widget import FieldWidget
  >>> from z3c.form.testing import IMySubObject
  >>> import zope.schema
  >>> field = zope.schema.Object(
  ...     __name__='subobject',
  ...     title=u'my object widget',
  ...     schema=IMySubObject)

Apply the field nicely with the helper:

  >>> widget = FieldWidget(field, widget)

We also need to register the templates for the widget and request:

  >>> import zope.component
  >>> from zope.pagetemplate.interfaces import IPageTemplate
  >>> from z3c.form.testing import getPath
  >>> from z3c.form.widget import WidgetTemplateFactory

  >>> zope.component.provideAdapter(
  ...     WidgetTemplateFactory(getPath('object_input.pt'), 'text/html'),
  ...     (None, None, None, None, interfaces.IObjectWidget),
  ...     IPageTemplate, name=interfaces.INPUT_MODE)

  >>> zope.component.provideAdapter(
  ...     WidgetTemplateFactory(getPath('object_display.pt'), 'text/html'),
  ...     (None, None, None, None, interfaces.IObjectWidget),
  ...     IPageTemplate, name=interfaces.DISPLAY_MODE)

We can now render the widget:

  >>> widget.update()
  >>> print(widget.render())
  <html>
    <body>
      <div class="object-widget required">
        <div class="label">
          <label for="subobject-widgets-foofield">
            <span>My foo field</span>
            <span class="required">*</span>
          </label>
        </div>
        <div class="widget">
          <input class="text-widget required int-field"
          id="subobject-widgets-foofield"
          name="subobject.widgets.foofield"
          type="text" value="1,111">
        </div>
        <div class="label">
          <label for="subobject-widgets-barfield">
            <span>My dear bar</span>
          </label>
        </div>
        <div class="widget">
          <input class="text-widget int-field"
          id="subobject-widgets-barfield"
          name="subobject.widgets.barfield"
          type="text" value="2,222">
        </div>
        <input name="subobject-empty-marker" type="hidden" value="1">
      </div>
    </body>
  </html>


As you see all sort of default values are rendered.

Let's provide a more meaningful value:

  >>> from z3c.form.testing import MySubObject
  >>> v = MySubObject()
  >>> v.foofield = 42
  >>> v.barfield = 666
  >>> v.__marker__ = "ThisMustStayTheSame"


  >>> widget.ignoreContext = False
  >>> widget.value = dict(foofield=42, barfield=666)

  >>> widget.update()

  >>> print(widget.render())
  <html>
    <body>
      <div class="object-widget required">
        <div class="label">
          <label for="subobject-widgets-foofield">
            <span>My foo field</span>
            <span class="required">*</span>
          </label>
        </div>
        <div class="widget">
          <input class="text-widget required int-field"
          id="subobject-widgets-foofield"
          name="subobject.widgets.foofield"
          type="text" value="42">
        </div>
        <div class="label">
          <label for="subobject-widgets-barfield">
            <span>My dear bar</span>
          </label>
        </div>
        <div class="widget">
          <input class="text-widget int-field"
          id="subobject-widgets-barfield"
          name="subobject.widgets.barfield"
          type="text" value="666">
        </div>
        <input name="subobject-empty-marker" type="hidden" value="1">
      </div>
    </body>
  </html>

The widget's value is NO_VALUE until it gets a request:

  >>> widget.value
  <NO_VALUE>

Let's fill in some values via the request:

  >>> widget.request = TestRequest(form={'subobject.widgets.foofield':u'2',
  ...                                    'subobject.widgets.barfield':u'999',
  ...                                    'subobject-empty-marker':u'1'})
  >>> widget.update()
  >>> print(widget.render())
  <html>
    <body>
      <div class="object-widget required">
        <div class="label">
          <label for="subobject-widgets-foofield">
            <span>My foo field</span>
            <span class="required">*</span>
          </label>
        </div>
        <div class="widget">
          <input class="text-widget required int-field"
          id="subobject-widgets-foofield"
          name="subobject.widgets.foofield"
          type="text" value="2">
        </div>
        <div class="label">
          <label for="subobject-widgets-barfield">
            <span>My dear bar</span>
          </label>
        </div>
        <div class="widget">
          <input class="text-widget int-field"
          id="subobject-widgets-barfield"
          name="subobject.widgets.barfield"
          type="text" value="999">
        </div>
        <input name="subobject-empty-marker" type="hidden" value="1">
      </div>
    </body>
  </html>

Widget value comes from the request:

  >>> wv = widget.value
  >>> pprint(wv)
  {'barfield': 999, 'foofield': 2}

But our object will not be modified, since there was no "apply"-like control.

  >>> v
  <z3c.form.testing.MySubObject object at ...>
  >>> v.foofield
  42
  >>> v.barfield
  666

The marker must stay (we have to modify the same object):

  >>> v.__marker__
  'ThisMustStayTheSame'


  >>> converter = interfaces.IDataConverter(widget)

  >>> value = converter.toFieldValue(wv)
  Traceback (most recent call last):
  ...
  ValueError: No IObjectFactory adapter registered for z3c.form.testing.IMySubObject

We have to register object factory adapters to allow the objectwidget to
create objects:

  >>> from z3c.form.object import registerFactoryAdapter
  >>> registerFactoryAdapter(IMySubObject, MySubObject)
  >>> registerFactoryAdapter(IMySecond, MySecond)

  >>> value = converter.toFieldValue(wv)
  >>> value
  <z3c.form.testing.MySubObject object at ...>
  >>> value.foofield
  2
  >>> value.barfield
  999

This is a different object:

  >>> value.__marker__
  Traceback (most recent call last):
  ...
  AttributeError: 'MySubObject' object has no attribute '__marker__'


Setting missing values on the widget works too:

  >>> widget.value = converter.toWidgetValue(field.missing_value)

  >>> widget.update()

Default values get rendered:

  >>> print(widget.render())
  <div class="object-widget required">
    <div class="label">
      <label for="subobject-widgets-foofield">
        <span>My foo field</span>
        <span class="required">*</span>
      </label>
    </div>
    <div class="widget">
      <input id="subobject-widgets-foofield"
             name="subobject.widgets.foofield"
             class="text-widget required int-field" value="2" type="text" />
    </div>
    <div class="label">
      <label for="subobject-widgets-barfield">
        <span>My dear bar</span>
      </label>
    </div>
    <div class="widget">
      <input id="subobject-widgets-barfield"
             name="subobject.widgets.barfield"
             class="text-widget int-field" value="999" type="text" />
    </div>
    <input name="subobject-empty-marker" type="hidden" value="1" />
  </div>

But on the return we get default values back:

  >>> pprint(widget.value)
  {'barfield': 999, 'foofield': 2}

  >>> value = converter.toFieldValue(widget.value)
  >>> value
  <z3c.form.testing.MySubObject object at ...>

HMMMM.... do we have to test error handling here?
I'm tempted to leave it out as no widgets seem to do this.

#Error handling is next. Let's use the value "bad" (an invalid integer literal)
#as input for our internal (sub) widget.
#
#  >>> widget.request = TestRequest(form={'subobject.widgets.foofield':u'55',
#  ...                                    'subobject.widgets.barfield':u'bad',
#  ...                                    'subobject-empty-marker':u'1'})
#
#
#  >>> widget.update()
#  >>> print(widget.render())
#  <html>
#    <body>
#      <div class="object-widget required">
#        <div class="label">
#          <label for="subobject-widgets-foofield">
#            <span>My foo field</span>
#            <span class="required">*</span>
#          </label>
#        </div>
#        <div class="widget">
#          <input class="text-widget required int-field"
#          id="subobject-widgets-foofield"
#          name="subobject.widgets.foofield"
#          type="text" value="55">
#        </div>
#        <div class="label">
#          <label for="subobject-widgets-barfield">
#            <span>My dear bar</span>
#          </label>
#        </div>
#        <div class="error">The entered value is not a valid integer literal.</div>
#        <div class="widget">
#          <input class="text-widget int-field"
#          id="subobject-widgets-barfield"
#          name="subobject.widgets.barfield"
#          type="text" value="bad">
#        </div>
#        <input name="subobject-empty-marker" type="hidden" value="1">
#      </div>
#    </body>
#  </html>
#
#Getting the widget value raises the widget errors:
#
#  >>> widget.value
#  Traceback (most recent call last):
#  ...
#  MultipleErrors
#
#Our object still must retain the old values:
#
#  >>> v
#  <z3c.form.testing.MySubObject object at ...>
#  >>> v.foofield
#  42
#  >>> v.barfield
#  666
#  >>> v.__marker__
#  'ThisMustStayTheSame'



In forms
========

Do all that fun in add and edit forms too:


We have to provide an adapter first:

  >>> zope.component.provideAdapter(z3c.form.browser.object.ObjectFieldWidget)

Forms and our objectwidget fire events on add and edit, setup a subscriber
for those:

  >>> eventlog = []
  >>> import zope.lifecycleevent
  >>> @zope.component.adapter(zope.lifecycleevent.ObjectModifiedEvent)
  ... def logEvent(event):
  ...     eventlog.append(event)
  >>> zope.component.provideHandler(logEvent)
  >>> @zope.component.adapter(zope.lifecycleevent.ObjectCreatedEvent)
  ... def logEvent2(event):
  ...     eventlog.append(event)
  >>> zope.component.provideHandler(logEvent2)

  >>> def printEvents():
  ...     for event in eventlog:
  ...         print(str(event))
  ...         if isinstance(event, zope.lifecycleevent.ObjectModifiedEvent):
  ...             for attr in event.descriptions:
  ...                 print(attr.interface)
  ...                 print(sorted(attr.attributes))

We define an interface containing a subobject, and an addform for it:

  >>> from z3c.form import form, field
  >>> from z3c.form.testing import MyObject, IMyObject

Note, that creating an object will print(some information about it:)

  >>> class MyAddForm(form.AddForm):
  ...     fields = field.Fields(IMyObject)
  ...     def create(self, data):
  ...         print("MyAddForm.create")
  ...         pprint(data)
  ...         return MyObject(**data)
  ...     def add(self, obj):
  ...         self.context[obj.name] = obj
  ...     def nextURL(self):
  ...         pass

We create the form and try to update it:

  >>> request = TestRequest()
  >>> myaddform =  MyAddForm(root, request)


  >>> myaddform.update()

As usual, the form contains a widget manager with the expected widget

  >>> myaddform.widgets.keys()
  ['subobject', 'name']
  >>> myaddform.widgets.values()
  [<ObjectWidget 'form.widgets.subobject'>, <TextWidget 'form.widgets.name'>]

The addform has our ObjectWidget which in turn contains a subform:

  >>> myaddform.widgets['subobject'].subform
  <z3c.form.object.ObjectSubForm object at ...>

Which in turn contains the sub-widgets:

  >>> myaddform.widgets['subobject'].subform.widgets.keys()
  ['foofield', 'barfield']

If we want to render the addform, we must give it a template:

  >>> import os
  >>> from zope.browserpage.viewpagetemplatefile import ViewPageTemplateFile
  >>> from zope.browserpage.viewpagetemplatefile import BoundPageTemplate
  >>> from z3c.form import tests
  >>> def addTemplate(form):
  ...     form.template = BoundPageTemplate(
  ...         ViewPageTemplateFile(
  ...             'simple_edit.pt', os.path.dirname(tests.__file__)), form)
  >>> addTemplate(myaddform)

Now rendering the addform renders the subform as well:

  >>> print(myaddform.render())
  <html xmlns="http://www.w3.org/1999/xhtml">
    <body>
      <form action=".">
        <div class="row">
          <label for="form-widgets-subobject">my object</label>
          <div class="object-widget required">
            <div class="label">
              <label for="form-widgets-subobject-widgets-foofield">
                <span>My foo field</span>
                <span class="required">*</span>
              </label>
            </div>
            <div class="widget">
              <input class="text-widget required int-field"
              id="form-widgets-subobject-widgets-foofield"
              name="form.widgets.subobject.widgets.foofield"
              type="text" value="1,111">
            </div>
            <div class="label">
              <label for="form-widgets-subobject-widgets-barfield">
                <span>My dear bar</span>
              </label>
            </div>
            <div class="widget">
              <input class="text-widget int-field"
              id="form-widgets-subobject-widgets-barfield"
              name="form.widgets.subobject.widgets.barfield"
              type="text" value="2,222">
            </div>
            <input name="form.widgets.subobject-empty-marker" type="hidden"
            value="1">
          </div>
        </div>
        <div class="row">
          <label for="form-widgets-name">name</label>
          <input class="text-widget required textline-field" id="form-widgets-name" name="form.widgets.name" type="text" value="">
        </div>
        <div class="action">
          <input class="submit-widget button-field" id="form-buttons-add"
          name="form.buttons.add" type="submit" value="Add">
        </div>
      </form>
    </body>
  </html>


We don't have the object (yet) in the root:

  >>> root['first']
  Traceback (most recent call last):
  ...
  KeyError: 'first'

Let's try to add an object:

  >>> request = TestRequest(form={
  ...     'form.widgets.subobject.widgets.foofield':u'66',
  ...     'form.widgets.subobject.widgets.barfield':u'99',
  ...     'form.widgets.name':u'first',
  ...     'form.widgets.subobject-empty-marker':u'1',
  ...     'form.buttons.add':'Add'})
  >>> myaddform.request = request

  >>> myaddform.update()
  MyAddForm.create
  {'name': u'first',
   'subobject': <z3c.form.testing.MySubObject object at ...>}

Wow, it got added:

  >>> root['first']
  <z3c.form.testing.MyObject object at ...>

  >>> root['first'].subobject
  <z3c.form.testing.MySubObject object at ...>

Field values need to be right:

  >>> root['first'].subobject.foofield
  66
  >>> root['first'].subobject.barfield
  99

Let's see our event log:

  >>> len(eventlog)
  4

  >>> printEvents()
  <zope...ObjectCreatedEvent object at ...>
  <zope...ObjectModifiedEvent object at ...>
  <InterfaceClass z3c.form.testing.IMySubObject>
  ['barfield', 'foofield']
  <zope...ObjectCreatedEvent object at ...>
  <zope...contained.ContainerModifiedEvent object at ...>


  >>> eventlog=[]

Let's try to edit that newly added object:

  >>> class MyEditForm(form.EditForm):
  ...     fields = field.Fields(IMyObject)

  >>> editform = MyEditForm(root['first'], TestRequest())
  >>> addTemplate(editform)
  >>> editform.update()

Watch for the widget values in the HTML:

  >>> print(editform.render())
  <html xmlns="http://www.w3.org/1999/xhtml">
    <body>
      <form action=".">
        <div class="row">
          <label for="form-widgets-subobject">my object</label>
          <div class="object-widget required">
            <div class="label">
              <label for="form-widgets-subobject-widgets-foofield">
                <span>My foo field</span>
                <span class="required">*</span>
              </label>
            </div>
            <div class="widget">
              <input class="text-widget required int-field"
              id="form-widgets-subobject-widgets-foofield"
              name="form.widgets.subobject.widgets.foofield"
              type="text" value="66">
            </div>
            <div class="label">
              <label for="form-widgets-subobject-widgets-barfield">
                <span>My dear bar</span>
              </label>
            </div>
            <div class="widget">
              <input class="text-widget int-field"
              id="form-widgets-subobject-widgets-barfield"
              name="form.widgets.subobject.widgets.barfield"
              type="text" value="99">
            </div>
            <input name="form.widgets.subobject-empty-marker" type="hidden"
            value="1">
          </div>
        </div>
        <div class="row">
          <label for="form-widgets-name">name</label>
          <input class="text-widget required textline-field" id="form-widgets-name"
          name="form.widgets.name" type="text" value="first">
        </div>
        <div class="action">
          <input class="submit-widget button-field" id="form-buttons-apply"
          name="form.buttons.apply" type="submit" value="Apply">
        </div>
      </form>
    </body>
  </html>

Let's modify the values:

  >>> request = TestRequest(form={
  ...     'form.widgets.subobject.widgets.foofield':u'43',
  ...     'form.widgets.subobject.widgets.barfield':u'55',
  ...     'form.widgets.name':u'first',
  ...     'form.widgets.subobject-empty-marker':u'1',
  ...     'form.buttons.apply':'Apply'})

They are still the same:

  >>> root['first'].subobject.foofield
  66
  >>> root['first'].subobject.barfield
  99

  >>> editform.request = request
  >>> editform.update()

Until we have updated the form:

  >>> root['first'].subobject.foofield
  43
  >>> root['first'].subobject.barfield
  55

Let's see our event log:

  >>> len(eventlog)
  2

  >>> printEvents()
  <zope...ObjectModifiedEvent object at ...>
  <InterfaceClass z3c.form.testing.IMySubObject>
  ['barfield', 'foofield']
  <zope...ObjectModifiedEvent object at ...>
  <InterfaceClass z3c.form.testing.IMyObject>
  ['subobject']


  >>> eventlog=[]


After the update the form says that the values got updated and renders the new
values:

  >>> print(editform.render())
  <html xmlns="http://www.w3.org/1999/xhtml">
    <body>
      <i>Data successfully updated.</i>
      <form action=".">
        <div class="row">
          <label for="form-widgets-subobject">my object</label>
          <div class="object-widget required">
            <div class="label">
              <label for="form-widgets-subobject-widgets-foofield">
                <span>My foo field</span>
                <span class="required">*</span>
              </label>
            </div>
            <div class="widget">
              <input class="text-widget required int-field"
              id="form-widgets-subobject-widgets-foofield"
              name="form.widgets.subobject.widgets.foofield"
              type="text" value="43">
            </div>
            <div class="label">
              <label for="form-widgets-subobject-widgets-barfield">
                <span>My dear bar</span>
              </label>
            </div>
            <div class="widget">
              <input class="text-widget int-field"
              id="form-widgets-subobject-widgets-barfield"
              name="form.widgets.subobject.widgets.barfield"
              type="text" value="55">
            </div>
            <input name="form.widgets.subobject-empty-marker" type="hidden"
            value="1">
          </div>
        </div>
        <div class="row">
          <label for="form-widgets-name">name</label>
          <input class="text-widget required textline-field" id="form-widgets-name"
          name="form.widgets.name" type="text" value="first">
        </div>
        <div class="action">
          <input class="submit-widget button-field" id="form-buttons-apply"
          name="form.buttons.apply" type="submit" value="Apply">
        </div>
      </form>
    </body>
  </html>


Let's see if the widget keeps the old object on editing:

We add a special property to keep track of the object:

  >>> root['first'].__marker__ = "ThisMustStayTheSame"

  >>> root['first'].subobject.foofield
  43
  >>> root['first'].subobject.barfield
  55

Let's modify the values:

  >>> request = TestRequest(form={
  ...     'form.widgets.subobject.widgets.foofield':u'666',
  ...     'form.widgets.subobject.widgets.barfield':u'999',
  ...     'form.widgets.name':u'first',
  ...     'form.widgets.subobject-empty-marker':u'1',
  ...     'form.buttons.apply':'Apply'})

  >>> editform.request = request

  >>> editform.update()

Let's check what are ther esults of the update:

  >>> root['first'].subobject.foofield
  666
  >>> root['first'].subobject.barfield
  999
  >>> root['first'].__marker__
  'ThisMustStayTheSame'


Let's make a nasty error, by typing 'bad' instead of an integer:

  >>> request = TestRequest(form={
  ...     'form.widgets.subobject.widgets.foofield':u'99',
  ...     'form.widgets.subobject.widgets.barfield':u'bad',
  ...     'form.widgets.name':u'first',
  ...     'form.widgets.subobject-empty-marker':u'1',
  ...     'form.buttons.apply':'Apply'})

  >>> editform.request = request
  >>> eventlog=[]
  >>> editform.update()

Eventlog must be clean:

  >>> len(eventlog)
  0

Watch for the error message in the HTML:
it has to appear at the field itself and at the top of the form:

  >>> print(editform.render())
  <html xmlns="http://www.w3.org/1999/xhtml">
    <body>
      <i>There were some errors.</i>
      <ul>
        <li>
        my object:
          <div class="error">The entered value is not a valid integer literal.</div>
        </li>
      </ul>
      <form action=".">
        <div class="row">
          <b>
            <div class="error">The entered value is not a valid integer literal.</div>
          </b>
          <label for="form-widgets-subobject">my object</label>
          <div class="object-widget required">
            <div class="label">
              <label for="form-widgets-subobject-widgets-foofield">
                <span>My foo field</span>
                <span class="required">*</span>
              </label>
            </div>
            <div class="widget">
              <input class="text-widget required int-field"
              id="form-widgets-subobject-widgets-foofield"
              name="form.widgets.subobject.widgets.foofield"
              type="text" value="99">
            </div>
            <div class="label">
              <label for="form-widgets-subobject-widgets-barfield">
                <span>My dear bar</span>
              </label>
            </div>
            <div class="error">The entered value is not a valid integer literal.</div>
            <div class="widget">
              <input class="text-widget int-field"
              id="form-widgets-subobject-widgets-barfield"
              name="form.widgets.subobject.widgets.barfield"
              type="text" value="bad">
            </div>
            <input name="form.widgets.subobject-empty-marker" type="hidden"
            value="1">
          </div>
        </div>
        <div class="row">
          <label for="form-widgets-name">name</label>
          <input class="text-widget required textline-field" id="form-widgets-name"
          name="form.widgets.name" type="text" value="first">
        </div>
        <div class="action">
          <input class="submit-widget button-field" id="form-buttons-apply"
          name="form.buttons.apply" type="submit" value="Apply">
        </div>
      </form>
    </body>
  </html>

The object values must stay at the old ones:

  >>> root['first'].subobject.foofield
  666
  >>> root['first'].subobject.barfield
  999

Let's make more errors:
Now we enter 'bad' and '999999', where '999999' hits the upper limit of the field.

  >>> request = TestRequest(form={
  ...     'form.widgets.subobject.widgets.foofield':u'999999',
  ...     'form.widgets.subobject.widgets.barfield':u'bad',
  ...     'form.widgets.name':u'first',
  ...     'form.widgets.subobject-empty-marker':u'1',
  ...     'form.buttons.apply':'Apply'})

  >>> editform.request = request
  >>> editform.update()

Both errors must appear at the top of the form:

  >>> print(editform.render())
  <html xmlns="http://www.w3.org/1999/xhtml">
    <body>
      <i>There were some errors.</i>
      <ul>
        <li>
        my object:
          <div class="error">Value is too big</div>
          <div class="error">The entered value is not a valid integer literal.</div>
        </li>
      </ul>
      <form action=".">
        <div class="row">
          <b>
            <div class="error">Value is too big</div>
            <div class="error">The entered value is not a valid integer literal.</div>
          </b>
          <label for="form-widgets-subobject">my object</label>
          <div class="object-widget required">
            <div class="label">
              <label for="form-widgets-subobject-widgets-foofield">
                <span>My foo field</span>
                <span class="required">*</span>
              </label>
            </div>
            <div class="error">Value is too big</div>
            <div class="widget">
              <input class="text-widget required int-field"
              id="form-widgets-subobject-widgets-foofield"
              name="form.widgets.subobject.widgets.foofield"
              type="text" value="999999">
            </div>
            <div class="label">
              <label for="form-widgets-subobject-widgets-barfield">
                <span>My dear bar</span>
              </label>
            </div>
            <div class="error">The entered value is not a valid integer literal.</div>
            <div class="widget">
              <input class="text-widget int-field"
              id="form-widgets-subobject-widgets-barfield"
              name="form.widgets.subobject.widgets.barfield"
              type="text" value="bad">
            </div>
            <input name="form.widgets.subobject-empty-marker" type="hidden"
            value="1">
          </div>
        </div>
        <div class="row">
          <label for="form-widgets-name">name</label>
          <input class="text-widget required textline-field" id="form-widgets-name"
          name="form.widgets.name" type="text" value="first">
        </div>
        <div class="action">
          <input class="submit-widget button-field" id="form-buttons-apply"
          name="form.buttons.apply" type="submit" value="Apply">
        </div>
      </form>
    </body>
  </html>

And of course, the object values do not get modified:

  >>> root['first'].subobject.foofield
  666
  >>> root['first'].subobject.barfield
  999

Simple but often used use-case is the display form:

  >>> editform = MyEditForm(root['first'], TestRequest())
  >>> addTemplate(editform)
  >>> editform.mode = interfaces.DISPLAY_MODE
  >>> editform.update()
  >>> print(editform.render())
  <html xmlns="http://www.w3.org/1999/xhtml">
    <body>
      <form action=".">
        <div class="row">
          <label for="form-widgets-subobject">my object</label>
          <div class="object-widget">
            <div class="label">
              <label for="form-widgets-subobject-widgets-foofield">
                <span>My foo field</span>
                <span class="required">*</span>
              </label>
            </div>
            <div class="widget">
              <span class="text-widget int-field"
              id="form-widgets-subobject-widgets-foofield">666</span>
            </div>
            <div class="label">
              <label for="form-widgets-subobject-widgets-barfield">
                <span>My dear bar</span>
              </label>
            </div>
            <div class="widget">
              <span class="text-widget int-field"
              id="form-widgets-subobject-widgets-barfield">999</span>
            </div>
          </div>
        </div>
        <div class="row">
          <label for="form-widgets-name">name</label>
          <span class="text-widget textline-field"
          id="form-widgets-name">first</span>
        </div>
        <div class="action">
          <input class="submit-widget button-field"
          id="form-buttons-apply" name="form.buttons.apply" type="submit" value="Apply">
        </div>
      </form>
    </body>
  </html>


Let's see what happens in HIDDEN_MODE:
(not quite sane thing, but we want to see the objectwidget rendered in hidden
mode)

  >>> zope.component.provideAdapter(
  ...     WidgetTemplateFactory(getPath('object_hidden.pt'), 'text/html'),
  ...     (None, None, None, None, interfaces.IObjectWidget),
  ...     IPageTemplate, name=interfaces.HIDDEN_MODE)


  >>> editform = MyEditForm(root['first'], TestRequest())
  >>> addTemplate(editform)
  >>> editform.mode = interfaces.HIDDEN_MODE
  >>> editform.update()

Note, that the labels and the button is there because the form template for testing
does/should not care about the form being hidden.
What matters is that the objectwidget is rendered hidden.

  >>> print(editform.render())
  <html xmlns="http://www.w3.org/1999/xhtml">
    <body>
      <form action=".">
        <div class="row">
          <label for="form-widgets-subobject">my object</label>
          <input id="form-widgets-subobject-widgets-foofield"
                 name="form.widgets.subobject.widgets.foofield"
                 value="666" class="hidden-widget" type="hidden" />
          <input id="form-widgets-subobject-widgets-barfield"
                 name="form.widgets.subobject.widgets.barfield"
                 value="999" class="hidden-widget" type="hidden" />
        </div>
        <div class="row">
          <label for="form-widgets-name">name</label>
          <input id="form-widgets-name" name="form.widgets.name"
                 value="first" class="hidden-widget" type="hidden" />
        </div>
        <div class="action">
         <input id="form-buttons-apply" name="form.buttons.apply"
                class="submit-widget button-field" value="Apply" type="submit" />
        </div>
      </form>
    </body>
  </html>



Editforms might use dicts as context:

  >>> newsub = MySubObject()
  >>> newsub.foofield = 78
  >>> newsub.barfield = 87

  >>> class MyEditFormDict(form.EditForm):
  ...     fields = field.Fields(IMyObject)
  ...     def getContent(self):
  ...         return {'subobject': newsub, 'name': u'blooki'}

  >>> editform = MyEditFormDict(None, TestRequest())
  >>> addTemplate(editform)
  >>> editform.update()

Watch for the widget values in the HTML:

  >>> print(editform.render())
  <html xmlns="http://www.w3.org/1999/xhtml">
    <body>
      <form action=".">
        <div class="row">
          <label for="form-widgets-subobject">my object</label>
          <div class="object-widget required">
            <div class="label">
              <label for="form-widgets-subobject-widgets-foofield">
                <span>My foo field</span>
                <span class="required">*</span>
              </label>
            </div>
            <div class="widget">
              <input class="text-widget required int-field"
              id="form-widgets-subobject-widgets-foofield"
              name="form.widgets.subobject.widgets.foofield"
              type="text" value="78">
            </div>
            <div class="label">
              <label for="form-widgets-subobject-widgets-barfield">
                <span>My dear bar</span>
              </label>
            </div>
            <div class="widget">
              <input class="text-widget int-field"
              id="form-widgets-subobject-widgets-barfield"
              name="form.widgets.subobject.widgets.barfield"
              type="text" value="87">
            </div>
            <input name="form.widgets.subobject-empty-marker" type="hidden"
            value="1">
          </div>
        </div>
        <div class="row">
          <label for="form-widgets-name">name</label>
          <input class="text-widget required textline-field" id="form-widgets-name"
          name="form.widgets.name" type="text" value="blooki">
        </div>
        <div class="action">
          <input class="submit-widget button-field" id="form-buttons-apply"
          name="form.buttons.apply" type="submit" value="Apply">
        </div>
      </form>
    </body>
  </html>

Let's modify the values:

  >>> request = TestRequest(form={
  ...     'form.widgets.subobject.widgets.foofield':u'43',
  ...     'form.widgets.subobject.widgets.barfield':u'55',
  ...     'form.widgets.name':u'first',
  ...     'form.widgets.subobject-empty-marker':u'1',
  ...     'form.buttons.apply':'Apply'})

They are still the same:

  >>> newsub.foofield
  78
  >>> newsub.barfield
  87

Until updating the form:

  >>> editform.request = request
  >>> eventlog=[]
  >>> editform.update()

  >>> newsub.foofield
  43
  >>> newsub.barfield
  55

  >>> len(eventlog)
  2
  >>> printEvents()
  <zope...ObjectModifiedEvent object at ...>
  <InterfaceClass z3c.form.testing.IMySubObject>
  ['barfield', 'foofield']
  <zope...ObjectModifiedEvent object at ...>
  <InterfaceClass z3c.form.testing.IMyObject>
  ['name', 'subobject']


Object in an Object situation
=============================


We define an interface containing a subobject, and an addform for it:

  >>> from z3c.form import form, field
  >>> from z3c.form.testing import IMyComplexObject

Note, that creating an object will print some information about it:

  >>> class MyAddForm(form.AddForm):
  ...     fields = field.Fields(IMyComplexObject)
  ...     def create(self, data):
  ...         print("MyAddForm.create", str(data))
  ...         return MyObject(**data)
  ...     def add(self, obj):
  ...         self.context[obj.name] = obj
  ...     def nextURL(self):
  ...         pass

We create the form and try to update it:

  >>> request = TestRequest()

  >>> myaddform =  MyAddForm(root, request)

  >>> myaddform.update()

As usual, the form contains a widget manager with the expected widget

  >>> myaddform.widgets.keys()
  ['subobject', 'name']
  >>> myaddform.widgets.values()
  [<ObjectWidget 'form.widgets.subobject'>, <TextWidget 'form.widgets.name'>]

The addform has our ObjectWidget which in turn contains a subform:

  >>> myaddform.widgets['subobject'].subform
  <z3c.form.object.ObjectSubForm object at ...>

Which in turn contains the sub-widgets:

  >>> myaddform.widgets['subobject'].subform.widgets.keys()
  ['subfield', 'moofield']

  >>> myaddform.widgets['subobject'].subform.widgets['subfield'].subform.widgets.keys()
  ['foofield', 'barfield']

If we want to render the addform, we must give it a template:

  >>> addTemplate(myaddform)

Now rendering the addform renders the subform as well:

  >>> print(myaddform.render())
  <html xmlns="http://www.w3.org/1999/xhtml">
    <body>
      <form action=".">
        <div class="row">
          <label for="form-widgets-subobject">my object</label>
          <div class="object-widget required">
            <div class="label">
              <label for="form-widgets-subobject-widgets-subfield">
                <span>Second-subobject</span>
                <span class="required">*</span>
              </label>
            </div>
            <div class="widget">
              <div class="object-widget required">
                <div class="label">
                  <label for="form-widgets-subobject-widgets-subfield-widgets-foofield">
                    <span>My foo field</span>
                    <span class="required">*</span>
                  </label>
                </div>
                <div class="widget">
                  <input class="text-widget required int-field"
                  id="form-widgets-subobject-widgets-subfield-widgets-foofield"
                  name="form.widgets.subobject.widgets.subfield.widgets.foofield"
                  type="text" value="1,111">
                </div>
                <div class="label">
                  <label for="form-widgets-subobject-widgets-subfield-widgets-barfield">
                    <span>My dear bar</span>
                  </label>
                </div>
                <div class="widget">
                  <input class="text-widget int-field"
                  id="form-widgets-subobject-widgets-subfield-widgets-barfield"
                  name="form.widgets.subobject.widgets.subfield.widgets.barfield"
                  type="text" value="2,222">
                </div>
                <input name="form.widgets.subobject.widgets.subfield-empty-marker" type="hidden" value="1">
              </div>
            </div>
            <div class="label">
              <label for="form-widgets-subobject-widgets-moofield">
                <span>Something</span>
                <span class="required">*</span>
              </label>
            </div>
            <div class="widget">
              <input class="text-widget required textline-field"
              id="form-widgets-subobject-widgets-moofield"
              name="form.widgets.subobject.widgets.moofield" type="text" value="">
            </div>
            <input name="form.widgets.subobject-empty-marker" type="hidden" value="1">
          </div>
        </div>
        <div class="row">
          <label for="form-widgets-name">name</label>
          <input class="text-widget required textline-field"
          id="form-widgets-name" name="form.widgets.name" type="text" value="">
        </div>
        <div class="action">
          <input class="submit-widget button-field" id="form-buttons-add" name="form.buttons.add" type="submit" value="Add">
        </div>
      </form>
    </body>
  </html>


Coverage happiness
------------------

Converting interfaces.NO_VALUE holds None:

  >>> converter.toFieldValue(interfaces.NO_VALUE) is None
  True


This is a complicated case.
Happens when the context is a dict, and the dict misses the field.
(Note, we're making ``sub__object`` instead of ``subobject``)

  >>> context = dict(sub__object=None, foo=123, bar=456)

All the story the create a widget:

  >>> field = zope.schema.Object(
  ...     __name__='subobject',
  ...     title=u'my object widget',
  ...     schema=IMySubObject)

  >>> wv = {'foofield': 2, 'barfield': 999}

  >>> request = TestRequest()
  >>> widget = z3c.form.browser.object.ObjectWidget(request)
  >>> widget = FieldWidget(field, widget)
  >>> widget.context = context
  >>> widget.value = wv
  >>> widget.update()
  >>> converter = interfaces.IDataConverter(widget)

And still we get a MySubObject, no failure:

  >>> value = converter.toFieldValue(wv)
  >>> value
  <z3c.form.testing.MySubObject object at ...>
  >>> value.foofield
  2
  >>> value.barfield
  999


Easy (after the previous).
In case the previous value on the context is None (or missing).
We need to create a new object to be able to set properties on.

  >>> context['subobject'] = None
  >>> value = converter.toFieldValue(wv)
  >>> value
  <z3c.form.testing.MySubObject object at ...>
  >>> value.foofield
  2
  >>> value.barfield
  999

In case there is something that cannot be adapted to the right interface,
it just burps:
(might be an idea to create in this case also a new blank object)

  >>> context['subobject'] = u'brutal'
  >>> converter.toFieldValue(wv)
  Traceback (most recent call last):
  ...
  TypeError: ('Could not adapt', u'brutal',
  <InterfaceClass z3c.form.testing.IMySubObject>)

  >>> context['subobject'] = None


One more.
Value to convert misses a field. Should never happen actually:

  >>> wv = {'foofield': 2}
  >>> value = converter.toFieldValue(wv)

Known property is set:

  >>> value.foofield
  2

Unknown sticks ti it's default value:

  >>> value.barfield
  2222
