From a80fc78945a362f2cea0d41e50d70ea1dea89b7d Mon Sep 17 00:00:00 2001
From: Kazuhiko Shiozaki <kazuhiko@nexedi.com>
Date: Wed, 20 Jan 2010 11:34:33 +0000
Subject: [PATCH] use the FormBox's key as the part of its inside fields' keys.
 now we can include FormBox inside ListBox.

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@31835 20353a03-c40f-0410-a6d1-a30d3c3de9de
---
 .../testFormBoxDialogParameter.xml            | 14 +++----
 .../form_box_zuite/testFormBoxEdit.xml        | 14 +++----
 .../testFormBoxParameterSavedInRequest.xml    | 22 +++++------
 .../form_box_zuite/testFormBoxValidator.xml   | 24 ++++++------
 bt5/erp5_ui_test/bt/revision                  |  2 +-
 .../portal_skins/erp5_core/Base_edit.xml      |  8 ++--
 product/ERP5/bootstrap/erp5_core/bt/revision  |  2 +-
 .../erp5_xhtml_style/field_render.xml         |  3 +-
 .../bootstrap/erp5_xhtml_style/bt/revision    |  2 +-
 product/ERP5Form/Form.py                      | 12 ++++--
 product/ERP5Form/FormBox.py                   | 12 ++++--
 product/Formulator/Field.py                   | 38 ++++++++++---------
 product/Formulator/Form.py                    |  4 +-
 13 files changed, 87 insertions(+), 70 deletions(-)

diff --git a/bt5/erp5_ui_test/PathTemplateItem/portal_tests/form_box_zuite/testFormBoxDialogParameter.xml b/bt5/erp5_ui_test/PathTemplateItem/portal_tests/form_box_zuite/testFormBoxDialogParameter.xml
index b824a19aa3..98a1b0adfd 100644
--- a/bt5/erp5_ui_test/PathTemplateItem/portal_tests/form_box_zuite/testFormBoxDialogParameter.xml
+++ b/bt5/erp5_ui_test/PathTemplateItem/portal_tests/form_box_zuite/testFormBoxDialogParameter.xml
@@ -43,7 +43,7 @@
       xmlns:metal="http://xml.zope.org/namespaces/metal">\n
 <head>\n
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">\n
-<title>Test Form Box Edition</title>\n
+<title>Test Form Box Dialog</title>\n
 </head>\n
 <body>\n
 <table cellpadding="1" cellspacing="1" border="1">\n
@@ -92,17 +92,17 @@
 </tr>\n
 <tr>\n
   <td>type</td>\n
-  <td>field_my_title</td>\n
+  <td>field_my_formbox_my_title</td>\n
   <td>Default title</td>\n
 </tr>\n
 <tr>\n
   <td>type</td>\n
-  <td>field_my_quantity</td>\n
+  <td>field_my_formbox_my_quantity</td>\n
   <td>99</td>\n
 </tr>\n
 <tr>\n
   <td>type</td>\n
-  <td>field_my_description</td>\n
+  <td>field_my_formbox_my_description</td>\n
   <td>Default description</td>\n
 </tr>\n
 \n
@@ -124,17 +124,17 @@
 </tr>\n
 <tr>\n
   <td>verifyValue</td>\n
-  <td>field_my_title</td>\n
+  <td>field_my_formbox_my_title</td>\n
   <td>Title 0</td>\n
 </tr>\n
 <tr>\n
   <td>verifyValue</td>\n
-  <td>field_my_quantity</td>\n
+  <td>field_my_formbox_my_quantity</td>\n
   <td>10.0</td>\n
 </tr>\n
 <tr>\n
   <td>verifyValue</td>\n
-  <td>field_my_description</td>\n
+  <td>field_my_formbox_my_description</td>\n
   <td></td>\n
 </tr>\n
 \n
