[Checkins] SVN: z3c.form/trunk/ - Feature: Implemented MultiWidget. The MultiWidget allows to use simple fields

Roger Ineichen roger at projekt01.ch
Thu Aug 28 18:20:32 EDT 2008


Log message for revision 90564:
  - Feature: Implemented MultiWidget. The MultiWidget allows to use simple fields
    like ITextLine, IInt, IPassword, etc. in a IList or ITuple sequence. Since we
    used the term sequence for the sequence we can choose from, from the point of
    view of a widget e.g. a source or vocabulary, the name multi is used for the
    widget which allows to collect values for a sequence field.
  
  - Feature: Implemented TextLinesWidget. This widget offers a TextArea and
    splits lines in sequence items. This is usfull for power user interfaces.
    The widget can be used for e.g. (IList or ITuple) of ITextLine or any other
    (sequence) of simple field like IPassword, IInt etc.

Changed:
  U   z3c.form/trunk/CHANGES.txt
  U   z3c.form/trunk/src/z3c/form/browser/README.txt
  U   z3c.form/trunk/src/z3c/form/browser/configure.zcml
  A   z3c.form/trunk/src/z3c/form/browser/multi.py
  A   z3c.form/trunk/src/z3c/form/browser/multi.txt
  A   z3c.form/trunk/src/z3c/form/browser/multi.zcml
  A   z3c.form/trunk/src/z3c/form/browser/multi_display.pt
  A   z3c.form/trunk/src/z3c/form/browser/multi_hidden.pt
  A   z3c.form/trunk/src/z3c/form/browser/multi_input.pt
  U   z3c.form/trunk/src/z3c/form/browser/orderedselect.py
  U   z3c.form/trunk/src/z3c/form/browser/orderedselect.zcml
  U   z3c.form/trunk/src/z3c/form/browser/tests.py
  A   z3c.form/trunk/src/z3c/form/browser/textlines.py
  A   z3c.form/trunk/src/z3c/form/browser/textlines.txt
  A   z3c.form/trunk/src/z3c/form/browser/textlines.zcml
  A   z3c.form/trunk/src/z3c/form/browser/textlines_display.pt
  A   z3c.form/trunk/src/z3c/form/browser/textlines_input.pt
  U   z3c.form/trunk/src/z3c/form/configure.zcml
  U   z3c.form/trunk/src/z3c/form/converter.py
  U   z3c.form/trunk/src/z3c/form/converter.txt
  U   z3c.form/trunk/src/z3c/form/interfaces.py
  U   z3c.form/trunk/src/z3c/form/widget.py
  U   z3c.form/trunk/src/z3c/form/widget.txt
  A   z3c.form/trunk/src/z3c/form/widget_multi.pt

-=-
Modified: z3c.form/trunk/CHANGES.txt
===================================================================
--- z3c.form/trunk/CHANGES.txt	2008-08-28 22:03:22 UTC (rev 90563)
+++ z3c.form/trunk/CHANGES.txt	2008-08-28 22:20:31 UTC (rev 90564)
@@ -5,6 +5,17 @@
 Version 1.9.1dev (unreleased)
 -----------------------------
 
+- Feature: Implemented MultiWidget. The MultiWidget allows to use simple fields
+  like ITextLine, IInt, IPassword, etc. in a IList or ITuple sequence. Since we
+  used the term sequence for the sequence we can choose from, from the point of
+  view of a widget e.g. a source or vocabulary, the name multi is used for the
+  widget which allows to collect values for a sequence field.
+
+- Feature: Implemented TextLinesWidget. This widget offers a TextArea and
+  splits lines in sequence items. This is usfull for power user interfaces.
+  The widget can be used for e.g. (IList or ITuple) of ITextLine or any other
+  (sequence) of simple field like IPassword, IInt etc.
+
 - Remove unused imports, adjust buildout dependencies in setup.py
 
 

Modified: z3c.form/trunk/src/z3c/form/browser/README.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/README.txt	2008-08-28 22:03:22 UTC (rev 90563)
+++ z3c.form/trunk/src/z3c/form/browser/README.txt	2008-08-28 22:20:31 UTC (rev 90564)
@@ -44,6 +44,13 @@
   >>> field = zope.schema.ASCII(default='This is\n ASCII.')
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.textarea.TextAreaWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <FieldDataConverter converts from ASCII to TextAreaWidget>
+
   >>> print widget.render()
   <textarea id="foo" name="bar" class="textarea-widget required ascii-field">This is
    ASCII.</textarea>
@@ -60,6 +67,13 @@
   >>> field = zope.schema.ASCIILine(default='An ASCII line.')
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.text.TextWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <FieldDataConverter converts from ASCIILine to TextWidget>
+
   >>> print widget.render()
   <input type="text" id="foo" name="bar"
          class="text-widget required asciiline-field" value="An ASCII line." />
@@ -74,6 +88,13 @@
   >>> field = zope.schema.Bool(default=True)
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.radio.RadioWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <SequenceDataConverter converts from Bool to RadioWidget>
+
   >>> print widget.render()
   <span class="option">
     <label for="foo-0">
@@ -158,6 +179,10 @@
   >>> field = button.Button(title=u'Press me!')
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.submit.SubmitWidget'>
+
   >>> print widget.render()
   <input type="submit" id="foo" name="bar"
          class="submit-widget button-field" value="Press me!" />
@@ -194,6 +219,13 @@
   >>> field = zope.schema.Bytes(default='\10\45\n\32')
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.file.FileWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <FileUploadDataConverter converts from Bytes to FileWidget>
+
   >>> print widget.render()
   <input type="file" id="foo" name="bar" class="file-widget required bytes-field" />
 
@@ -208,6 +240,13 @@
   >>> field = zope.schema.BytesLine(default='A Bytes line.')
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.text.TextWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <FieldDataConverter converts from BytesLine to TextWidget>
+
   >>> print widget.render()
   <input type="text" id="foo" name="bar" class="text-widget required bytesline-field"
          value="A Bytes line." />
@@ -227,6 +266,13 @@
   >>> field = zope.schema.Choice(default=True, vocabulary=vocabulary)
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.select.SelectWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <SequenceDataConverter converts from Choice to SelectWidget>
+
   >>> print widget.render()
   <select id="foo" name="bar:list" class="select-widget required choice-field"
           size="1">
@@ -248,6 +294,13 @@
   >>> field = zope.schema.Date(default=datetime.date(2007, 4, 1))
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.text.TextWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <DateDataConverter converts from Date to TextWidget>
+
   >>> print widget.render()
   <input type="text" id="foo" name="bar" class="text-widget required date-field"
          value="07/04/01" />
@@ -263,6 +316,13 @@
   >>> field = zope.schema.Datetime(default=datetime.datetime(2007, 4, 1, 12))
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.text.TextWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <DatetimeDataConverter converts from Datetime to TextWidget>
+
   >>> print widget.render()
   <input type="text" id="foo" name="bar" class="text-widget required datetime-field"
          value="07/04/01 12:00" />
@@ -279,6 +339,13 @@
   >>> field = zope.schema.Decimal(default=decimal.Decimal('1265.87'))
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.text.TextWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <DecimalDataConverter converts from Decimal to TextWidget>
+
   >>> print widget.render()
   <input type="text" id="foo" name="bar" class="text-widget required decimal-field"
          value="1,265.87" />
@@ -301,6 +368,13 @@
   >>> field = zope.schema.DottedName(default='z3c.form')
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.text.TextWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <FieldDataConverter converts from DottedName to TextWidget>
+
   >>> print widget.render()
   <input type="text" id="foo" name="bar" class="text-widget required dottedname-field"
          value="z3c.form" />
@@ -316,6 +390,13 @@
   >>> field = zope.schema.Float(default=1265.8)
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.text.TextWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <FloatDataConverter converts from Float to TextWidget>
+
   >>> print widget.render()
   <input type="text" id="foo" name="bar" class="text-widget required float-field"
          value="1,265.8" />
@@ -333,6 +414,13 @@
   ...     default=frozenset([1, 3]) )
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.select.SelectWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <CollectionSequenceDataConverter converts from FrozenSet to SelectWidget>
+
   >>> print widget.render()
   <select id="foo" name="bar:list" class="select-widget required frozenset-field"
           multiple="multiple" size="5">
@@ -356,6 +444,13 @@
   >>> field = zope.schema.Id(default='z3c.form')
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.text.TextWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <FieldDataConverter converts from Id to TextWidget>
+
   >>> print widget.render()
   <input type="text" id="foo" name="bar" class="text-widget required id-field"
          value="z3c.form" />
@@ -400,6 +495,10 @@
 
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.image.ImageWidget'>
+
   >>> print widget.render()
   <input type="image" id="foo" name="bar"
          class="image-widget imagebutton-field"
@@ -420,6 +519,13 @@
   >>> field = zope.schema.Int(default=1200)
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.text.TextWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <IntegerDataConverter converts from Int to TextWidget>
+
   >>> print widget.render()
   <input type="text" id="foo" name="bar" class="text-widget required int-field"
          value="1,200" />
@@ -429,19 +535,163 @@
   <span id="foo" class="text-widget required int-field">1,200</span>
 
 
