diff --git a/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/ERP5Site_filterParameterList.xml b/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/ERP5Site_filterParameterList.xml
index 37ff9f3d56949004a7e4af5f0fd2da91704d5715..e052910a4112033380277ecdffcfa56c98d3a0e4 100644
--- a/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/ERP5Site_filterParameterList.xml
+++ b/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/ERP5Site_filterParameterList.xml
@@ -52,6 +52,7 @@
             <key> <string>_body</string> </key>
             <value> <string>kept_names = (\'editable_mode\', \'ignore_layout\',            # erp5_web\n
               \'selection_name\', \'selection_index\',         # list mode\n
+              \'selection_key\',                             # list mode\n
               \'bt_list\',                                   # business template installation system\n
               \'ignore_hide_rows\',\n
              )\n
diff --git a/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/ListBox_asHTML.xml b/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/ListBox_asHTML.xml
index 15fb6230be3b03eb679fe53e36584b1821610f03..fec16bb0ac854e38ca0e887dd763964bbe41cd88 100644
--- a/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/ListBox_asHTML.xml
+++ b/product/ERP5/bootstrap/erp5_xhtml_style/SkinTemplateItem/portal_skins/erp5_xhtml_style/ListBox_asHTML.xml
@@ -546,6 +546,11 @@
           </tbody>\n
 \n
       </table>\n
+      <input type="hidden" name="selection_name_selection_key" value="md5"\n
+             tal:define="selection_key here/getSelectionKey"\n
+             tal:condition="selection_key"\n
+             tal:attributes="name string:${selection_name}_selection_key;\n
+                             value selection_key" />\n
     </div>\n
 \n
     <div class="listbox-footer">\n
diff --git a/product/ERP5Form/ListBox.py b/product/ERP5Form/ListBox.py
index 614dbafe34ea4d5fe7aa821658c672e32006d8df..90cc8f0f23458dccd8bc3f6a06bb71a7b8fb6c41 100644
--- a/product/ERP5Form/ListBox.py
+++ b/product/ERP5Form/ListBox.py
@@ -1196,7 +1196,20 @@ class ListBoxRenderer:
     if self.getListMethodName():
       # Update parameters, only if list_method is defined.
       # (i.e. do not update parameters in listboxes intended to show a previously defined selection.
-      params.update(self.request.form)
+      listbox_prefix = '%s_' % self.getId()
+      for k, v in self.request.form.iteritems():
+        # Ignore parameters for other listboxes and selection keys.
+        if 'listbox_' in k or k.endswith('selection_key'):
+          continue
+        elif k.startswith(listbox_prefix):
+          k = k[len(listbox_prefix):]
+          # <listbox_field_id>_uid is already handled in
+          # ListBoxValidator.validate() and putting uid in selection
+          # will limit the contents for the selection.
+          if k != 'uid':
+            params[k] = v
+        else:
+          params[k] = v
       for k, v in self.getDefaultParamList():
         params.setdefault(k, v)
 
@@ -2102,6 +2115,11 @@ class ListBoxRenderer:
     """
     return self.render(**kw)
 
+  def getSelectionKey(self):
+    selection_tool = self.getSelectionTool()
+    selection_name = self.getSelectionName()
+    return selection_tool.getAnonymousSelectionKey(selection_name)
+
 class ListBoxRendererLine:
   """This class describes a line in a ListBox to assist ListBoxRenderer.
   """
@@ -2447,6 +2465,9 @@ class ListBoxHTMLRendererLine(ListBoxRendererLine):
               params.extend(('selection_name=%s' % selection_name,
                              'selection_index=%s' % self.index,
                              'reset:int=1'))
+              selection_tool = self.getObject().getPortalObject().portal_selections
+              if selection_tool._isAnonymous():
+                params.append('selection_key=%s' % selection.getAnonymousSelectionKey())
             if params:
               url = '%s?%s' % (url, '&amp;'.join(params))
           except AttributeError:
diff --git a/product/ERP5Form/Selection.py b/product/ERP5Form/Selection.py
index 967fbc15a7545a99559839417d66b82ee2aed009..1924502c03b70381964e01ea60c010b942d16f4b 100644
--- a/product/ERP5Form/Selection.py
+++ b/product/ERP5Form/Selection.py
@@ -33,6 +33,7 @@ from OFS.Traversable import Traversable
 from AccessControl import ClassSecurityInfo
 from Products.ERP5Type import Permissions as ERP5Permissions
 from Products.PythonScripts.Utility import allow_class
+from hashlib import md5
 
 # Put a try in front XXX
 from Products.CMFCategory.Category import Category
@@ -368,6 +369,10 @@ class Selection(Acquisition.Implicit, Traversable, Persistent):
     def getReportTreeMode(self):
         return getattr(self, 'report_tree_mode', 0)
 
+    security.declarePublic('getAnonymousSelectionKey')
+    def getAnonymousSelectionKey(self):
+        return md5(repr(dict([(k, v) for k, v in self.__dict__.iteritems() if k != 'index']))).hexdigest()
+
 InitializeClass(Selection)
 allow_class(Selection)
 
diff --git a/product/ERP5Form/Tool/SelectionTool.py b/product/ERP5Form/Tool/SelectionTool.py
index 94892074831b257dbaa0238646a2153ec24adf86..de1e991fa1a902130f01e8b51ab0194fc94bf7d6 100644
--- a/product/ERP5Form/Tool/SelectionTool.py
+++ b/product/ERP5Form/Tool/SelectionTool.py
@@ -32,7 +32,6 @@
 """
 
 from OFS.SimpleItem import SimpleItem