diff --git a/bt5/erp5_ui_test/PathTemplateItem/portal_tests/form_box_zuite/testFormBoxEdit.xml b/bt5/erp5_ui_test/PathTemplateItem/portal_tests/form_box_zuite/testFormBoxEdit.xml
index 9694d581d4..ee5bb8f2d0 100644
--- a/bt5/erp5_ui_test/PathTemplateItem/portal_tests/form_box_zuite/testFormBoxEdit.xml
+++ b/bt5/erp5_ui_test/PathTemplateItem/portal_tests/form_box_zuite/testFormBoxEdit.xml
@@ -48,7 +48,7 @@
 <body>\n
 <table cellpadding="1" cellspacing="1" border="1">\n
 <thead>\n
-<tr><td rowspan="1" colspan="3">Test Form Box</td></tr>\n
+<tr><td rowspan="1" colspan="3">Test Form Box Edition</td></tr>\n
 </thead><tbody>\n
 <tal:block metal:use-macro="here/RelationFieldZuite_CommonTemplate/macros/init" />\n
 <tr>\n
@@ -81,17 +81,17 @@
 <!-- Initialize -->\n
 <tr>\n
   <td>type</td>\n
-  <td>field_my_title</td>\n
+  <td>field_my_formbox_my_title</td>\n
   <td>Default title</td>\n
 </tr>\n
 <tr>\n
   <td>type</td>\n
-  <td>field_my_quantity</td>\n
+  <td>field_my_formbox_my_quantity</td>\n
   <td>99</td>\n
 </tr>\n
 <tr>\n
   <td>type</td>\n
-  <td>field_my_description</td>\n
+  <td>field_my_formbox_my_description</td>\n
   <td>Default description</td>\n
 </tr>\n
 <tr>\n
@@ -106,17 +106,17 @@
 </tr>\n
 <tr>\n
   <td>verifyValue</td>\n
-  <td>field_my_title</td>\n
+  <td>field_my_formbox_my_title</td>\n
   <td>Default title</td>\n
 </tr>\n
 <tr>\n
   <td>verifyValue</td>\n
-  <td>field_my_quantity</td>\n
+  <td>field_my_formbox_my_quantity</td>\n
   <td>99.0</td>\n
 </tr>\n
 <tr>\n
   <td>verifyValue</td>\n
-  <td>field_my_description</td>\n
+  <td>field_my_formbox_my_description</td>\n
   <td>Default description</td>\n
 </tr>\n
 \n
diff --git a/bt5/erp5_ui_test/PathTemplateItem/portal_tests/form_box_zuite/testFormBoxParameterSavedInRequest.xml b/bt5/erp5_ui_test/PathTemplateItem/portal_tests/form_box_zuite/testFormBoxParameterSavedInRequest.xml
index 18f5d88d8e..60a6a1bd89 100644
--- a/bt5/erp5_ui_test/PathTemplateItem/portal_tests/form_box_zuite/testFormBoxParameterSavedInRequest.xml
+++ b/bt5/erp5_ui_test/PathTemplateItem/portal_tests/form_box_zuite/testFormBoxParameterSavedInRequest.xml
@@ -43,12 +43,12 @@
       xmlns:metal="http://xml.zope.org/namespaces/metal">\n
 <head>\n
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">\n
-<title>Test Form Box Edition</title>\n
+<title>Test Form Box Parameter Saved in Request</title>\n
 </head>\n
 <body>\n
 <table cellpadding="1" cellspacing="1" border="1">\n
 <thead>\n
-<tr><td rowspan="1" colspan="3">Test Form Box</td></tr>\n
+<tr><td rowspan="1" colspan="3">Test Form Box Parameter Saved in Request</td></tr>\n
 </thead><tbody>\n
 <tal:block metal:use-macro="here/RelationFieldZuite_CommonTemplate/macros/init" />\n
 <tr>\n
@@ -86,17 +86,17 @@
 </tr>\n
 <tr>\n
   <td>type</td>\n
-  <td>field_my_title</td>\n
+  <td>field_my_formbox_my_title</td>\n
   <td>Default title</td>\n
 </tr>\n
 <tr>\n
   <td>type</td>\n
-  <td>field_my_quantity</td>\n
+  <td>field_my_formbox_my_quantity</td>\n
   <td>99</td>\n
 </tr>\n
 <tr>\n
   <td>type</td>\n