-List
-----
+List - ASCII
+------------
 
   >>> field = zope.schema.List(
+  ...     value_type=zope.schema.ASCII(
+  ...         title=u'ASCII',
+  ...         default='This is\n ASCII.'),
+  ...     default=['foo\nfoo', 'bar\nbar'])
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from List to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>ASCII</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><textarea id="foo-0" name="bar.0"
+                 class="textarea-widget required ascii-field">foo
+  foo</textarea>
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>ASCII</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><textarea id="foo-1" name="bar.1"
+                 class="textarea-widget required ascii-field">bar
+  bar</textarea>
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+List - ASCIILine
+----------------
+
+  >>> field = zope.schema.List(
+  ...     value_type=zope.schema.ASCIILine(
+  ...         title=u'ASCIILine',
+  ...         default='An ASCII line.'),
+  ...     default=['foo', 'bar'])
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from List to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>ASCIILine</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required asciiline-field"
+                 value="foo" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>ASCIILine</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required asciiline-field"
+                 value="bar" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+List - Choice
+-------------
+
+  >>> field = zope.schema.List(
   ...     value_type=zope.schema.Choice(values=(1, 2, 3, 4)),
   ...     default=[1, 3] )
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.orderedselect.OrderedSelectWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <CollectionSequenceDataConverter converts from List to OrderedSelectWidget>
+
   >>> print widget.render()
   <script type="text/javascript">
   ...
   </script>
-  <BLANKLINE>
   <table border="0" class="ordered-selection-field">
     <tr>
       <td>
@@ -490,6 +740,963 @@
       class="selected-option">3</span></span>
 
 
+List - Date
+-----------
+
+  >>> field = zope.schema.List(
+  ...     value_type=zope.schema.Date(
+  ...         title=u'Date',
+  ...         default=datetime.date(2007, 4, 1)),
+  ...     default=[datetime.date(2008, 9, 27), datetime.date(2008, 9, 28)])
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from List to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>Date</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required date-field"
+                 value="08/09/27" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>Date</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required date-field"
+                 value="08/09/28" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+List - Datetime
+---------------
+
+  >>> field = zope.schema.List(
+  ...     value_type=zope.schema.Datetime(
+  ...         title=u'Datetime',
+  ...         default=datetime.datetime(2007, 4, 1, 12)),
+  ...     default=[datetime.datetime(2008, 9, 27, 12),
+  ...              datetime.datetime(2008, 9, 28, 12)])
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from List to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>Datetime</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required datetime-field"
+                 value="08/09/27 12:00" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>Datetime</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required datetime-field"
+                 value="08/09/28 12:00" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+List - Decimal
+---------------
+
+  >>> field = zope.schema.List(
+  ...     value_type=zope.schema.Decimal(
+  ...         title=u'Decimal',
+  ...         default=decimal.Decimal('1265.87')),
+  ...     default=[decimal.Decimal('123.456'), decimal.Decimal('1')])
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from List to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>Decimal</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required decimal-field"
+                 value="123.456" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>Decimal</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required decimal-field" value="1" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+List - DottedName
+-----------------
+
+  >>> field = zope.schema.List(
+  ...     value_type=zope.schema.DottedName(
+  ...         title=u'DottedName',
+  ...         default='z3c.form'),
+  ...     default=[u'z3c.form', u'z3c.wizard'])
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from List to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>DottedName</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required dottedname-field"
+                 value="z3c.form" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>DottedName</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required dottedname-field"
+                 value="z3c.wizard" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+List - Float
+------------
+
+  >>> field = zope.schema.List(
+  ...     value_type=zope.schema.Float(
+  ...         title=u'Float',
+  ...         default=123.456),
+  ...     default=[1234.5, 1])
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from List to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>Float</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required float-field"
+                 value="1,234.5" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>Float</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required float-field" value="1.0" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+List - Id
+---------
+
+  >>> field = zope.schema.List(
+  ...     value_type=zope.schema.Id(
+  ...         title=u'Id',
+  ...         default='z3c.form'),
+  ...     default=['z3c.form', 'z3c.wizard'])
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from List to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>Id</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required id-field"
+                 value="z3c.form" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>Id</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required id-field"
+                 value="z3c.wizard" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+List - Int
+----------
+
+  >>> field = zope.schema.List(
+  ...     value_type=zope.schema.Int(
+  ...         title=u'Int',
+  ...         default=666),
+  ...     default=[42, 43])
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from List to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>Int</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required int-field" value="42" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>Int</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required int-field" value="43" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+List - Password
+---------------
+
+  >>> field = zope.schema.List(
+  ...     value_type=zope.schema.Password(
+  ...         title=u'Password',
+  ...         default=u'mypwd'),
+  ...     default=['pwd', 'pass'])
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from List to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>Password</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="password" id="foo-0" name="bar.0"
+                 class="password-widget required password-field" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>Password</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="password" id="foo-1" name="bar.1"
+                 class="password-widget required password-field" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+List - SourceText
+-----------------
+
+  >>> field = zope.schema.List(
+  ...     value_type=zope.schema.SourceText(
+  ...         title=u'SourceText',
+  ...         default=u'<source />'),
+  ...     default=[u'<html></body>foo</body></html>', u'<h1>bar</h1>'] )
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from List to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>SourceText</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><textarea id="foo-0" name="bar.0"
+                 class="textarea-widget required sourcetext-field">&lt;html&gt;&lt;/body&gt;foo&lt;/body&gt;&lt;/html&gt;</textarea>
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>SourceText</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><textarea id="foo-1" name="bar.1"
+                 class="textarea-widget required sourcetext-field">&lt;h1&gt;bar&lt;/h1&gt;</textarea>
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+List - Text
+-----------
+
+  >>> field = zope.schema.List(
+  ...     value_type=zope.schema.Text(
+  ...         title=u'Text',
+  ...         default=u'Some\n Text.'),
+  ...     default=[u'foo\nfoo', u'bar\nbar'] )
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from List to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>Text</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><textarea id="foo-0" name="bar.0"
+            class="textarea-widget required text-field">foo
+  foo</textarea>
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>Text</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><textarea id="foo-1" name="bar.1"
+            class="textarea-widget required text-field">bar
+  bar</textarea>
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+List - TextLine
+---------------
+
+  >>> field = zope.schema.List(
+  ...     value_type=zope.schema.TextLine(
+  ...         title=u'TextLine',
+  ...         default=u'Some Text line.'),
+  ...     default=[u'foo', u'bar'] )
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from List to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>TextLine</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required textline-field"
+                 value="foo" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>TextLine</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required textline-field"
+                 value="bar" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+List - Time
+-----------
+
+  >>> field = zope.schema.List(
+  ...     value_type=zope.schema.Time(
+  ...         title=u'Time',
+  ...         default=datetime.time(12, 0)),
+  ...     default=[datetime.time(13, 0), datetime.time(14, 0)] )
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from List to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>Time</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required time-field" value="13:00" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>Time</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required time-field" value="14:00" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+List - Timedelta
+----------------
+
+  >>> field = zope.schema.List(
+  ...     value_type=zope.schema.Timedelta(
+  ...         title=u'Timedelta',
+  ...         default=datetime.timedelta(days=3)),
+  ...     default=[datetime.timedelta(days=4), datetime.timedelta(days=5)] )
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from List to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>Timedelta</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required timedelta-field"
+                 value="4 days, 0:00:00" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>Timedelta</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required timedelta-field"
+                 value="5 days, 0:00:00" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+List - URI
+----------
+
+  >>> field = zope.schema.List(
+  ...     value_type=zope.schema.URI(
+  ...         title=u'URI',
+  ...         default='http://zope.org'),
+  ...     default=['http://www.python.org', 'http://www.zope.com'] )
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from List to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>URI</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required uri-field"
+                 value="http://www.python.org" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>URI</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required uri-field"
+                 value="http://www.zope.com" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
 Object
 ------
 
@@ -503,6 +1710,13 @@
   >>> field = zope.schema.Password(default=u'mypwd')
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.password.PasswordWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <FieldDataConverter converts from Password to PasswordWidget>
+
   >>> print widget.render()
   <input type="password" id="foo" name="bar"
          class="password-widget required password-field" />
@@ -520,6 +1734,13 @@
   ...     default=set([1, 3]) )
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.select.SelectWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <CollectionSequenceDataConverter converts from Set to SelectWidget>
+
   >>> print widget.render()
   <select id="foo" name="bar:list" class="select-widget required set-field"
           multiple="multiple"  size="5">
@@ -543,6 +1764,13 @@
   >>> field = zope.schema.SourceText(default=u'<source />')
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.textarea.TextAreaWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <FieldDataConverter converts from SourceText to TextAreaWidget>
+
   >>> print widget.render()
   <textarea id="foo" name="bar"
             class="textarea-widget required sourcetext-field">&lt;source /&gt;</textarea>
@@ -558,6 +1786,13 @@
   >>> field = zope.schema.Text(default=u'Some\n Text.')
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.textarea.TextAreaWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <FieldDataConverter converts from Text to TextAreaWidget>
+
   >>> print widget.render()
   <textarea id="foo" name="bar" class="textarea-widget required text-field">Some
    Text.</textarea>
@@ -574,6 +1809,13 @@
   >>> field = zope.schema.TextLine(default=u'Some Text line.')
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.text.TextWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <FieldDataConverter converts from TextLine to TextWidget>
+
   >>> print widget.render()
   <input type="text" id="foo" name="bar" class="text-widget required textline-field"
          value="Some Text line." />
@@ -589,6 +1831,14 @@
   >>> field = zope.schema.Time(default=datetime.time(12, 0))
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.text.TextWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <TimeDataConverter converts from Time to TextWidget>
+
+
   >>> print widget.render()
   <input type="text" id="foo" name="bar" class="text-widget required time-field"
          value="12:00" />
@@ -604,6 +1854,13 @@
   >>> field = zope.schema.Timedelta(default=datetime.timedelta(days=3))
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.text.TextWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <TimedeltaDataConverter converts from Timedelta to TextWidget>
+
   >>> print widget.render()
   <input type="text" id="foo" name="bar" class="text-widget required timedelta-field"
          value="3 days, 0:00:00" />
@@ -613,19 +1870,163 @@
   <span id="foo" class="text-widget required timedelta-field">3 days, 0:00:00</span>
 
 