-from Products.CMFCore.utils import UniqueObject
 from Products.ERP5Type.Globals import InitializeClass, DTMLFile, PersistentMapping, get_request
 from AccessControl import ClassSecurityInfo
 from Products.ERP5Type.Tool.BaseTool import BaseTool
@@ -43,8 +42,6 @@ from Products.ERP5Form.Selection import Selection, DomainSelection
 from ZPublisher.HTTPRequest import FileUpload
 from hashlib import md5
 import string, re
-from time import time
-from random import random
 from urlparse import urlsplit, urlunsplit
 from zLOG import LOG, INFO, WARNING
 from Acquisition import aq_base
@@ -273,6 +270,17 @@ class SelectionTool( BaseTool, SimpleItem ):
         return None
       return selection(method=method, context=context, REQUEST=REQUEST, params=params)
 
+    def _getRequest(self, REQUEST=None):
+      if REQUEST is None:
+        REQUEST = getattr(self, 'REQUEST', None)
+      return REQUEST
+
+    def _getSelectionKeyFromRequest(self, selection_name, REQUEST):
+      REQUEST = self._getRequest(REQUEST=REQUEST)
+      if REQUEST is not None:
+        return REQUEST.get('%s_selection_key' % selection_name, None) or \
+          REQUEST.get('selection_key', None)
+
     security.declareProtected(ERP5Permissions.View, 'getSelectionFor')
     def getSelectionFor(self, selection_name, REQUEST=None):
       """
@@ -283,6 +291,11 @@ class SelectionTool( BaseTool, SimpleItem ):
       if not selection_name:
         return None
       selection = self._getSelectionFromContainer(selection_name)
+      if selection is None and self._isAnonymous():
+        selection_key = self._getSelectionKeyFromRequest(selection_name, REQUEST)
+        if selection_key is not None:
+          selection = self.getAnonymousSelection(selection_key, selection_name)
+          self._setSelectionToContainer(selection_name, selection)
       if selection is not None:
         return selection.__of__(self)
 
@@ -296,19 +309,21 @@ class SelectionTool( BaseTool, SimpleItem ):
       """
       if not selection_name:
         return
-      anonymous_uid = REQUEST and REQUEST.get('anonymous_uid', None)
-      if anonymous_uid is not None:
-        self.REQUEST.response.setCookie('anonymous_uid', anonymous_uid,
-                                        path='/')
-
       if not (selection_object is None or
               selection_name == selection_object.name):
         LOG('SelectionTool', WARNING,
             "Selection not set: new Selection name ('%s') differs from existing one ('%s')" % \
             (selection_name,
              selection_object.name))
-      elif self.getSelectionFor(selection_name) != selection_object:
+      elif self.getSelectionFor(selection_name, REQUEST=REQUEST) != selection_object:
         self._setSelectionToContainer(selection_name, selection_object)
+      if selection_object is None and self._isAnonymous():
+        REQUEST = self._getRequest(REQUEST=REQUEST)
+        for key in ('%s_selection_key' % selection_name, 'selection_key'):
+          try:
+            del REQUEST.form[key]
+          except KeyError:
+            pass
 
     security.declareProtected(ERP5Permissions.View, 'getSelectionParamsFor')
     def getSelectionParamsFor(self, selection_name, params=None, REQUEST=None):