-  <td>field_my_description</td>\n
+  <td>field_my_formbox_my_description</td>\n
   <td>Default description</td>\n
 </tr>\n
 <tr>\n
@@ -116,17 +116,17 @@
 </tr>\n
 <tr>\n
   <td>verifyValue</td>\n
-  <td>field_my_title</td>\n
+  <td>field_my_formbox_my_title</td>\n
   <td>Default title</td>\n
 </tr>\n
 <tr>\n
   <td>verifyValue</td>\n
-  <td>field_my_quantity</td>\n
+  <td>field_my_formbox_my_quantity</td>\n
   <td>99.0</td>\n
 </tr>\n
 <tr>\n
   <td>verifyValue</td>\n
-  <td>field_my_description</td>\n
+  <td>field_my_formbox_my_description</td>\n
   <td>Default description</td>\n
 </tr>\n
 \n
@@ -152,17 +152,17 @@
 </tr>\n
 <tr>\n
   <td>verifyValue</td>\n
-  <td>field_my_title</td>\n
+  <td>field_my_formbox_my_title</td>\n
   <td>Default title</td>\n
 </tr>\n
 <tr>\n
   <td>verifyValue</td>\n
-  <td>field_my_quantity</td>\n
+  <td>field_my_formbox_my_quantity</td>\n
   <td>99.0</td>\n
 </tr>\n
 <tr>\n
   <td>verifyValue</td>\n
-  <td>field_my_description</td>\n
+  <td>field_my_formbox_my_description</td>\n
   <td>Default description</td>\n
 </tr>\n
 \n
diff --git a/bt5/erp5_ui_test/PathTemplateItem/portal_tests/form_box_zuite/testFormBoxValidator.xml b/bt5/erp5_ui_test/PathTemplateItem/portal_tests/form_box_zuite/testFormBoxValidator.xml
index 4e8b14c080..3e0952fb4a 100644
--- a/bt5/erp5_ui_test/PathTemplateItem/portal_tests/form_box_zuite/testFormBoxValidator.xml
+++ b/bt5/erp5_ui_test/PathTemplateItem/portal_tests/form_box_zuite/testFormBoxValidator.xml
@@ -43,12 +43,12 @@
       xmlns:metal="http://xml.zope.org/namespaces/metal">\n
 <head>\n
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">\n
-<title>Test Form Box Edition</title>\n
+<title>Test Form Box Validator</title>\n
 </head>\n
 <body>\n
 <table cellpadding="1" cellspacing="1" border="1">\n
 <thead>\n
-<tr><td rowspan="1" colspan="3">Test Form Box</td></tr>\n
+<tr><td rowspan="1" colspan="3">Test Form Box Validator</td></tr>\n
 </thead><tbody>\n
 <tal:block metal:use-macro="here/RelationFieldZuite_CommonTemplate/macros/init" />\n
 <tr>\n
@@ -86,17 +86,17 @@
 </tr>\n
 <tr>\n
   <td>type</td>\n
-  <td>field_my_title</td>\n
+  <td>field_my_formbox_my_title</td>\n
   <td></td>\n
 </tr>\n
 <tr>\n
   <td>type</td>\n
-  <td>field_my_quantity</td>\n
+  <td>field_my_formbox_my_quantity</td>\n
   <td>99</td>\n
 </tr>\n
 <tr>\n
   <td>type</td>\n
-  <td>field_my_description</td>\n
+  <td>field_my_formbox_my_description</td>\n
   <td>Default description</td>\n
 </tr>\n
 <tr>\n
@@ -116,23 +116,23 @@
 </tr>\n
 <tr>\n
   <td>verifyValue</td>\n
-  <td>field_my_title</td>\n
+  <td>field_my_formbox_my_title</td>\n
   <td></td>\n
 </tr>\n
 <tr>\n
   <td>verifyValue</td>\n
-  <td>field_my_quantity</td>\n
+  <td>field_my_formbox_my_quantity</td>\n
   <td>99.0</td>\n
 </tr>\n
 <tr>\n
   <td>verifyValue</td>\n