-Tuple
------
+Tuple - ASCII
+-------------
 
   >>> field = zope.schema.Tuple(
+  ...     value_type=zope.schema.ASCII(
+  ...         title=u'ASCII',
+  ...         default='This is\n ASCII.'),
+  ...     default=('foo\nfoo', 'bar\nbar'))
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from Tuple to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>ASCII</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><textarea id="foo-0" name="bar.0"
+                 class="textarea-widget required ascii-field">foo
+  foo</textarea>
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>ASCII</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><textarea id="foo-1" name="bar.1"
+                 class="textarea-widget required ascii-field">bar
+  bar</textarea>
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+Tuple - ASCIILine
+-----------------
+
+  >>> field = zope.schema.Tuple(
+  ...     value_type=zope.schema.ASCIILine(
+  ...         title=u'ASCIILine',
+  ...         default='An ASCII line.'),
+  ...     default=('foo', 'bar'))
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from Tuple to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>ASCIILine</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required asciiline-field"
+                 value="foo" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>ASCIILine</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required asciiline-field"
+                 value="bar" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+Tuple - Choice
+--------------
+
+  >>> field = zope.schema.Tuple(
   ...     value_type=zope.schema.Choice(values=(1, 2, 3, 4)),
   ...     default=(1, 3) )
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.orderedselect.OrderedSelectWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <CollectionSequenceDataConverter converts from Tuple to OrderedSelectWidget>
+
   >>> print widget.render()
   <script type="text/javascript">
   ...
   </script>
-  <BLANKLINE>
   <table border="0" class="ordered-selection-field">
     <tr>
       <td>
@@ -674,12 +2075,976 @@
     class="selected-option">3</span></span>
 
 
+Tuple - Date
+------------
+
+  >>> field = zope.schema.Tuple(
+  ...     value_type=zope.schema.Date(
+  ...         title=u'Date',
+  ...         default=datetime.date(2007, 4, 1)),
+  ...     default=(datetime.date(2008, 9, 27), datetime.date(2008, 9, 28)))
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from Tuple to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>Date</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required date-field"
+                 value="08/09/27" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>Date</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required date-field"
+                 value="08/09/28" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+Tuple - Datetime
+----------------
+
+  >>> field = zope.schema.Tuple(
+  ...     value_type=zope.schema.Datetime(
+  ...         title=u'Datetime',
+  ...         default=datetime.datetime(2007, 4, 1, 12)),
+  ...     default=(datetime.datetime(2008, 9, 27, 12),
+  ...              datetime.datetime(2008, 9, 28, 12)))
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from Tuple to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>Datetime</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required datetime-field"
+                 value="08/09/27 12:00" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>Datetime</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required datetime-field"
+                 value="08/09/28 12:00" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+Tuple - Decimal
+----------------
+
+  >>> field = zope.schema.Tuple(
+  ...     value_type=zope.schema.Decimal(
+  ...         title=u'Decimal',
+  ...         default=decimal.Decimal('1265.87')),
+  ...     default=(decimal.Decimal('123.456'), decimal.Decimal('1')))
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from Tuple to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>Decimal</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required decimal-field"
+                 value="123.456" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>Decimal</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required decimal-field" value="1" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+Tuple - DottedName
+------------------
+
+  >>> field = zope.schema.Tuple(
+  ...     value_type=zope.schema.DottedName(
+  ...         title=u'DottedName',
+  ...         default='z3c.form'),
+  ...     default=(u'z3c.form', u'z3c.wizard'))
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from Tuple to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>DottedName</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required dottedname-field"
+                 value="z3c.form" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>DottedName</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required dottedname-field"
+                 value="z3c.wizard" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+Tuple - Float
+-------------
+
+  >>> field = zope.schema.Tuple(
+  ...     value_type=zope.schema.Float(
+  ...         title=u'Float',
+  ...         default=123.456),
+  ...     default=(1234.5, 1))
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from Tuple to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>Float</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required float-field"
+                 value="1,234.5" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>Float</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required float-field" value="1.0" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+Tuple - Id
+----------
+
+  >>> field = zope.schema.Tuple(
+  ...     value_type=zope.schema.Id(
+  ...         title=u'Id',
+  ...         default='z3c.form'),
+  ...     default=('z3c.form', 'z3c.wizard'))
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from Tuple to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>Id</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required id-field"
+                 value="z3c.form" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>Id</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required id-field"
+                 value="z3c.wizard" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+Tuple - Int
+-----------
+
+  >>> field = zope.schema.Tuple(
+  ...     value_type=zope.schema.Int(
+  ...         title=u'Int',
+  ...         default=666),
+  ...     default=(42, 43))
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from Tuple to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>Int</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required int-field" value="42" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>Int</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required int-field" value="43" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+Tuple - Password
+----------------
+
+  >>> field = zope.schema.Tuple(
+  ...     value_type=zope.schema.Password(
+  ...         title=u'Password',
+  ...         default=u'mypwd'),
+  ...     default=('pwd', 'pass'))
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from Tuple to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>Password</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="password" id="foo-0" name="bar.0"
+                 class="password-widget required password-field" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>Password</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="password" id="foo-1" name="bar.1"
+                 class="password-widget required password-field" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+Tuple - SourceText
+------------------
+
+  >>> field = zope.schema.Tuple(
+  ...     value_type=zope.schema.SourceText(
+  ...         title=u'SourceText',
+  ...         default=u'<source />'),
+  ...     default=(u'<html></body>foo</body></html>', u'<h1>bar</h1>'))
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from Tuple to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>SourceText</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><textarea id="foo-0" name="bar.0"
+                 class="textarea-widget required sourcetext-field">&lt;html&gt;&lt;/body&gt;foo&lt;/body&gt;&lt;/html&gt;</textarea>
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>SourceText</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><textarea id="foo-1" name="bar.1"
+                 class="textarea-widget required sourcetext-field">&lt;h1&gt;bar&lt;/h1&gt;</textarea>
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+Tuple - Text
+------------
+
+  >>> field = zope.schema.Tuple(
+  ...     value_type=zope.schema.Text(
+  ...         title=u'Text',
+  ...         default=u'Some\n Text.'),
+  ...     default=(u'foo\nfoo', u'bar\nbar'))
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from Tuple to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>Text</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><textarea id="foo-0" name="bar.0"
+            class="textarea-widget required text-field">foo
+  foo</textarea>
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>Text</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><textarea id="foo-1" name="bar.1"
+            class="textarea-widget required text-field">bar
+  bar</textarea>
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+Tuple - TextLine
+----------------
+
+  >>> field = zope.schema.Tuple(
+  ...     value_type=zope.schema.TextLine(
+  ...         title=u'TextLine',
+  ...         default=u'Some Text line.'),
+  ...     default=(u'foo', u'bar'))
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from Tuple to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>TextLine</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required textline-field"
+                 value="foo" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>TextLine</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required textline-field"
+                 value="bar" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+Tuple - Time
+------------
+
+  >>> field = zope.schema.Tuple(
+  ...     value_type=zope.schema.Time(
+  ...         title=u'Time',
+  ...         default=datetime.time(12, 0)),
+  ...     default=(datetime.time(13, 0), datetime.time(14, 0)))
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from Tuple to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>Time</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required time-field" value="13:00" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>Time</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required time-field" value="14:00" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+Tuple - Timedelta
+-----------------
+
+  >>> field = zope.schema.Tuple(
+  ...     value_type=zope.schema.Timedelta(
+  ...         title=u'Timedelta',
+  ...         default=datetime.timedelta(days=3)),
+  ...     default=(datetime.timedelta(days=4), datetime.timedelta(days=5)))
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from Tuple to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>Timedelta</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required timedelta-field"
+                 value="4 days, 0:00:00" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>Timedelta</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required timedelta-field"
+                 value="5 days, 0:00:00" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
+Tuple - URI
+-----------
+
+  >>> field = zope.schema.Tuple(
+  ...     value_type=zope.schema.URI(
+  ...         title=u'URI',
+  ...         default='http://zope.org'),
+  ...     default=('http://www.python.org', 'http://www.zope.com'))
+  >>> widget = setupWidget(field)
+  >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.multi.MultiWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <MultiConverter converts from Tuple to MultiWidget>
+
+  >>> print widget.render()
+  <div class="multi-widget required">
+      <div id="foo-0-row" class="row">
+          <div class="label">
+            <label for="foo-0">
+              <span>URI</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-0-remove" name="bar.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-0" name="bar.0"
+                 class="text-widget required uri-field"
+                 value="http://www.python.org" />
+          </div>
+        </div>
+      </div>
+      <div id="foo-1-row" class="row">
+          <div class="label">
+            <label for="foo-1">
+              <span>URI</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="foo-1-remove" name="bar.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="foo-1" name="bar.1"
+                 class="text-widget required uri-field"
+                 value="http://www.zope.com" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="bar.count" value="2" />
+
+
 URI
 ---
 
   >>> field = zope.schema.URI(default='http://zope.org')
   >>> widget = setupWidget(field)
   >>> widget.update()
+
+  >>> widget.__class__
+  <class 'z3c.form.browser.text.TextWidget'>
+
+  >>> interfaces.IDataConverter(widget)
+  <FieldDataConverter converts from URI to TextWidget>
+
   >>> print widget.render()
   <input type="text" id="foo" name="bar" class="text-widget required uri-field"
          value="http://zope.org" />

Modified: z3c.form/trunk/src/z3c/form/browser/configure.zcml
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/configure.zcml	2008-08-28 22:03:22 UTC (rev 90563)
+++ z3c.form/trunk/src/z3c/form/browser/configure.zcml	2008-08-28 22:20:31 UTC (rev 90564)
@@ -7,6 +7,7 @@
   <include file="checkbox.zcml" />
   <include file="file.zcml" />
   <include file="image.zcml" />
