diff --git a/product/ERP5Form/ProxyField.py b/product/ERP5Form/ProxyField.py
index 9af37cbb0d9a18ee12959886d0f6b58234dadd6e..44eba583846d615bddfe02ec13b0cceff6316088 100644
--- a/product/ERP5Form/ProxyField.py
+++ b/product/ERP5Form/ProxyField.py
@@ -671,6 +671,7 @@ class ProxyField(ZMIField):
     # defined by a TALES
     if self._p_oid is None or self.tales['field_id'] or self.tales['form_id']:
       return self._get_value(id, **kw)
+      # XXX: Are these disabled?
       proxy_field = self.getTemplateField(cache=False)
       if proxy_field is not None:
         return proxy_field.get_value(id, **kw)
diff --git a/product/ERP5Form/Report.py b/product/ERP5Form/Report.py
index 5f9d785dc1cb733cbf78305504aa0db149f5d75d..01c6f54416ea7e59f37a79707efd20675193b879 100644
--- a/product/ERP5Form/Report.py
+++ b/product/ERP5Form/Report.py
@@ -28,6 +28,7 @@
 
 from Globals import InitializeClass, DTMLFile, get_request
 from AccessControl import ClassSecurityInfo
+from Acquisition import aq_base
 from Products.PythonScripts.Utility import allow_class
 from Products.Formulator.DummyField import fields
 from Products.Formulator.Form import ZMIForm
@@ -123,6 +124,7 @@ class ERP5Report(ERP5Form):
 
     # Proxy method to PageTemplate
     def __call__(self, *args, **kwargs):
+        warn("ERP5Report to be obsolete, please use ReportBox and normal ERP5Form instead.", DeprecationWarning)
         if not self.report_method:
           raise KeyError, 'report method is not set on the report'
 
@@ -205,7 +207,8 @@ class ReportSection:
                      selection_stats=None,
                      selection_sort_order=None,
                      selection_report_path=None,
-                     selection_report_list=None):
+                     selection_report_list=None,
+                     temporary_selection=True):
     """
       Initialize the line and set the default values
       Selected columns must be defined in parameter of listbox.render...
@@ -213,6 +216,8 @@ class ReportSection:
       In ReportTree listbox display mode, you can override :
         selection_report_path, the root category for this report 
         selection_report_list, the list of unfolded categories (defaults to all)      
+
+      If temporary_selection is False, the selection will be written which is specified by selection_name.
     """
 
     self.path = path
@@ -222,20 +227,18 @@ class ReportSection:
       warn("Don't use translated_title, but title directly", DeprecationWarning)
     self.translated_title = translated_title
     self.level = level
-    self.saved_request = {}
     self.selection_name = selection_name
     self.selection_params = selection_params
     self.listbox_display_mode = listbox_display_mode
     self.selection_columns = selection_columns
     self.selection_stats = selection_stats
     self.selection_sort_order = selection_sort_order
-    self.saved_selections = {}
     self.selection_report_path = selection_report_path
     self.selection_report_list = selection_report_list
-    self.saved_request_form = {}
     self.param_dict = param_dict or {}
     self.param_list = param_list or []
     self.method_id = method_id
+    self.temporary_selection = temporary_selection
 
   security.declarePublic('getTitle')
   def getTitle(self):
@@ -266,17 +269,36 @@ class ReportSection:
   def getFormId(self):
     return self.form_id
 
-  _no_parameter_ = []
-
+  def pushRequest(self):
+    self = aq_base(self)
+    if hasattr(self, '_REQUEST'):
+      raise ValueError, "can not replace the backupped REQUEST"
+    self._REQUEST = {'form': {}, 'other': {},}
+    REQUEST = get_request()
+    self._REQUEST['form'].update(REQUEST.form)
+    self._REQUEST['other'].update(REQUEST.other)
+    REQUEST.form.update(self.param_dict)
+
+  def popRequest(self):
+    self = aq_base(self)
+    if not hasattr(self, '_REQUEST'):
+      raise ValueError, "no backupped REQUEST"
+    REQUEST = get_request()
+    REQUEST.form.clear()
+    REQUEST.other.clear()
+    REQUEST.form.update(self._REQUEST['form'])
+    REQUEST.other.update(self._REQUEST['other'])
+    del self._REQUEST
+    
   security.declarePublic('pushReport')
   def pushReport(self, context, render_prefix=None):