-  <td>field_my_description</td>\n
+  <td>field_my_formbox_my_description</td>\n
   <td>Default description</td>\n
 </tr>\n
 \n
 <tr>\n
   <td>type</td>\n
-  <td>field_my_title</td>\n
+  <td>field_my_formbox_my_title</td>\n
   <td>Default title</td>\n
 </tr>\n
 <tr>\n
@@ -152,17 +152,17 @@
 </tr>\n
 <tr>\n
   <td>verifyValue</td>\n
-  <td>field_my_title</td>\n
+  <td>field_my_formbox_my_title</td>\n
   <td>Default title</td>\n
 </tr>\n
 <tr>\n
   <td>verifyValue</td>\n
-  <td>field_my_quantity</td>\n
+  <td>field_my_formbox_my_quantity</td>\n
   <td>99.0</td>\n
 </tr>\n
 <tr>\n
   <td>verifyValue</td>\n
-  <td>field_my_description</td>\n
+  <td>field_my_formbox_my_description</td>\n
   <td>Default description</td>\n
 </tr>\n
 \n
diff --git a/bt5/erp5_ui_test/bt/revision b/bt5/erp5_ui_test/bt/revision
index 19afd4ebd9..4e41d750b7 100644
--- a/bt5/erp5_ui_test/bt/revision
+++ b/bt5/erp5_ui_test/bt/revision
@@ -1 +1 @@
-527
\ No newline at end of file
+528
\ No newline at end of file
diff --git a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Base_edit.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Base_edit.xml
index c878af7127..8819e708cb 100644
--- a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Base_edit.xml
+++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Base_edit.xml
@@ -93,7 +93,7 @@ edit_order = form.edit_order\n
 \n
 try:\n
   # Validate\n
-  form.validate_all_to_request(request)\n
+  form.validate_all_to_request(request, key_prefix=key_prefix)\n
 except FormValidationError, validation_errors:\n
   # Pack errors into the request\n
   field_errors = form.ErrorFields(validation_errors)\n
@@ -317,7 +317,7 @@ return result\n
         </item>
         <item>
             <key> <string>_params</string> </key>
-            <value> <string>form_id, selection_index=0, selection_name=\'\', dialog_id=\'\', ignore_layout=0, editable_mode=1, silent_mode=0, field_prefix=\'my_\'</string> </value>
+            <value> <string>form_id, selection_index=0, selection_name=\'\', dialog_id=\'\', ignore_layout=0, editable_mode=1, silent_mode=0, field_prefix=\'my_\', key_prefix=None</string> </value>
         </item>
         <item>
             <key> <string>errors</string> </key>
@@ -337,7 +337,7 @@ return result\n
                   <dictionary>
                     <item>
                         <key> <string>co_argcount</string> </key>
-                        <value> <int>8</int> </value>
+                        <value> <int>9</int> </value>
                     </item>
                     <item>
                         <key> <string>co_varnames</string> </key>
@@ -351,6 +351,7 @@ return result\n
                             <string>editable_mode</string>
                             <string>silent_mode</string>
                             <string>field_prefix</string>
+                            <string>key_prefix</string>
                             <string>Products.Formulator.Errors</string>
                             <string>FormValidationError</string>
                             <string>Products.CMFActivity.Errors</string>
@@ -415,6 +416,7 @@ return result\n
                 <int>1</int>
                 <int>0</int>
                 <string>my_</string>
+                <none/>
               </tuple>
             </value>
         </item>
diff --git a/product/ERP5/bootstrap/erp5_core/bt/revision b/product/ERP5/bootstrap/erp5_core/bt/revision
index 891f73536c..052219ca7d 100644
--- a/product/ERP5/bootstrap/erp5_core/bt/revision
+++ b/product/ERP5/bootstrap/erp5_core/bt/revision
@@ -1 +1 @@
-1434
\ No newline at end of file
+1435
\ No newline at end of file
diff --git a/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/field_render.xml b/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/field_render.xml
index f67613dad4..d2f25abfb7 100644
--- a/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/field_render.xml
+++ b/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/field_render.xml
@@ -47,12 +47,13 @@
                tal:define="field_id     field/id;\n
                value        python: request.get(field_id, None);\n
                render_prefix render_prefix | nothing;\n