+  <include file="multi.zcml" />
   <include file="orderedselect.zcml" />
   <include file="password.zcml" />
   <include file="radio.zcml" />
@@ -14,5 +15,6 @@
   <include file="submit.zcml" />
   <include file="text.zcml" />
   <include file="textarea.zcml" />
+  <include file="textlines.zcml" />
 
 </configure>

Added: z3c.form/trunk/src/z3c/form/browser/multi.py
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/multi.py	                        (rev 0)
+++ z3c.form/trunk/src/z3c/form/browser/multi.py	2008-08-28 22:20:31 UTC (rev 90564)
@@ -0,0 +1,81 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (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.
+#
+##############################################################################
+"""Text Widget Implementation
+
+$Id: select.py 78513 2007-07-31 23:03:47Z srichter $
+"""
+__docformat__ = "reStructuredText"
+import zope.component
+import zope.interface
+import zope.schema
+import zope.schema.interfaces
+from zope.i18n import translate
+
+from z3c.form.i18n import MessageFactory as _
+from z3c.form import interfaces
+from z3c.form import widget
+from z3c.form import button
+from z3c.form.browser.widget import HTMLSelectWidget
+
+
+class FormMixin(object):
+    zope.interface.implements(interfaces.IButtonForm, interfaces.IHandlerForm)
+
+
+class MultiWidget(HTMLSelectWidget, widget.MultiWidget, FormMixin):
+    """Multi widget implementation."""
+    zope.interface.implements(interfaces.IMultiWidget)
+
+    buttons = button.Buttons()
+
+    prefix = 'widget'
+    klass = u'multi-widget'
+    items = ()
+
+    def updateActions(self):
+        self.actions = zope.component.getMultiAdapter(
+            (self, self.request, self), interfaces.IActions)
+        self.actions.update()
+
+    def update(self):
+        """See z3c.form.interfaces.IWidget."""
+        self.updateActions()
+        super(MultiWidget, self).update()
+        self.actions.execute()
+
+    @button.buttonAndHandler(_('Add'), name='add')
+    def handleAdd(self, action):
+        self.appendAddingWidget()
+
+    @button.buttonAndHandler(_('Remove'), name='remove')
+    def handleRemove(self, action):
+        ids = []
+        append = ids.append
+        counter = int(self.request.get(self.counterName, 0))
+        for widget in self.widgets:
+            name = '%s.remove' % (widget.name)
+            if name in self.request:
+                append(widget.id)
+        self.widgets = [widget for widget in self.widgets if widget.id not in ids]
+
+ at zope.interface.implementer(interfaces.IFieldWidget)
+def multiFieldWidgetFactory(field, request):
+    """IFieldWidget factory for TextLinesWidget."""
+    return widget.FieldWidget(field, MultiWidget(request))
+
+
+ at zope.interface.implementer(interfaces.IFieldWidget)
+def MultiFieldWidget(field, value_type, request):
+    """IFieldWidget factory for TextLinesWidget."""
+    return multiFieldWidgetFactory(field, request)


Property changes on: z3c.form/trunk/src/z3c/form/browser/multi.py
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.form/trunk/src/z3c/form/browser/multi.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/multi.txt	                        (rev 0)
+++ z3c.form/trunk/src/z3c/form/browser/multi.txt	2008-08-28 22:20:31 UTC (rev 90564)
@@ -0,0 +1,522 @@
+============
+Multi Widget
+============
+
+The multi widget allows you to add and edit one or more values.
+
+As for all widgets, the multi widget must provide the new ``IWidget``
+interface:
+
+  >>> from zope.interface.verify import verifyClass
+  >>> from z3c.form import interfaces
+  >>> from z3c.form.browser import multi
+
+  >>> verifyClass(interfaces.IWidget, multi.MultiWidget)
+  True
+
+The widget can be instantiated only using the request:
+
+  >>> from z3c.form.testing import TestRequest
+  >>> request = TestRequest()
+  >>> widget = multi.MultiWidget(request)
+
+Before rendering the widget, one has to set the name and id of the widget:
+
+  >>> widget.id = 'widget-id'
+  >>> widget.name = 'widget.name'
+
+We also need to register the template for at least 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('multi_input.pt'), 'text/html'),
+  ...     (None, None, None, None, interfaces.IMultiWidget),
+  ...     IPageTemplate, name=interfaces.INPUT_MODE)
+
+For the next test, we need to setup our button handler adapters. If we render 
+the widget we get an emtpy widget:
+
+  >>> from z3c.form import button
+  >>> zope.component.provideAdapter(button.ButtonActions)
+  >>> zope.component.provideAdapter(button.ButtonActionHandler)
+  >>> zope.component.provideAdapter(button.ButtonAction,
+  ...     provides=interfaces.IButtonAction)
+
+And our submit buttons will need some template:
+
+  >>> zope.component.provideAdapter(
+  ...     WidgetTemplateFactory(getPath('submit_input.pt'), 'text/html'),
+  ...     (None, None, None, None, interfaces.ISubmitWidget),
+  ...     IPageTemplate, name=interfaces.INPUT_MODE)
+
+  >>> widget.update()
+  >>> print widget.render()
+  <div class="multi-widget">
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="widget.name.count" value="0" />
+
+As you can see the widget is empty and doesn't provide values. Let's
+update the widget and check it again. But first register a IFieldWidget adapter
+and a template for our IInt field:
+
+  >>> import z3c.form.interfaces
+  >>> from z3c.form.browser.text import TextFieldWidget
+  >>> zope.component.provideAdapter(TextFieldWidget,
+  ...     (zope.schema.interfaces.IInt, z3c.form.interfaces.IFormLayer))
+
+  >>> zope.component.provideAdapter(
+  ...     WidgetTemplateFactory(getPath('text_input.pt'), 'text/html'),
+  ...     (None, None, None, None, interfaces.ITextWidget),
+  ...     IPageTemplate, name=interfaces.INPUT_MODE)
+
+  >>> widget.update()
+  >>> print widget.render()
+  <div class="multi-widget">
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="widget.name.count" value="0" />
+
+It's still the same. Since the widget doesn't provide a field nothing useful
+get rendered. Now let's define a fiel for this widget and check it again:
+
+  >>> field = zope.schema.List(
+  ...     __name__=u'foo',
+  ...     value_type=zope.schema.Int(title=u'Number'),
+  ...     )
+  >>> widget.field = field
+  >>> widget.update()
+  >>> print widget.render()
+  <div class="multi-widget">
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="widget.name.count" value="0" />
+
+As you can see, there is still no input value. Let's provide some values for 
+this widget. Before we can do that, we will need to register a data converter 
+for our multi widget and the data converter dispatcher adapter:
+
+  >>> from z3c.form.converter import IntegerDataConverter
+  >>> from z3c.form.converter import FieldWidgetDataConverter
+  >>> from z3c.form.validator import SimpleFieldValidator
+  >>> zope.component.provideAdapter(IntegerDataConverter)
+  >>> zope.component.provideAdapter(FieldWidgetDataConverter)
+  >>> zope.component.provideAdapter(SimpleFieldValidator)
+
+  >>> widget.update()
+  >>> widget.value = [u'42', u'43']
+  >>> print widget.render()
+  <div class="multi-widget">
+      <div id="widget-id-0-row" class="row">
+          <div class="label">
+            <label for="widget-id-0">
+              <span>Number</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="widget-id-0-remove"
+                     name="widget.name.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="widget-id-0" name="widget.name.0"
+                 class="text-widget required int-field" value="42" />
+          </div>
+        </div>
+      </div>
+      <div id="widget-id-1-row" class="row">
+          <div class="label">
+            <label for="widget-id-1">
+              <span>Number</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="widget-id-1-remove"
+                     name="widget.name.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="widget-id-1" name="widget.name.1"
+                 class="text-widget required int-field" value="43" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="widget.name.count" value="2" />
+
+If we now oush the ``Add`` button, we will get a new input field for enter a
+new value:
+
+  >>> widget.request = TestRequest(form={'widget.name.count':u'2',
+  ...                                    'widget.name.0':u'42',
+  ...                                    'widget.name.1':u'43',
+  ...                                    'widget.buttons.add':'Add'})
+  >>> widget.update()
+  >>> print widget.render()
+  <div class="multi-widget">
+      <div id="widget-id-0-row" class="row">
+          <div class="label">
+            <label for="widget-id-0">
+              <span>Number</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="widget-id-0-remove"
+                     name="widget.name.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="widget-id-0" name="widget.name.0"
+                 class="text-widget required int-field" value="42" />
+          </div>
+        </div>
+      </div>
+      <div id="widget-id-1-row" class="row">
+          <div class="label">
+            <label for="widget-id-1">
+              <span>Number</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="widget-id-1-remove"
+                     name="widget.name.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="widget-id-1" name="widget.name.1"
+                 class="text-widget required int-field" value="43" />
+          </div>
+        </div>
+      </div>
+      <div id="widget-id-2-row" class="row">
+          <div class="label">
+            <label for="widget-id-2">
+              <span>Number</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="widget-id-2-remove"
+                     name="widget.name.2.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="widget-id-2" name="widget.name.2"
+                 class="text-widget required int-field" value="" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="widget.name.count" value="3" />
+
+Now let's store the new value:
+
+  >>> widget.request = TestRequest(form={'widget.name.count':u'3',
+  ...                                    'widget.name.0':u'42',
+  ...                                    'widget.name.1':u'43',
+  ...                                    'widget.name.2':u'44'})
+  >>> widget.update()
+  >>> print widget.render()
+  <div class="multi-widget">
+      <div id="widget-id-0-row" class="row">
+          <div class="label">
+            <label for="widget-id-0">
+              <span>Number</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="widget-id-0-remove"
+                     name="widget.name.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="widget-id-0" name="widget.name.0"
+                 class="text-widget required int-field" value="42" />
+          </div>
+        </div>
+      </div>
+      <div id="widget-id-1-row" class="row">
+          <div class="label">
+            <label for="widget-id-1">
+              <span>Number</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="widget-id-1-remove"
+                     name="widget.name.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="widget-id-1" name="widget.name.1"
+                 class="text-widget required int-field" value="43" />
+          </div>
+        </div>
+      </div>
+      <div id="widget-id-2-row" class="row">
+          <div class="label">
+            <label for="widget-id-2">
+              <span>Number</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="widget-id-2-remove"
+                     name="widget.name.2.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="widget-id-2" name="widget.name.2"
+         class="text-widget required int-field" value="44" />
+  </div>
+          </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="widget.name.count" value="3" />
+
+As you can see in the above sample, the new stored value get rendered as a 
+real value and the new adding value input field is gone. Now let's try
+to remove an existing value:
+
+  >>> widget.request = TestRequest(form={'widget.name.count':u'3',
+  ...                                    'widget.name.0':u'42',
+  ...                                    'widget.name.1':u'43',
+  ...                                    'widget.name.2':u'44',
+  ...                                    'widget.name.1.remove':u'1',
+  ...                                    'widget.buttons.remove':'Remove'})
+  >>> widget.update()
+  >>> print widget.render()
+  <div class="multi-widget">
+      <div id="widget-id-0-row" class="row">
+          <div class="label">
+            <label for="widget-id-0">
+              <span>Number</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="widget-id-0-remove"
+                     name="widget.name.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="widget-id-0" name="widget.name.0"
+                 class="text-widget required int-field" value="42" />
+          </div>
+        </div>
+      </div>
+      <div id="widget-id-2-row" class="row">
+          <div class="label">
+            <label for="widget-id-2">
+              <span>Number</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="widget-id-2-remove"
+                     name="widget.name.2.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="widget-id-2" name="widget.name.2"
+                 class="text-widget required int-field" value="44" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="widget.name.count" value="2" />
+
+Show how the error handling works. Let's use a bad none integer value as input
+for our internal (sub) widget.
+
+  >>> from z3c.form.error import ErrorViewSnippet
+    >>> from z3c.form.error import StandardErrorViewTemplate
+  >>> zope.component.provideAdapter(ErrorViewSnippet)
+  >>> zope.component.provideAdapter(StandardErrorViewTemplate)
+
+  >>> widget.request = TestRequest(form={'widget.name.count':u'2',
+  ...                                    'widget.name.0':u'42',
+  ...                                    'widget.name.1':u'bad'})
+  >>> widget.update()
+  >>> print widget.render()
+  <div class="multi-widget">
+      <div id="widget-id-0-row" class="row">
+          <div class="label">
+            <label for="widget-id-0">
+              <span>Number</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="widget-id-0-remove"
+                     name="widget.name.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="widget-id-0" name="widget.name.0"
+                 class="text-widget required int-field" value="42" />
+          </div>
+        </div>
+      </div>
+      <div id="widget-id-1-row" class="row">
+          <div class="label">
+            <label for="widget-id-1">
+              <span>Number</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="widget-id-1-remove"
+                     name="widget.name.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="widget-id-1" name="widget.name.1"
+                 class="text-widget required int-field" value="bad" />
+            </div>
+          </div>
+          <div class="error">
+            <div class="error">The entered value is not a valid integer literal.</div>
+          </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="widget.name.count" value="2" />
+
+
+Label
+-----
+
+There is an option which allows to disable the label for the (sub) widgets.
+You can set the option showLabel to False which will skip rendering the labels.
+Or of corse you can register your own template for your layer if you like to 
+skip the label rendering for all widgets.
+
+  >>> field = zope.schema.List(
+  ...     __name__=u'foo',
+  ...     value_type=zope.schema.Int(
+  ...         title=u'Ignored'),
+  ...     )
+  >>> request = TestRequest()
+  >>> widget = multi.MultiWidget(request)
+  >>> widget.field = field
+  >>> widget.value = [u'42', u'43']
+  >>> widget.showLabel = False
+  >>> widget.update()
+  >>> print widget.render()
+  <div class="multi-widget">
+      <div id="None-0-row" class="row">
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="None-0-remove" name="None.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="None-0" name="None.0"
+                 class="text-widget required int-field" value="42" />
+          </div>
+        </div>
+      </div>
+      <div id="None-1-row" class="row">
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="None-1-remove" name="None.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input type="text" id="None-1" name="None.1"
+                 class="text-widget required int-field" value="43" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-buttons-add"
+         name="widget.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-buttons-remove"
+         name="widget.buttons.remove"
+         class="submit-widget button-field" value="Remove" />
+     </div>
+  </div>
+  <input type="hidden" name="None.count" value="2" />