@@ -447,7 +462,10 @@ class SelectionTool( BaseTool, SimpleItem ):
       """
       selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
       if selection:
-        return selection.getListUrl()
+        url = selection.getListUrl()
+        if self._isAnonymous() and '?' in url:
+          url += '&selection_key=%s' % self._getSelectionKeyFromRequest(selection_name, REQUEST)
+        return url
       else:
         return None
 
@@ -669,88 +687,30 @@ class SelectionTool( BaseTool, SimpleItem ):
       """
         Access first item in a selection
       """
-      if not REQUEST:
-        REQUEST = get_request()
-      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
-      if selection:
-        method = self.unrestrictedTraverse(selection.method_path)
-        selection_list = selection(method = method, context=self, REQUEST=REQUEST)
-        if len(selection_list):
-          o = selection_list[0]
-          url = o.absolute_url()
-          form_id = self._getExistingFormId(o.getObject(), form_id)
-        else:
-          url = REQUEST.getURL()
-      else:
-        url = REQUEST.getURL()
-      ignore_layout = int(REQUEST.get('ignore_layout', 0))
-      if form_id != 'view':
-        url += '/%s' % form_id
-      url += '?selection_index=%s&selection_name=%s' % (0, selection_name)
-      if ignore_layout:
-        url += '&ignore_layout:int=1'
-      REQUEST.RESPONSE.redirect(url)
+      return self._redirectToIndex(0, selection_name, form_id, REQUEST)
 
     security.declareProtected(ERP5Permissions.View, 'viewLast')
     def viewLast(self, selection_index='', selection_name='', form_id='view', REQUEST=None):
       """
         Access last item in a selection
       """
-      if not REQUEST:
-        REQUEST = get_request()
-      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
-      if selection:
-        method = self.unrestrictedTraverse(selection.method_path)
-        selection_list = selection(method = method, context=self, REQUEST=REQUEST)
-        if len(selection_list):
-          o = selection_list[-1]
-          url = o.absolute_url()
-          form_id = self._getExistingFormId(o.getObject(), form_id)
-        else:
-          url = REQUEST.getURL()
-      else:
-        url = REQUEST.getURL()
-      ignore_layout = int(REQUEST.get('ignore_layout', 0))
-      if form_id != 'view':
-        url += '/%s' % form_id
-      url += '?selection_index=%s&selection_name=%s' % (-1, selection_name)
-      if ignore_layout:
-        url += '&ignore_layout:int=1'
-      REQUEST.RESPONSE.redirect(url)
+      return self._redirectToIndex(-1, selection_name, form_id, REQUEST)
 
     security.declareProtected(ERP5Permissions.View, 'viewNext')
     def viewNext(self, selection_index='', selection_name='', form_id='view', REQUEST=None):
       """
         Access next item in a selection
       """
-      if not REQUEST:
-        REQUEST = get_request()
-      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
-      if selection:
-        method = self.unrestrictedTraverse(selection.method_path)
-        selection_list = selection(method = method, context=self, REQUEST=REQUEST)
-        if len(selection_list):
-          o = selection_list[(int(selection_index) + 1) % len(selection_list)]
-          url = o.absolute_url()
-          form_id = self._getExistingFormId(o.getObject(), form_id)
-        else:
-          url = REQUEST.getURL()
-      else:
-        url = REQUEST.getURL()
-      ignore_layout = int(REQUEST.get('ignore_layout', 0))
-      if form_id != 'view':
-        url += '/%s' % form_id
-      url += '?selection_index=%s&selection_name=%s' % (int(selection_index)+1,
-                                                        selection_name)
-      if ignore_layout:
-        url += '&ignore_layout:int=1'
-      REQUEST.RESPONSE.redirect(url)
+      return self._redirectToIndex(int(selection_index) + 1, selection_name, form_id, REQUEST)
 
     security.declareProtected(ERP5Permissions.View, 'viewPrevious')
     def viewPrevious(self, selection_index='', selection_name='', form_id='view', REQUEST=None):
       """
         Access previous item in a selection
       """
+      return self._redirectToIndex(int(selection_index) - 1, selection_name, form_id, REQUEST)
+
+    def _redirectToIndex(self, selection_index, selection_name, form_id, REQUEST):
       if not REQUEST:
         REQUEST = get_request()
       selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
@@ -758,7 +718,9 @@ class SelectionTool( BaseTool, SimpleItem ):
         method = self.unrestrictedTraverse(selection.method_path)
         selection_list = selection(method = method, context=self, REQUEST=REQUEST)
         if len(selection_list):
-          o = selection_list[(int(selection_index) - 1) % len(selection_list)]
+          if selection_index > 0:
+            selection_index = selection_index % len(selection_list)
+          o = selection_list[selection_index]
           url = o.absolute_url()
           form_id = self._getExistingFormId(o.getObject(), form_id)
         else:
@@ -768,13 +730,13 @@ class SelectionTool( BaseTool, SimpleItem ):
       ignore_layout = int(REQUEST.get('ignore_layout', 0))
       if form_id != 'view':
         url += '/%s' % form_id
-      url += '?selection_index=%s&selection_name=%s' % (int(selection_index)-1,
-                                                        selection_name)
+      url += '?selection_index=%s&selection_name=%s' % (selection_index, selection_name)
       if ignore_layout:
         url += '&ignore_layout:int=1'
+      if self._isAnonymous():
+        url += '&selection_key=%s' % self.getAnonymousSelectionKey(selection_name, REQUEST=REQUEST)
       REQUEST.RESPONSE.redirect(url)
 
-
     # ListBox related methods
 
     security.declareProtected(ERP5Permissions.View, 'firstPage')
@@ -1467,12 +1429,6 @@ class SelectionTool( BaseTool, SimpleItem ):
       if user_id is not None:
         return user_id
       user_id = self.portal_membership.getAuthenticatedMember().getUserName()
-      if user_id == 'Anonymous User' and self.getAnonymousStorage() is not None:
-        anonymous_uid = self.REQUEST.get('anonymous_uid', None)
-        if anonymous_uid is None:
-          anonymous_uid = md5('%s.%s' % (time(), random())).hexdigest()
-          self.REQUEST['anonymous_uid'] = anonymous_uid
-        user_id = 'Anonymous:%s' % anonymous_uid
       tv['_user_id'] = user_id
       return user_id
 
@@ -1498,6 +1454,25 @@ class SelectionTool( BaseTool, SimpleItem ):
          temporary_selection_dict[selection_name]:
         temporary_selection_dict[selection_name].pop()
 
+    def getAnonymousSelection(self, key, selection_name):
+      container_id = '_v_anonymous_selection_container'
+      storage = self.getAnonymousStorage() or self.getStorage()
+      container = self._getContainerFromStorage(container_id, storage)
+      return container.getSelection(key, selection_name)
+
+    def getAnonymousSelectionKey(self, selection_name, REQUEST=None):
+      if not self._isAnonymous():
+        return ''
+      selection = self.getSelectionFor(selection_name, REQUEST=REQUEST)
+      if selection is None:
+        return ''
+      key = selection.getAnonymousSelectionKey()
+      container_id = '_v_anonymous_selection_container'
+      storage = self.getAnonymousStorage() or self.getStorage()
+      container = self._getContainerFromStorage(container_id, storage)
+      container.setSelection(key, selection_name, selection)
+      return key
+
     def _getSelectionFromContainer(self, selection_name):
       user_id = self._getUserId()
       if user_id is None: return None
@@ -1540,15 +1515,20 @@ class SelectionTool( BaseTool, SimpleItem ):
                       self.getTemporarySelectionDict().keys()))
 
     def _isAnonymous(self):
-      return self.portal_membership.isAnonymousUser()
+      return self._getUserId() == 'Anonymous User'
 
     def _getContainer(self):
       if self._isAnonymous():
-        container_id = '_v_anonymous_selection_container'
-        storage = self.getAnonymousStorage() or self.getStorage()
+        tv = getTransactionalVariable()
+        storage = tv.setdefault('_transactional_selection_container', {})
+        container = TransactionalCacheContainer(storage)
+        return container
       else:
         container_id = '_v_selection_container'
         storage = self.getStorage()
+        return self._getContainerFromStorage(container_id, storage)
+
+    def _getContainerFromStorage(self, container_id, storage):
       container = getattr(aq_base(self), container_id, None)
       if container is None:
         if storage.startswith('portal_memcached/'):
@@ -1567,10 +1547,11 @@ class SelectionTool( BaseTool, SimpleItem ):
 
 InitializeClass( SelectionTool )
 
-class MemcachedContainer(object):
+class BaseContainer(object):
   def __init__(self, container):
     self._container = container
 
+class MemcachedContainer(BaseContainer):
   def getSelectionNameList(self, user_id):
     return []
 
@@ -1589,10 +1570,11 @@ class MemcachedContainer(object):
   def deleteGlobalSelection(self, user_id, selection_name):
     pass
 
-class PersistentMappingContainer(object):
-  def __init__(self, container):
-    self._container = container
+class TransactionalCacheContainer(MemcachedContainer):
+  def setSelection(self, user_id, selection_name, selection):
+    self._container.__setitem__('%s-%s' % (user_id, selection_name), aq_base(selection))
 
+class PersistentMappingContainer(BaseContainer):
   def getSelectionNameList(self, user_id):
     try:
       return self._container[user_id].keys()