-    REQUEST = get_request()
-    for k,v in self.param_dict.items():
-      self.saved_request[k] = REQUEST.form.get(k, self._no_parameter_)
-      REQUEST.form[k] = v
+    self.pushRequest()
 
+    REQUEST = get_request()
     portal_selections = context.portal_selections
     selection_list = [self.selection_name]
+    # when the Form which is specified by form_id, has a listbox, make prefixed_selection_name.
+    # which is based on specified selection_name in the listbox.
     if self.getFormId() and hasattr(context[self.getFormId()], 'listbox') :
       selection_name = context[self.getFormId()].listbox.get_value('selection_name')
       if render_prefix is not None:
@@ -285,62 +307,46 @@ class ReportSection:
       selection_list += [selection_name]
     # save report's selection and orignal form's selection,
     #as ListBox will overwrite it
-    for selection_name in selection_list :
-      if selection_name is not None :
-        if not self.saved_selections.has_key(selection_name) :
-          self.saved_selections[selection_name] = {}
-        if self.selection_report_list is not None:
-          selection = portal_selections.getSelectionFor(selection_name,
-                                                        REQUEST=REQUEST)
-          if selection is None:
-            selection = Selection()
-            portal_selections.setSelectionFor(selection_name, selection, 
+    for selection_name in filter(lambda x: x is not None, selection_list):
+      if self.temporary_selection:
+        portal_selections.pushSelection(selection_name)
+      else:
+        if portal_selections.getSelectionFor(selection_name) is None:
+          portal_selections.setSelectionFor(selection_name, Selection())
+
+      if self.selection_report_list is not None:
+        selection = portal_selections.getSelectionFor(selection_name,
+                                                      REQUEST=REQUEST)
+        selection.edit(report_list=self.selection_report_list)
+      if self.selection_report_path is not None:
+        selection = portal_selections.getSelectionFor(selection_name,
+                                                      REQUEST=REQUEST)
+        selection.edit(report_path=self.selection_report_path)
+      if self.listbox_display_mode is not None:
+        # XXX Dirty fix, to be able to change the display mode in form_view
+        REQUEST.list_selection_name = selection_name
+        portal_selections.setListboxDisplayMode(REQUEST,
+                                                self.listbox_display_mode,
+                                                selection_name=selection_name)
+      if self.selection_params is not None:
+        params = portal_selections.getSelectionParamsFor(selection_name,
+                                                         REQUEST=REQUEST)
+        params.update(self.selection_params)
+        portal_selections.setSelectionParamsFor(selection_name,
+                                                params,
+                                                REQUEST=REQUEST)
+      if self.selection_columns is not None:
+        portal_selections.setSelectionColumns(selection_name,
+                                              self.selection_columns,
                                               REQUEST=REQUEST)
-          self.saved_selections[selection_name]['report_list'] = \
-               selection.getReportList()
-          selection.edit(report_list=self.selection_report_list)
-        if self.selection_report_path is not None:
-          selection = portal_selections.getSelectionFor(selection_name,
-                                                        REQUEST=REQUEST)
-          self.saved_selections[selection_name]['report_path'] = \
-               selection.getReportPath()
-          selection.edit(report_path=self.selection_report_path)
-        if self.listbox_display_mode is not None:
-          self.saved_selections[selection_name]['display_mode'] = \
-               portal_selections.getListboxDisplayMode(selection_name,
-                                                       REQUEST=REQUEST)
-          # XXX Dirty fix, to be able to change the display mode in form_view
-          REQUEST.list_selection_name = selection_name
-          portal_selections.setListboxDisplayMode(
-                                           REQUEST, self.listbox_display_mode,
-                                           selection_name=selection_name)
-        if self.selection_params is not None:
-          params = portal_selections.getSelectionParams(
-                               selection_name, REQUEST=REQUEST)
-          self.saved_selections[selection_name]['params'] = params.copy()
-          params.update(self.selection_params)
-          portal_selections.setSelectionParamsFor(selection_name,
-                               params, REQUEST=REQUEST)
-        if self.selection_columns is not None:
-          self.saved_selections[selection_name]['columns'] =  \
-               portal_selections.getSelectionColumns(selection_name,
-                                                     REQUEST=REQUEST)
-          portal_selections.setSelectionColumns(selection_name,
-                                  self.selection_columns, REQUEST=REQUEST)
-        if self.selection_sort_order is not None:
-          self.saved_selections[selection_name]['sort_order'] =  \
-               portal_selections.getSelectionSortOrder(selection_name,
-                                                       REQUEST=REQUEST)
-          portal_selections.setSelectionSortOrder(selection_name,
-                      self.selection_sort_order, REQUEST=REQUEST)
-        if self.selection_stats is not None:
-          self.saved_selections[selection_name]['stats'] =  \
-               portal_selections.getSelectionStats(selection_name,
-                                                     REQUEST=REQUEST)
-          portal_selections.setSelectionStats(selection_name,
-                                  self.selection_stats, REQUEST=REQUEST)
-
-    self.saved_request_form = REQUEST.form
+      if self.selection_sort_order is not None:
+        portal_selections.setSelectionSortOrder(selection_name,
+                                                self.selection_sort_order,
+                                                REQUEST=REQUEST)
+      if self.selection_stats is not None:
+        portal_selections.setSelectionStats(selection_name,
+                                            self.selection_stats,
+                                            REQUEST=REQUEST)
 
     # When rendering a report section with a listbox, listbox gets parameters
     # from request.form and edits selection with those parameters, so if you
@@ -354,68 +360,18 @@ class ReportSection:
 
   security.declarePublic('popReport')
   def popReport(self, context, render_prefix=None):
-    REQUEST = get_request()
-    for k,v in self.param_dict.items():
-      if self.saved_request[k] is self._no_parameter_:
-        if REQUEST.form.has_key(k):
-          del REQUEST.form[k]
-      else:
-        REQUEST.form[k] = self.saved_request[k]
+    self.popRequest()
 
     portal_selections = context.portal_selections
     selection_list = []
     if self.getFormId() and hasattr(context[self.getFormId()], 'listbox') :
       selection_name = context[self.getFormId()].listbox.get_value('selection_name')
-      if render_prefix is not None:
-        del REQUEST.other['prefixed_selection_name']
-        # Return before cleanup, because there is no interest in cleaning up
-        # what won't be shared.
-        return
       selection_list += [selection_name]
     selection_list += [self.selection_name]
-    # restore report then form selection
-    for selection_name in selection_list:
-      if selection_name is not None:
-        if self.selection_report_list is not None:
-          selection = portal_selections.getSelectionFor(
-                              selection_name, REQUEST=REQUEST)
-          selection.edit(report_list =
-                self.saved_selections[selection_name]['report_list'])
-        if self.selection_report_path is not None:
-          selection = portal_selections.getSelectionFor(
-                selection_name, REQUEST=REQUEST)
-          selection.edit(report_path =
-                self.saved_selections[selection_name]['report_path'])
-        if self.listbox_display_mode is not None:
-          # XXX Dirty fix, to be able to change the display mode in form_view
-          REQUEST.list_selection_name = selection_name
-          portal_selections.setListboxDisplayMode(
-                       REQUEST,
-                       self.saved_selections[selection_name]['display_mode'],
-                       selection_name=selection_name)
-
-        # first make sure no parameters that have been pushed are kept 
-        portal_selections.setSelectionParamsFor(selection_name,
-                                                {}, REQUEST=REQUEST)
-        if self.selection_params is not None:
-          # then restore the original params
-          portal_selections.setSelectionParamsFor(selection_name,
-                      self.saved_selections[selection_name]['params'],
-                      REQUEST=REQUEST)
-        if self.selection_columns is not None:
-          portal_selections.setSelectionColumns(selection_name,
-                      self.saved_selections[selection_name]['columns'],
-                      REQUEST=REQUEST)
-        if self.selection_sort_order is not None:
-          portal_selections.setSelectionSortOrder(selection_name,
-                      self.saved_selections[selection_name]['sort_order'],
-                      REQUEST=REQUEST)
-        if self.selection_stats is not None:
-          portal_selections.setSelectionStats(selection_name,
-                      self.saved_selections[selection_name]['stats'],
-                      REQUEST=REQUEST)
-
-    REQUEST.form = self.saved_request_form
+    if self.temporary_selection:
+      for selection_name in selection_list:
+        if selection_name is not None:
+          portal_selections.popSelection(selection_name)
 
 InitializeClass(ReportSection)
 allow_class(ReportSection)
diff --git a/product/ERP5Form/ReportBox.py b/product/ERP5Form/ReportBox.py
new file mode 100644
index 0000000000000000000000000000000000000000..468b711f531adf94eb2b38f5affe01f3a2c4456c
--- /dev/null
+++ b/product/ERP5Form/ReportBox.py
@@ -0,0 +1,84 @@
+##############################################################################
+#
+# Copyright (c) 2009 Nexedi SARL and Contributors. All Rights Reserved.
+#                    Jean-Paul Smets-Solanes <jp@nexedi.com>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+##############################################################################
+
+from Globals import get_request
+from AccessControl.ZopeGuards import guarded_getattr
+from Products.Formulator import Widget, Validator
+from Products.Formulator.Field import ZMIField
+from Products.Formulator.DummyField import fields
+
+class ReportBoxWidget(Widget.Widget):
+
+  property_names = list(Widget.Widget.property_names)
+  property_names.append('report_method')
+
+  # XXX this is only needed on bootstrap
+  default = fields.StringField('default',
+                                title='Default',
+                                description="",
+                                default="",
+                                required=0)
+
+  report_method = fields.StringField('report_method',
+                                     title='Report Method',
+                                     description="",
+                                     default="",
+                                     required=0)
+
+  def render_view(self, field, value, REQUEST=None, key='reportbox', render_prefix=None):
+    """
+    """
+    if REQUEST is None:
+      REQUEST = get_request()
+    return self.render(field, key, value, REQUEST)
+
+  def render(self, field, key, value, REQUEST, render_prefix=None):
+    """
+    """
+    form = getattr(field, 'aq_parent', None)
+    if form is not None:
+      obj = getattr(form, 'aq_parent', None)
+    else:
+      obj = None
+    if obj is not None:
+      report_method = guarded_getattr(obj, field['report_method'])
+      if callable(report_method):
+        return report_method()
+
+
+class ReportBoxValidator(Validator.Validator):
+
+  def validate(self, field, key, REQUEST):
+    return True
+
+
+class ReportBox(ZMIField):
+  meta_type = "ReportBox"
+
+  widget = ReportBoxWidget()
+  validator = ReportBoxValidator()
diff --git a/product/ERP5Form/SelectionTool.py b/product/ERP5Form/SelectionTool.py
index a33af7eac296cabb224bdbce1d2e2434a99528ec..a70b4a0122f399cb8ba4a4a540d3807c7ce61a36 100644
--- a/product/ERP5Form/SelectionTool.py
+++ b/product/ERP5Form/SelectionTool.py
@@ -37,6 +37,7 @@ from Globals import InitializeClass, DTMLFile, PersistentMapping, get_request
 from AccessControl import ClassSecurityInfo
 from Products.ERP5Type.Tool.BaseTool import BaseTool
 from Products.ERP5Type import Permissions as ERP5Permissions
+from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
 from Products.ERP5Form import _dtmldir
 from Selection import Selection, DomainSelection
 from ZPublisher.HTTPRequest import FileUpload
@@ -1320,9 +1321,38 @@ class SelectionTool( BaseTool, UniqueObject, SimpleItem ):
       # XXX It would be good to add somthing here
       # So that 2 anonymous users do not share the same selection
 
+    def getTemporarySelectionDict(self):
+      """ Temporary selections are used in push/pop nested scope,
+      to prevent from editting for stored selection in the scope.
+      Typically, it is used for ReportSection."""
+      tv = getTransactionalVariable(self)
+      return tv.setdefault('_temporary_selection_dict', {})
+
+    def pushSelection(self, selection_name):
+      selection = self.getSelectionFor(selection_name)
+      # a temporary selection is kept in transaction.
+      temp_selection = Selection()
+      if selection:
+        temp_selection.__dict__.update(selection.__dict__)
+      self.getTemporarySelectionDict()\
+        .setdefault(selection_name, []).append(temp_selection)
+
+    def popSelection(self, selection_name):
+      temporary_selection_dict = self.getTemporarySelectionDict()
+      if selection_name in temporary_selection_dict and \
+         temporary_selection_dict[selection_name]:
+        temporary_selection_dict[selection_name].pop()
+
     def _getSelectionFromContainer(self, selection_name):
       user_id = self._getUserId()
       if user_id is None: return None
+
+      temporary_selection_dict = self.getTemporarySelectionDict()
+      if temporary_selection_dict and selection_name in temporary_selection_dict:
+        if temporary_selection_dict[selection_name]:
+          # focus the temporary selection in the most narrow scope.
+          return temporary_selection_dict[selection_name][-1]
+
       if self.isMemcachedUsed():
         return self._getMemcachedContainer().get('%s-%s' %
                                                  (user_id, selection_name))
@@ -1333,6 +1363,14 @@ class SelectionTool( BaseTool, UniqueObject, SimpleItem ):
     def _setSelectionToContainer(self, selection_name, selection):
       user_id = self._getUserId()
       if user_id is None: return
+
+      temporary_selection_dict = self.getTemporarySelectionDict()
+      if temporary_selection_dict and selection_name in temporary_selection_dict:
+        if temporary_selection_dict[selection_name]:
+          # focus the temporary selection in the most narrow scope.
+          temporary_selection_dict[selection_name][-1] = selection
+          return
+
       if self.isMemcachedUsed():
         self._getMemcachedContainer().set('%s-%s' % (user_id, selection_name), aq_base(selection))
       else:
@@ -1360,7 +1398,9 @@ class SelectionTool( BaseTool, UniqueObject, SimpleItem ):
       else:
         user_id = self._getUserId()
         if user_id is None: return []
-        return self._getPersistentContainer(user_id).keys()
+
+        tv = getTransactionalVariable(self)
+        return list(set(self._getPersistentContainer(user_id).keys() + self.getTemporarySelectionDict().keys()))
 
     def _getMemcachedContainer(self):
       value = getattr(aq_base(self), '_v_selection_data', None)
diff --git a/product/ERP5Form/__init__.py b/product/ERP5Form/__init__.py
index 2d946fd631c6157e65c97934f84dccc44d475ac5..e71145a0c90af032ea7708d9d1b1c549db0e3041 100644
--- a/product/ERP5Form/__init__.py
+++ b/product/ERP5Form/__init__.py
@@ -40,7 +40,7 @@ document_classes = updateGlobals( this_module, globals(),
                                   permissions_module = Permissions)
 
 # Define object classes and tools
-import Form, FSForm, ListBox, MatrixBox, SelectionTool
+import Form, FSForm, ListBox, ReportBox, MatrixBox, SelectionTool
 import OOoChart, PDFTemplate, Report, PDFForm, ParallelListField
 import PlanningBox, POSBox, FormBox, EditorField, ProxyField, DurationField
 import RelationField, ImageField, MultiRelationField, MultiLinkField, InputButtonField
@@ -86,6 +86,8 @@ def initialize( context ):
                                 'www/StringField.gif')
     FieldRegistry.registerField(ListBox.ListBox,
                                 'www/StringField.gif')
+    FieldRegistry.registerField(ReportBox.ReportBox,
+                                'www/StringField.gif')
     FieldRegistry.registerField(PlanningBox.PlanningBox,
                                 'www/StringField.gif')
     FieldRegistry.registerField(MatrixBox.MatrixBox,
diff --git a/product/Formulator/Field.py b/product/Formulator/Field.py
index abc410ff11a0dadf174ad175198ec48983d675fa..a8c5aa174f1df8b650fe5b47663184e4c77a96c5 100644
--- a/product/Formulator/Field.py
+++ b/product/Formulator/Field.py
@@ -625,6 +625,10 @@ class ZMIField(
             return 1
         except ImportError:
             return 0
+
+    def getTemplateField(self):
+        return self
+    getRecursiveTemplateField = getTemplateField
         
 Globals.InitializeClass(ZMIField)
 PythonField = ZMIField # NOTE: for backwards compatibility