Property changes on: z3c.form/trunk/src/z3c/form/browser/multi.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.form/trunk/src/z3c/form/browser/multi.zcml
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/multi.zcml	                        (rev 0)
+++ z3c.form/trunk/src/z3c/form/browser/multi.zcml	2008-08-28 22:20:31 UTC (rev 90564)
@@ -0,0 +1,50 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:z3c="http://namespaces.zope.org/z3c"
+    i18n_domain="z3c.form">
+
+  <class class=".multi.MultiWidget">
+    <require
+        permission="zope.Public"
+        interface="z3c.form.interfaces.IMultiWidget"
+        />
+  </class>
+
+  <adapter
+      factory=".multi.MultiFieldWidget"
+      provides="z3c.form.interfaces.IFieldWidget"
+      for="zope.schema.interfaces.IList
+           zope.schema.interfaces.IField
+           z3c.form.interfaces.IFormLayer"
+      />
+
+  <adapter
+      factory=".multi.MultiFieldWidget"
+      provides="z3c.form.interfaces.IFieldWidget"
+      for="zope.schema.interfaces.ITuple
+           zope.schema.interfaces.IField
+           z3c.form.interfaces.IFormLayer"
+      />
+
+  <z3c:widgetTemplate
+      mode="display"
+      widget="z3c.form.interfaces.IMultiWidget"
+      layer="z3c.form.interfaces.IFormLayer"
+      template="multi_display.pt"
+      />
+
+  <z3c:widgetTemplate
+      mode="input"
+      widget="z3c.form.interfaces.IMultiWidget"
+      layer="z3c.form.interfaces.IFormLayer"
+      template="multi_input.pt"
+      />
+
+  <z3c:widgetTemplate
+      mode="hidden"
+      widget="z3c.form.interfaces.IMultiWidget"
+      layer="z3c.form.interfaces.IFormLayer"
+      template="multi_hidden.pt"
+      />
+
+</configure>


Property changes on: z3c.form/trunk/src/z3c/form/browser/multi.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.form/trunk/src/z3c/form/browser/multi_display.pt
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/multi_display.pt	                        (rev 0)
+++ z3c.form/trunk/src/z3c/form/browser/multi_display.pt	2008-08-28 22:20:31 UTC (rev 90564)
@@ -0,0 +1,22 @@
+<span id="" class=""
+      tal:attributes="id view/id;
+                      class view/klass;
+                      style view/style;
+                      title view/title;
+                      lang view/lang;
+                      onclick view/onclick;
+                      ondblclick view/ondblclick;
+                      onmousedown view/onmousedown;
+                      onmouseup view/onmouseup;
+                      onmouseover view/onmouseover;
+                      onmousemove view/onmousemove;
+                      onmouseout view/onmouseout;
+                      onkeypress view/onkeypress;
+                      onkeydown view/onkeydown;
+                      onkeyup view/onkeyup"><tal:block
+    tal:repeat="value view/displayValue"
+    ><span class="selected-option"
+           tal:content="value"
+    /><tal:block condition="not:repeat/value/end">, </tal:block
+  ></tal:block
+></span>


Property changes on: z3c.form/trunk/src/z3c/form/browser/multi_display.pt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.form/trunk/src/z3c/form/browser/multi_hidden.pt
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/multi_hidden.pt	                        (rev 0)
+++ z3c.form/trunk/src/z3c/form/browser/multi_hidden.pt	2008-08-28 22:20:31 UTC (rev 90564)
@@ -0,0 +1,9 @@
+<tal:block define="id view/id;
+                   name string:${view/name}:list"
+           repeat="item view/items">
+  <input type="hidden" name="" class="hidden-widget"
+         tal:condition="item/selected"
+         tal:attributes="name name; value item/value; id item/id" />
+</tal:block>
+<input name="field-empty-marker" type="hidden" value="1"
+       tal:attributes="name string:${view/name}-empty-marker" />


Property changes on: z3c.form/trunk/src/z3c/form/browser/multi_hidden.pt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.form/trunk/src/z3c/form/browser/multi_input.pt
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/multi_input.pt	                        (rev 0)
+++ z3c.form/trunk/src/z3c/form/browser/multi_input.pt	2008-08-28 22:20:31 UTC (rev 90564)
@@ -0,0 +1,40 @@
+<div class="multi-widget"
+     tal:attributes="class view/klass">
+  <tal:block repeat="widget view/widgets">
+    <div id="" class="row"
+         tal:attributes="id string:${widget/id}-row"
+         tal:condition="python:widget.mode != 'hidden'">
+      <metal:block define-macro="widget-row">
+        <div class="label" tal:condition="view/showLabel">
+          <label tal:attributes="for widget/id">
+            <span i18n:translate=""
+                tal:content="widget/label">label</span>
+            <span class="required"
+                  tal:condition="widget/required">*</span>
+          </label>
+        </div>
+        <div class="widget">
+          <div class="multi-widget-checkbox">
+            <input type="checkbox" value="1" class="multi-widget-checkbox checkbox-widget"
+                   tal:attributes="id string:${widget/id}-remove;
+                                   name string:${widget/name}.remove" />
+          </div>
+          <div class="multi-widget-input"
+               tal:content="structure widget/render">
+            <input type="text" size="24" value="" />
+          </div>
+        </div>
+        <div class="error"
+             tal:condition="widget/error">
+          <span tal:replace="structure widget/error/render">error</span>
+        </div>
+      </metal:block>
+    </div>
+  </tal:block>
+  <div class="buttons">
+    <input tal:repeat="action view/actions/values"
+           tal:replace="structure action/render"
+           />
+   </div>
+</div>
+<input type="hidden" tal:replace="structure view/counterMarker" />