+               key_prefix key_prefix | nothing;\n
                field_errors python: request.get(\'field_errors\', {});\n
                field_has_error  python: field_errors.has_key(field_id);\n
                global form_id form_id | form/id | nothing;\n
                field_description field/Field_getDescription;\n
                is_web_mode is_web_mode | nothing">\n
-      <div tal:define="html_render  python: field.render_htmlgrid(value, request, render_prefix=render_prefix)"\n
+      <div tal:define="html_render  python: field.render_htmlgrid(value, request, render_prefix=render_prefix, key_prefix=key_prefix)"\n
            tal:attributes="title field_description;\n
            class python: \' \'.join([x for x in [\'field\', field.is_required() and \'required\' or None, field_has_error and \'error\' or None, field.get_value(\'css_class\') or None] if x is not None])"\n
            i18n:attributes="title" i18n:domain="ui">\n
diff --git a/product/ERP5/bootstrap/erp5_xhtml_style/bt/revision b/product/ERP5/bootstrap/erp5_xhtml_style/bt/revision
index abb531abb7..0f2ed730d5 100644
--- a/product/ERP5/bootstrap/erp5_xhtml_style/bt/revision
+++ b/product/ERP5/bootstrap/erp5_xhtml_style/bt/revision
@@ -1 +1 @@
-876
\ No newline at end of file
+877
\ No newline at end of file
diff --git a/product/ERP5Form/Form.py b/product/ERP5Form/Form.py
index 323c0450a9..944f772edf 100644
--- a/product/ERP5Form/Form.py
+++ b/product/ERP5Form/Form.py
@@ -600,6 +600,11 @@ class ERP5Form(ZMIForm, ZopePageTemplate):
         # properties which are sensitive.
         if not kwargs.has_key('args'):
             kwargs['args'] = args
+        if kwargs.has_key('key_prefix'):
+          key_prefix = kwargs['key_prefix']
+          del(kwargs['key_prefix'])
+        else:
+          key_prefix = None
         form = self
         obj = getattr(form, 'aq_parent', None)
         if obj is not None:
@@ -612,6 +617,7 @@ class ERP5Form(ZMIForm, ZopePageTemplate):
         extra_context = dict( container=container,
                               template=self,
                               form=self,
+                              key_prefix=key_prefix,
                               options=kwargs,
                               here=obj )
         return pt.pt_render(extra_context=extra_context)
@@ -652,7 +658,7 @@ class ERP5Form(ZMIForm, ZopePageTemplate):
 
     # Pached validate_all to support ListBox validation
     security.declareProtected('View', 'validate_all')
-    def validate_all(self, REQUEST):
+    def validate_all(self, REQUEST, key_prefix=None):
         """Validate all enabled fields in this form, catch any ValidationErrors
         if they occur and raise a FormValidationError in the end if any
         Validation Errors occured.
@@ -664,12 +670,12 @@ class ERP5Form(ZMIForm, ZopePageTemplate):
                 continue
             for field in self.get_fields_in_group(group):
                 # skip any field we don't need to validate
-                if not field.need_validate(REQUEST):
+                if not field.need_validate(REQUEST, key_prefix=key_prefix):
                     continue
                 if not (field.get_value('editable',REQUEST=REQUEST)):
                     continue
                 try:
-                    value = field.validate(REQUEST)
+                    value = field.validate(REQUEST, key_prefix=key_prefix)
                     # store under id
                     result[field.id] = value
                     # store as alternate name as well if necessary
diff --git a/product/ERP5Form/FormBox.py b/product/ERP5Form/FormBox.py
index e4fed03c0a..9fe5aa79f6 100644
--- a/product/ERP5Form/FormBox.py
+++ b/product/ERP5Form/FormBox.py
@@ -88,7 +88,11 @@ class FormBoxWidget(Widget.Widget):
     """
         Render a form in a field
     """
-    here = REQUEST['here']
+    # If FormBox is inside ListBox, we want use REQUEST['cell'] as
+    # 'here'.
+    # XXX REQUEST['cell'] will remain after ListBox rendering. We need a
+    # way to check if it is inside ListBox or not correctly.
+    here = REQUEST.get('cell', REQUEST['here'])
     try:
       form = getattr(here, field.get_value('formbox_target_id'))
     except AttributeError:
@@ -96,7 +100,7 @@ class FormBoxWidget(Widget.Widget):
           'Could not get a form from formbox %s in %s' % \
               (field.id, field.aq_parent.id))
       return ''
-    return form(REQUEST=REQUEST)
+    return form(REQUEST=REQUEST, key_prefix=key)
 
 class FormBoxEditor:
   """
@@ -152,14 +156,14 @@ class FormBoxValidator(Validator.Validator):
     current_field_errors = REQUEST.get('field_errors', [])
 
     # XXX Hardcode script name
-    result, result_type = here.Base_edit(formbox_target_id, silent_mode=1)
+    result, result_type = here.Base_edit(formbox_target_id, silent_mode=1, key_prefix=key)
     if result_type == 'edit':
       return FormBoxEditor(field.id, result)
     elif result_type == 'form':
       formbox_field_errors = REQUEST.get('field_errors', [])
       current_field_errors.extend(formbox_field_errors)
       REQUEST.set('field_errors', current_field_errors)
-      getattr(here, formbox_target_id).validate_all_to_request(REQUEST)
+      getattr(here, formbox_target_id).validate_all_to_request(REQUEST, key_prefix=key)
     else:
       raise NotImplementedError, result_type
 
diff --git a/product/Formulator/Field.py b/product/Formulator/Field.py
index 6920c9729f..dc6a27479d 100644
--- a/product/Formulator/Field.py
+++ b/product/Formulator/Field.py
@@ -154,15 +154,17 @@ class Field:
 
     security.declareProtected('Access contents information',
                               'generate_field_key')
-    def generate_field_key(self, validation=0, key=None):
+    def generate_field_key(self, validation=0, key=None, key_prefix=None):
       """Generate the key Silva uses to render the field in the form.
       """
       # Patched by JPS for ERP5 in order to
       # dynamically change the name
+      if key_prefix is None:
+        key_prefix = 'field'
       if key is not None:
-        return 'field_%s' % key
+        return '%s_%s' % (key_prefix, key)
       if self.field_record is None:
-        return 'field_%s' % self.id
+        return '%s_%s' % (key_prefix, self.id)
       elif validation:
         return self.id
       elif isinstance(self.widget, MultiItemsWidget):
@@ -230,7 +232,7 @@ class Field:
       return REQUEST.form[key]
 
     security.declareProtected('View', 'render')
-    def render(self, value=None, REQUEST=None, key=None, render_prefix=None):
+    def render(self, value=None, REQUEST=None, key=None, render_prefix=None, key_prefix=None):
       """Render the field widget.
       value -- the value the field should have (for instance
                 from validation).
@@ -240,7 +242,7 @@ class Field:
       if value and REQUEST are both None, the 'default' property of
       the field will be used for the value.
       """
-      return self._render_helper(self.generate_field_key(key=key), value, REQUEST,
+      return self._render_helper(self.generate_field_key(key=key, key_prefix=key_prefix), value, REQUEST,
                                  render_prefix)
 
     security.declareProtected('View', 'render_view')
@@ -264,12 +266,12 @@ class Field:
       return self.render(*args, **kw)
 
     security.declareProtected('View', 'render_htmlgrid')
-    def render_htmlgrid(self, value=None, REQUEST=None, key=None, render_prefix=None):
+    def render_htmlgrid(self, value=None, REQUEST=None, key=None, render_prefix=None, key_prefix=None):
       """
       render_htmlgrid returns a list of tuple (title, html render)
       """
       # What about CSS ? What about description ? What about error ?
-      widget_key = self.generate_field_key(key=key)
+      widget_key = self.generate_field_key(key=key, key_prefix=key_prefix)
       value = self._get_default(widget_key, value, REQUEST)
       __traceback_info__ = ('key=%s value=%r' % (key, value))
       return self.widget.render_htmlgrid(self, widget_key, value, REQUEST, render_prefix=render_prefix)
@@ -282,8 +284,9 @@ class Field:
 
     security.declareProtected('View', 'render_odt')
     def render_odt(self, key=None, value=None, as_string=True, ooo_builder=None,
-        REQUEST=None, render_prefix=None, attr_dict=None, local_name='p'):
-      widget_key = self.generate_field_key(key=key)
+        REQUEST=None, render_prefix=None, attr_dict=None, local_name='p',
+        key_prefix=None):
+      widget_key = self.generate_field_key(key=key, key_prefix=key_prefix)
       value = self._get_default(widget_key, value, REQUEST)
       return self.widget.render_odt(self, value, as_string, ooo_builder,
                                     REQUEST, render_prefix, attr_dict,
@@ -291,8 +294,9 @@ class Field:
 
     security.declareProtected('View', 'render_odg')
     def render_odg(self, key=None, value=None, as_string=True, ooo_builder=None,
-        REQUEST=None, render_prefix=None, attr_dict=None, local_name='p'):
-      widget_key = self.generate_field_key(key=key)
+        REQUEST=None, render_prefix=None, attr_dict=None, local_name='p',
+        key_prefix=None):
+      widget_key = self.generate_field_key(key=key, key_prefix=key_prefix)
       value = self._get_default(widget_key, value, REQUEST)
       return self.widget.render_odg(self, value, as_string, ooo_builder,
                                     REQUEST, render_prefix, attr_dict,
@@ -332,11 +336,11 @@ class Field:
       """
       return self.widget.render_dict(self, value)
 
-    def render_from_request(self, REQUEST):
+    def render_from_request(self, REQUEST, key_prefix=None):
         """Convenience method; render the field widget from REQUEST
         (unvalidated data), or default if no raw data is found.
         """
-        return self._render_helper(self.generate_field_key(), None, REQUEST)
+        return self._render_helper(self.generate_field_key(key_prefix=key_prefix), None, REQUEST)
 
     security.declareProtected('View', 'render_sub_field')
     def render_sub_field(self, id, value=None, REQUEST=None, key=None, render_prefix=None):
@@ -365,18 +369,18 @@ class Field:
         return value
 
     security.declareProtected('View', 'validate')
-    def validate(self, REQUEST):
+    def validate(self, REQUEST, key_prefix=None):
         """Validate/transform the field.
         """
         return self._validate_helper(
-            self.generate_field_key(validation=1), REQUEST)
+            self.generate_field_key(validation=1, key_prefix=key_prefix), REQUEST)
 
     security.declareProtected('View', 'need_validate')
-    def need_validate(self, REQUEST):
+    def need_validate(self, REQUEST, key_prefix=None):
         """Return true if validation is needed for this field.
         """
         return self.validator.need_validate(
-            self, self.generate_field_key(validation=1), REQUEST)
+            self, self.generate_field_key(validation=1, key_prefix=key_prefix), REQUEST)
 
     security.declareProtected('View', 'validate_sub_field')
     def validate_sub_field(self, id, REQUEST, key=None):
diff --git a/product/Formulator/Form.py b/product/Formulator/Form.py
index c0f66719e8..43e4672240 100644
--- a/product/Formulator/Form.py
+++ b/product/Formulator/Form.py
@@ -388,12 +388,12 @@ class Form:
         return result
 
     security.declareProtected('View', 'validate_all_to_request')
-    def validate_all_to_request(self, REQUEST):
+    def validate_all_to_request(self, REQUEST, key_prefix=None):
         """Validation, continue validating all fields, catch errors.
         Everything that could be validated will be added to REQUEST.
         """
         try:
-            result = self.validate_all(REQUEST)
+            result = self.validate_all(REQUEST, key_prefix=key_prefix)
         except FormValidationError, e:
             # put whatever result we have in REQUEST
             for key, value in e.result.items():
-- 
2.30.9