Property changes on: z3c.form/trunk/src/z3c/form/browser/multi_input.pt
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: z3c.form/trunk/src/z3c/form/browser/orderedselect.py
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/orderedselect.py	2008-08-28 22:03:22 UTC (rev 90563)
+++ z3c.form/trunk/src/z3c/form/browser/orderedselect.py	2008-08-28 22:20:31 UTC (rev 90564)
@@ -83,8 +83,6 @@
         (field, field.value_type, request), interfaces.IFieldWidget)
 
 
- at zope.component.adapter(zope.schema.interfaces.ISequence,
-    zope.schema.interfaces.IChoice, interfaces.IFormLayer)
 @zope.interface.implementer(interfaces.IFieldWidget)
 def SequenceChoiceSelectFieldWidget(field, value_type, request):
     """IFieldWidget factory for SelectWidget."""

Modified: z3c.form/trunk/src/z3c/form/browser/orderedselect.zcml
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/orderedselect.zcml	2008-08-28 22:03:22 UTC (rev 90563)
+++ z3c.form/trunk/src/z3c/form/browser/orderedselect.zcml	2008-08-28 22:20:31 UTC (rev 90564)
@@ -16,8 +16,18 @@
 
   <adapter
       factory=".orderedselect.SequenceChoiceSelectFieldWidget"
+      for="zope.schema.interfaces.IList
+           zope.schema.interfaces.IChoice
+           z3c.form.interfaces.IFormLayer"
       />
 
+  <adapter
+      factory=".orderedselect.SequenceChoiceSelectFieldWidget"
+      for="zope.schema.interfaces.ITuple
+           zope.schema.interfaces.IChoice
+           z3c.form.interfaces.IFormLayer"
+      />
+
   <z3c:widgetTemplate
       mode="display"
       widget="z3c.form.interfaces.IOrderedSelectWidget"

Modified: z3c.form/trunk/src/z3c/form/browser/tests.py
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/tests.py	2008-08-28 22:03:22 UTC (rev 90563)
+++ z3c.form/trunk/src/z3c/form/browser/tests.py	2008-08-28 22:20:31 UTC (rev 90564)
@@ -69,4 +69,12 @@
                      setUp=testing.setUp, tearDown=testing.tearDown,
                      optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
                      ),
+        DocFileSuite('textlines.txt',
+                     setUp=testing.setUp, tearDown=testing.tearDown,
+                     optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+                     ),
+        DocFileSuite('multi.txt',
+                     setUp=testing.setUp, tearDown=testing.tearDown,
+                     optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+                     ),
         ))

Added: z3c.form/trunk/src/z3c/form/browser/textlines.py
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/textlines.py	                        (rev 0)
+++ z3c.form/trunk/src/z3c/form/browser/textlines.py	2008-08-28 22:20:31 UTC (rev 90564)
@@ -0,0 +1,44 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (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: __init__.py 97 2007-03-29 22:58:27Z rineichen $
+"""
+__docformat__ = "reStructuredText"
+
+import zope.component
+import zope.interface
+import zope.schema.interfaces
+
+from z3c.form.i18n import MessageFactory as _
+from z3c.form.interfaces import IFormLayer
+from z3c.form.interfaces import IFieldWidget
+from z3c.form import interfaces
+from z3c.form import widget
+from z3c.form.browser import textarea
+
+
+class TextLinesWidget(textarea.TextAreaWidget):
+    """Input type sequence widget implementation."""
+    zope.interface.implementsOnly(interfaces.ITextLinesWidget)
+
+
+def TextLinesFieldWidget(field, request):
+    """IFieldWidget factory for TextLinesWidget."""
+    return widget.FieldWidget(field, TextLinesWidget(request))
+
+
+ at zope.interface.implementer(interfaces.IFieldWidget)
+def TextLinesFieldWidgetFactory(field, value_type, request):
+    """IFieldWidget factory for TextLinesWidget."""
+    return TextLinesFieldWidget(field, request)


Property changes on: z3c.form/trunk/src/z3c/form/browser/textlines.py
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.form/trunk/src/z3c/form/browser/textlines.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/textlines.txt	                        (rev 0)
+++ z3c.form/trunk/src/z3c/form/browser/textlines.txt	2008-08-28 22:20:31 UTC (rev 90564)
@@ -0,0 +1,56 @@
+================
+TextLines Widget
+================
+
+The text lines widget allows you to store a sequence of textline. This sequence
+is stored as a list or tuple. This depends on what you are using as sequence
+type.
+
+As for all widgets, the text lines widget must provide the new ``IWidget``
+interface:
+
+  >>> from zope.interface.verify import verifyClass
+  >>> from z3c.form import interfaces
+  >>> from z3c.form.browser import textlines
+
+  >>> verifyClass(interfaces.IWidget, textlines.TextLinesWidget)
+  True
+
+The widget can be instantiated only using the request:
+
+  >>> from z3c.form.testing import TestRequest
+  >>> request = TestRequest()
+
+  >>> widget = textlines.TextLinesWidget(request)
+
+Before rendering the widget, one has to set the name and id of the widget:
+
+  >>> widget.id = 'id'
+  >>> widget.name = 'name'
+
+We also need to register the template for at least 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('textlines_input.pt'), 'text/html'),
+  ...     (None, None, None, None, interfaces.ITextLinesWidget),
+  ...     IPageTemplate, name=interfaces.INPUT_MODE)
+
+If we render the widget we get an emtpy textarea widget:
+
+  >>> print widget.render()
+  <textarea id="id" name="name" class="textarea-widget"></textarea>
+
+Adding some more attributes to the widget will make it display more:
+
+  >>> widget.id = 'id'
+  >>> widget.name = 'name'
+  >>> widget.value = u'foo\nbar'
+
+  >>> print widget.render()
+  <textarea id="id" name="name" class="textarea-widget">foo
+  bar</textarea>


Property changes on: z3c.form/trunk/src/z3c/form/browser/textlines.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.form/trunk/src/z3c/form/browser/textlines.zcml
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/textlines.zcml	                        (rev 0)
+++ z3c.form/trunk/src/z3c/form/browser/textlines.zcml	2008-08-28 22:20:31 UTC (rev 90564)
@@ -0,0 +1,29 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:z3c="http://namespaces.zope.org/z3c"
+    i18n_domain="z3c.form">
+
+  <class class=".textlines.TextLinesWidget">
+    <require
+        permission="zope.Public"
+        interface="z3c.form.interfaces.ITextLinesWidget"
+        />
+  </class>
+
+  <!-- this widget is not configured for any field by default -->
+
+  <z3c:widgetTemplate
+      mode="display"
+      widget="z3c.form.interfaces.ITextLinesWidget"
+      layer="z3c.form.interfaces.IFormLayer"
+      template="textlines_display.pt"
+      />
+
+  <z3c:widgetTemplate
+      mode="input"
+      widget="z3c.form.interfaces.ITextLinesWidget"
+      layer="z3c.form.interfaces.IFormLayer"
+      template="textlines_input.pt"
+      />
+
+</configure>


Property changes on: z3c.form/trunk/src/z3c/form/browser/textlines.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.form/trunk/src/z3c/form/browser/textlines_display.pt
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/textlines_display.pt	                        (rev 0)
+++ z3c.form/trunk/src/z3c/form/browser/textlines_display.pt	2008-08-28 22:20:31 UTC (rev 90564)
@@ -0,0 +1,18 @@
+<span id="" class=""
+      tal:attributes="id view/id;
+                      class view/klass;
+                      style view/style;
+                      title view/title;
+                      lang view/lang;
+                      onclick view/onclick;
+                      ondblclick view/ondblclick;
+                      onmousedown view/onmousedown;
+                      onmouseup view/onmouseup;
+                      onmouseover view/onmouseover;
+                      onmousemove view/onmousemove;
+                      onmouseout view/onmouseout;
+                      onkeypress view/onkeypress;
+                      onkeydown view/onkeydown;
+                      onkeyup view/onkeyup"><tal:block
+      condition="view/value" content="view/value"
+/></span>


Property changes on: z3c.form/trunk/src/z3c/form/browser/textlines_display.pt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.form/trunk/src/z3c/form/browser/textlines_input.pt
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/textlines_input.pt	                        (rev 0)
+++ z3c.form/trunk/src/z3c/form/browser/textlines_input.pt	2008-08-28 22:20:31 UTC (rev 90564)
@@ -0,0 +1,30 @@
+<textarea
+    id="" name="" class="" cols="" rows=""
+    tabindex="" disabled="" readonly="" accesskey=""
+    tal:attributes="id view/id;
+                    name view/name;
+                    class view/klass;
+                    style view/style;
+                    title view/title;
+                    lang view/lang;
+                    onclick view/onclick;
+                    ondblclick view/ondblclick;
+                    onmousedown view/onmousedown;
+                    onmouseup view/onmouseup;
+                    onmouseover view/onmouseover;
+                    onmousemove view/onmousemove;
+                    onmouseout view/onmouseout;
+                    onkeypress view/onkeypress;
+                    onkeydown view/onkeydown;
+                    onkeyup view/onkeyup;
+                    disabled view/disabled;
+                    tabindex view/tabindex;
+                    onfocus view/onfocus;
+                    onblur view/onblur;
+                    onchange view/onchange;
+                    cols view/cols;
+                    rows view/rows;
+                    readonly view/readonly;
+                    accesskey view/accesskey;
+                    onselect view/onselect"
+    tal:content="structure view/value" />


Property changes on: z3c.form/trunk/src/z3c/form/browser/textlines_input.pt
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: z3c.form/trunk/src/z3c/form/configure.zcml
===================================================================
--- z3c.form/trunk/src/z3c/form/configure.zcml	2008-08-28 22:03:22 UTC (rev 90563)
+++ z3c.form/trunk/src/z3c/form/configure.zcml	2008-08-28 22:20:31 UTC (rev 90564)
@@ -67,6 +67,12 @@
   <adapter
       factory=".converter.FieldWidgetDataConverter"
       />
+  <adapter
+      factory=".converter.TextLinesConverter"
+      />
+  <adapter
+      factory=".converter.MultiConverter"
+      />
 
   <!-- ITerms -->
   <adapter

Modified: z3c.form/trunk/src/z3c/form/converter.py
===================================================================
--- z3c.form/trunk/src/z3c/form/converter.py	2008-08-28 22:03:22 UTC (rev 90563)
+++ z3c.form/trunk/src/z3c/form/converter.py	2008-08-28 22:20:31 UTC (rev 90564)
@@ -36,7 +36,6 @@
         self.field = field
         self.widget = widget
 
-
     def toWidgetValue(self, value):
         """See interfaces.IDataConverter"""
         if value is self.field.missing_value:
@@ -290,6 +289,64 @@
         return collectionType([widget.terms.getValue(token) for token in value])
 
 
+class TextLinesConverter(BaseDataConverter):
+    """Data converter for ITextLinesWidget."""
+
+    zope.component.adapts(
+        zope.schema.interfaces.ISequence, interfaces.ITextLinesWidget)
+
+    def toWidgetValue(self, value):
+        """Convert from text lines to HTML representation."""
+        # if the value is the missing value, then an empty list is produced.
+        if value is self.field.missing_value:
+            return u''
+        return "\n".join(value)
+
+    def toFieldValue(self, value):
+        """See interfaces.IDataConverter"""
+        widget = self.widget
+        collectionType = self.field._type
+        if not len(value):
+            return self.field.missing_value
+        valueType = self.field.value_type._type
+        values = [valueType(v) for v in value.split()]
+        return collectionType(values)
+
+
+class MultiConverter(BaseDataConverter):
+    """Data converter for IMultiWidget."""
+
+    zope.component.adapts(
+        zope.schema.interfaces.ISequence, interfaces.IMultiWidget)
+
+    def toWidgetValue(self, value):
+        """Just dispatch it."""
+        if value is self.field.missing_value:
+            return []
+        # We relay on the default registered widget, this is probably a 
+        # restriction for custom widgets. If so use your own MultiWidget and
+        # register your own converter which will get the right widget for the
+        # used value_type.
+        field = self.field.value_type
+        widget = zope.component.getMultiAdapter((field, self.widget.request),
+            interfaces.IFieldWidget)
+        converter = zope.component.getMultiAdapter((field, widget),
+            interfaces.IDataConverter)
+
+        # we always return a list of values for the widget
+        return [converter.toWidgetValue(v) for v in value]
+
+    def toFieldValue(self, value):
+        """See interfaces.IDataConverter"""
+        collectionType = self.field._type
+        if not len(value):
+            return self.field.missing_value
+        valueType = self.field.value_type._type
+        values = [valueType(v) for v in value]
+        # convert the field values to a tuple or list 
+        return collectionType(values)
+
+
 class BoolSingleCheckboxDataConverter(BaseDataConverter):
     "A special converter between boolean fields and single checkbox widgets."
 

Modified: z3c.form/trunk/src/z3c/form/converter.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/converter.txt	2008-08-28 22:03:22 UTC (rev 90563)
+++ z3c.form/trunk/src/z3c/form/converter.txt	2008-08-28 22:20:31 UTC (rev 90564)
@@ -642,3 +642,43 @@
 
 Note that this widget has no concept of missing value, since it can only
 represent two states by desgin.
+
+
+TextLines Data Converter
+------------------------
+
+For sequence widgets and fields that work with a sequence of TextLine, a simple
+data converter is required. Let's now create a list of text lines field and a 
+widget:
+
+  >>> languages = zope.schema.List(
+  ...     value_type=zope.schema.TextLine(),
+  ...     default=[],
+  ...     missing_value=None,
+  ...     )
+
+  >>> from z3c.form.browser import textlines
+  >>> tlWidget = textlines.TextLinesWidget(TestRequest())
+  >>> tlWidget.field = languages
+
+We now use the field and widget to instantiate the converter:
+
+  >>> tlc = converter.TextLinesConverter(languages, tlWidget)
+
+We can now convert a real value to a widget value:
+
+  >>> tlc.toWidgetValue([u'de', u'fr', u'en'])
+  u'de\nfr\nen'
+
+
+The result is always a string, since textlines widgets only deal with textarea 
+as input field. Of course, we can convert the widget value back to an internal
+value:
+
+  >>> tlc.toFieldValue('de\nfr\nen')
+  [u'de', u'fr', u'en']
+
+An empty string will also cause the missing value to be returned:
+
+  >>> tlc.toFieldValue('') is None
+  True

Modified: z3c.form/trunk/src/z3c/form/interfaces.py
===================================================================
--- z3c.form/trunk/src/z3c/form/interfaces.py	2008-08-28 22:03:22 UTC (rev 90563)
+++ z3c.form/trunk/src/z3c/form/interfaces.py	2008-08-28 22:20:31 UTC (rev 90564)
@@ -400,8 +400,21 @@
 
 
 class ISequenceWidget(IWidget):
-    """Sequence widget."""
+    """Term based sequence widget base.
+    
+    The sequence widget is used for select items from a sequence. Don't get
+    confused, this widget does support to choose one or more values from a
+    sequence. The word sequence is not used for the schema field, it's used 
+    for the values where this widget can choose from.
 
+    This widget base class is used for build single or sequence values based
+    on a sequence which is in most use case a collection. e.g.
+    IList of IChoice for sequence values or IChoice for single values.
+    
+    See also the MultiWidget for build sequence values based on none collection
+    based values. e.g. IList of ITextLine
+    """
+
     noValueToken = zope.schema.ASCIILine(
         title=_('NOVALUE Token'),
         description=_('The token to be used, if no value has been selected.'))
@@ -419,6 +432,21 @@
         """
 
 
+class IMultiWidget(IWidget):
+    """None Term based sequence widget base.
+    
+    The multi widget is used for ITuple or IList if no other widget is defined.
+    
+    Some IList or ITuple are using another specialized widget if they can
+    choose from a collection. e.g. a IList of IChoice. The base class of such
+    widget is the ISequenceWidget. 
+    
+    This widget can handle none collection based sequences and offers add or 
+    remove values to or from the sequence. Each sequence value get rendered by 
+    it's own relevant widget. e.g. IList of ITextLine or ITuple of IInt
+    """
+
+
 class ISelectWidget(ISequenceWidget):
     """Select widget with ITerms option."""
 
@@ -468,6 +496,9 @@
 class ITextAreaWidget(IWidget):
     """Text widget."""
 
+class ITextLinesWidget(IWidget):
+    """Text lines widget."""
+
 class ITextWidget(IWidget):
     """Text widget."""
 

Modified: z3c.form/trunk/src/z3c/form/widget.py
===================================================================
--- z3c.form/trunk/src/z3c/form/widget.py	2008-08-28 22:03:22 UTC (rev 90563)
+++ z3c.form/trunk/src/z3c/form/widget.py	2008-08-28 22:20:31 UTC (rev 90564)
@@ -143,8 +143,21 @@
 
 
 class SequenceWidget(Widget):
-    """Sequence widget."""
+    """Term based sequence widget base.
+    
+    The sequence widget is used for select items from a sequence. Don't get
+    confused, this widget does support to choose one or more values from a
+    sequence. The word sequence is not used for the schema field, it's used 
+    for the values where this widget can choose from.
 
+    This widget base class is used for build single or sequence values based
+    on a sequence which is in most use case a collection. e.g.
+    IList of IChoice for sequence values or IChoice for single values.
+    
+    See also the MultiWidget for build sequence values based on none collection
+    based values. e.g. IList of ITextLine
+    """
+
     zope.interface.implements(interfaces.ISequenceWidget)
 
     value = ()
@@ -187,6 +200,7 @@
             return []
         value = self.request.get(self.name, default)
         if value != default:
+            # do some kind of validation, at least only use existing values
             for token in value:
                 if token == self.noValueToken:
                     continue
@@ -197,6 +211,155 @@
         return value
 
 
+class MultiWidget(Widget):
+    """None Term based sequence widget base.
+    
+    The multi widget is used for ITuple or IList if no other widget is defined.
+    
+    Some IList or ITuple are using another specialized widget if they can
+    choose from a collection. e.g. a IList of IChoice. The base class of such
+    widget is the ISequenceWidget. 
+    
+    This widget can handle none collection based sequences and offers add or 
+    remove values to or from the sequence. Each sequence value get rendered by 
+    it's own relevant widget. e.g. IList of ITextLine or ITuple of IInt
+    
+    Each widget get rendered within a sequence value. This means each internal
+    widget will repressent one value from the mutli widget value. Based on the
+    nature of this (sub) widget setup the internal widget do not have a real
+    context and can't get binded to it. This makes it impossible to use a 
+    sequence of collection where the collection needs a context. But that
+    should not be a problem since sequence of collection will use the 
+    SequenceWidget as base.
+    """
+
+    zope.interface.implements(interfaces.IMultiWidget)
+
+    allowAdding = True
+    # you set showLabel to False or use another template for disable (sub)
+    # widget labels
+    showLabel = True
+    widgets = []
+    _value = []
+
+    @property
+    def counterName(self):
+        return '%s.count' % self.name
+
+    @property
+    def counterMarker(self):
+        # this get called in render from the template and contains always the 
+        # right amount of widgets we use.
+        return '<input type="hidden" name="%s" value="%d" />' % (
+            self.counterName, len(self.widgets))
+
+    def getWidget(self, idx):
+        """Setup widget based on index id with or without value."""
+        id = '%s-%i' % (self.id, idx)
+        name = '%s.%i' % (self.name, idx)
+        valueType = self.field.value_type
+        widget = zope.component.getMultiAdapter((valueType, self.request),
+            interfaces.IFieldWidget)
+        widget.name = name
+        widget.id = id
+        widget.update()
+        return widget
+
+    def appendAddingWidget(self):
+        """Simply append a new empty widget with correct (counter) name."""
+        # since we start with idx 0 (zero) we can use the len as next idx
+        idx = len(self.widgets)
+        widget = self.getWidget(idx)
+        self.widgets.append(widget)
+
+    def applyValue(self, widget, value=interfaces.NOVALUE):
+        """Validate and apply value to given widget.
+        
+        This method get called on any multi widget vaue change and is 
+        responsible for validate the given value and setup an error message.
+        
+        This is internal apply value and validation process is needed because 
+        nothing outside this mutli widget does know something about our 
+        internal sub widgets.
+        """
+        if value is not interfaces.NOVALUE:
+            try:
+                # convert widget value to field value
+                converter = interfaces.IDataConverter(widget)
+                value = converter.toFieldValue(value)
+                # validate field value
+                zope.component.getMultiAdapter(
+                    (self.context,
+                     self.request,
+                     self.form,
+                     getattr(widget, 'field', None),
+                     widget),
+                    interfaces.IValidator).validate(value)
+                # convert field value to widget value
+                widget.value = converter.toWidgetValue(value)
+            except (zope.schema.ValidationError, ValueError), error:
+                # on exception, setup the widget error message
+                view = zope.component.getMultiAdapter(
+                    (error, self.request, widget, widget.field,
+                     self.form, self.context), interfaces.IErrorViewSnippet)
+                view.update()
+                widget.error = view
+                # set the wrong value as value
+                widget.value = value
+
+    def updateWidgets(self):
+        """Setup internal widgets based on the value_type for each value item.
+        """
+        oldLen = len(self.widgets)
+        self.widgets = []
+        if self.value:
+            for idx, v in enumerate(self.value):
+                widget = self.getWidget(idx)
+                self.applyValue(widget, v)
+                self.widgets.append(widget)
+        missing = oldLen - len(self.widgets)
+        if missing > 0:
+            # add previous existing new added widgtes
+            for i in range(missing):
+                idx += 1
+                widget = self.getWidget(idx)
+                self.widgets.append(widget)
+
+    @apply
+    def value():
+        """This invokes updateWidgets on any value change e.g. update/extract."""
+        def get(self):
+            return self._value
+        def set(self, value):
+            self._value = value
+            # ensure that we apply our new values to the widgets
+            self.updateWidgets()
+        return property(get, set)
+
+    def extract(self, default=interfaces.NOVALUE):
+        # This method is responsible to get the widgets value based on the 
+        # request and nothing else.
+        # We have to setup the widgets for extract their values, because we 
+        # don't know how to do this for every field without the right widgets. 
+        # Later we will setup the widgets based on this values. This is needed
+        # because we probably set a new value in the fornm for our multi widget
+        # which whould generate a different set of widgets.
+        if self.request.get(self.counterName) is None:
+            # counter marker not found
+            return interfaces.NOVALUE
+        counter = int(self.request.get(self.counterName, 0))
+        values = []
+        append = values.append
+        # extract value for existing widgets
+        for idx in range(counter):
+            widget = self.getWidget(idx)
+            append(widget.value)
+        if len(values) == 0:
+            # no multi value found
+            return interfaces.NOVALUE
+        return values
+
+
 def FieldWidget(field, widget):
     """Set the field for the widget."""
     widget.field = field

Modified: z3c.form/trunk/src/z3c/form/widget.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/widget.txt	2008-08-28 22:03:22 UTC (rev 90563)
+++ z3c.form/trunk/src/z3c/form/widget.txt	2008-08-28 22:20:31 UTC (rev 90564)
@@ -478,6 +478,115 @@
 So that's it. Everything else is the same from then on.
 
 
+Multi Widget
+------------
+
+A common use case in user interfaces is to ask the user to define one or more
+items. The ``widget`` module provides a basic widget implementation to support 
+this use case.
+
+The MultiWidget allows to store none, one or more values for a sequence field.
+Don't get cinfused by the term sequence. Ther sequence used in SequenceWidget
+means that the widget can choose from a sequence of values which is a really
+a collection. The MultiWidget can collect values for build and store a 
+sequence of values like used in ITuple or IList field.
+
+  >>> request = TestRequest()
+  >>> multiWidget = widget.MultiWidget(request)
+  >>> multiWidget.name = 'multi.name'
+  >>> multiWidget.id = 'multi-id'
+
+  >>> multiWidget.value
+  []
+
+Let's define a field for our multi widget:
+
+  >>> multiField = zope.schema.List(
+  ...     value_type=zope.schema.Int(default=42))
+  >>> multiWidget.field = multiField
+
+The value of a multi widget is always list. When extracting values from the 
+request, the values must be a list of valid values based on the value_type
+field used from the used sequence field. The widget also uses a counter which
+is required for processing the input from a request. The counter is a marker
+for build the right amount of enumerated widgets.
+
+If we provide an empty counter we will get no value:
+
+If we provide no request we will get no value:
+
+  >>> multiWidget.extract()
+  <NOVALUE>
+
+If we provide an empty counter we will get no value:
+
+  >>> multiWidget.request = TestRequest(form={'multi.name.count':'0'})
+  >>> multiWidget.extract()
+  <NOVALUE>
+
+If we provide real values within the request, we will get it back:
+
+  >>> multiWidget.request = TestRequest(form={'multi.name.count':'2',
+  ...                                         'multi.name.0':u'42',
+  ...                                         'multi.name.1':u'43'})
+  >>> multiWidget.extract()
+  [u'42', u'43']
+
+If we provide a bad value we will get the bad value within the extract method.
+Our widget update process will validate this bad value later:
+
+  >>> multiWidget.request = TestRequest(form={'multi.name.count':'1',
+  ...                                         'multi.name.0':u'bad'})
+  >>> multiWidget.extract()
+  [u'bad']
+
+Storing a widget value forces to update the (sub) widgets. this forces also to 
+validate the (sub) widget values. For showing this we nee dot register a 
+validator:
+
+  >>> from z3c.form.validator import SimpleFieldValidator
+  >>> zope.component.provideAdapter(SimpleFieldValidator)
+
+Since the value of the widget is a list of (widget) value items, when 
+displaying the values, they can be used as they are:
+
+  >>> multiWidget.request = TestRequest(form={'multi.name.count':'2',
+  ...                                         'multi.name.0':u'42',
+  ...                                         'multi.name.1':u'43'})
+  >>> multiWidget.value = multiWidget.extract()
+  >>> multiWidget.value
+  [u'42', u'43']
+
+Each widget normaly gets first process by it's update method call after 
+intialization. This update call forces to call extract, which first will get
+the right amount of (sub) widgets by the given counter value. Based on that 
+counter value the right amount of widgets will get created. Each widget will
+return it's own value and this collected values get returned by the extract
+method. The multi widget update method will then store this values if any give
+as multi widget value argument. If extract doesnt return a value the multi
+widget update method will use it's default value. If we store a given value
+from the extract as multi widget value, this will force to setup the multi
+widget widgets based on the given values and apply the right value for them.
+After that the mutli widget is ready for rendering. The good thing about that
+pattern is that it is possible to set a value before or after the update method
+is called. At any time if we change the mutli widget value the (sub) widgets 
+get updated within the new relevant value.
+
+  >>> multiRequest = TestRequest(form={'multi.name.count':'2',
+  ...                                  'multi.name.0':u'42',
+  ...                                  'multi.name.1':u'43'})
+
+  >>> multiWidget = widget.FieldWidget(multiField, widget.MultiWidget(
+  ...     multiRequest))
+  >>> multiWidget.name = 'multi.name'
+  >>> multiWidget.value
+  []
+
+  >>> multiWidget.update()
+  >>> multiWidget.value
+  [u'42', u'43']
+
+
 Widget Events
 -------------
 

Added: z3c.form/trunk/src/z3c/form/widget_multi.pt
===================================================================
--- z3c.form/trunk/src/z3c/form/widget_multi.pt	                        (rev 0)
+++ z3c.form/trunk/src/z3c/form/widget_multi.pt	2008-08-28 22:20:31 UTC (rev 90564)
@@ -0,0 +1,6 @@
+<div class="multiWidget"
+     tal:attributes="class view/css">
+  <div tal:repeat="widget view/widgets">
+    <tal:block replace="widget/render">widget</tal:block>
+  </div>
+</div>


Property changes on: z3c.form/trunk/src/z3c/form/widget_multi.pt
___________________________________________________________________
Name: svn:eol-style
   + native



More information about the Checkins mailing list