diff --git a/product/CMFCategory/Category.py b/product/CMFCategory/Category.py
index 2c9f8694cbf9b3d9148d056dc04d9535c6786641..f5974f2c41d52de919a8155fb478f27e15dba7be 100755
--- a/product/CMFCategory/Category.py
+++ b/product/CMFCategory/Category.py
@@ -168,13 +168,59 @@ class Category(Folder):
         logical_title_list.append(logical_title)
       return '/'.join(logical_title_list)
 
+    def _sortCategoryValueList(self, value_list=(), sort_on=None, sort_order=None, **kw):
+      """Sort categories.
+      """
+      # Sorting.
+      if sort_on is not None:
+        if type(sort_on) == type(''):
+          sort_on = (sort_on,)
+        reverse = (sort_order in ('descending', 'reverse', 'DESC'))
+        new_sort_on = []
+        for key in sort_on:
+          if type(key) == type(''):
+            new_sort_on.append((key, reverse, None))
+          else:
+            if len(key) == 1:
+              new_sort_on.append((key[0], reverse, None))
+            else:
+              new_sort_on.append((key[0], 
+                                  key[1] in ('descending', 'reverse', 'DESC'),
+                                  len(key) > 2 and ken[2] or None))
+        sort_on = new_sort_on
+
+        def sort_categories(a, b):
+          result = 0
+          for key, reverse, as_type in sort_on:
+            # FIXME: as_type is ignored.
+            result = cmp(a.getProperty(key, None), b.getProperty(key, None))
+            if reverse:
+              result = -result
+            if result != 0:
+              break
+          return result
+
+        value_list.sort(sort_categories)
+      return value_list
+      
     security.declareProtected(Permissions.AccessContentsInformation,
                                                     'getCategoryChildValueList')
-    def getCategoryChildValueList(self, recursive=1,include_if_child=1,**kw):
+    def getCategoryChildValueList(self, recursive=1, include_if_child=1, sort_on=None, sort_order=None, **kw):
       """
           List the child objects of this category and all its subcategories.
 
           recursive - if set to 1, list recursively
+
+          include_if_child - if set to 1, categories having child categories
+                             are not included
+
+          sort_on, sort_order - the same semantics as ZSQLCatalog
+                                sort_on specifies properties used for sorting
+                                sort_order specifies how categories are sorted
+
+                                WARNING: using these parameters can slow down
+                                significantly, because this is written in
+                                Python
       """
       if not(include_if_child) and len(self.objectValues(self.allowed_types))>0:
         value_list = []
@@ -182,11 +228,14 @@ class Category(Folder):
         value_list = [self]
       if recursive:
         for c in self.objectValues(self.allowed_types):
+          # Do not pass sort parameters intentionally, because sorting
+          # needs to be done only at the end of recursive calls.
           value_list.extend(c.getCategoryChildValueList(recursive = 1,include_if_child=include_if_child))
       else:
         for c in self.objectValues(self.allowed_types):
           value_list.append(c)
-      return value_list
+
+      return self._sortCategoryValueList(value_list=value_list, sort_on=sort_on, sort_order=sort_order, **kw)
 
     # List names recursively
     security.declareProtected(Permissions.AccessContentsInformation,
@@ -502,7 +551,7 @@ class BaseCategory(Category):
 
     security.declareProtected(Permissions.AccessContentsInformation,
                                                     'getCategoryChildValueList')
-    def getCategoryChildValueList(self, recursive=1, include_if_child=1, **kw):
+    def getCategoryChildValueList(self, recursive=1, include_if_child=1, sort_on=None, sort_order=None, **kw):
       """
           List the child objects of this category and all its subcategories.
 
@@ -532,7 +581,7 @@ class BaseCategory(Category):
           else:
             if len(c.objectValues(self.allowed_types))==0:
               value_list.append(c)
-      return value_list
+      return self._sortCategoryValueList(value_list=value_list, sort_on=sort_on, sort_order=sort_order)
 
     # Alias for compatibility
     security.declareProtected( Permissions.AccessContentsInformation, 'getBaseCategory' )
diff --git a/product/CMFCategory/tests/testCMFCategory.py b/product/CMFCategory/tests/testCMFCategory.py
index d0cb67e9473da588e59e2767fa9d2b2f98e82f34..ffc61abcfa73c8ad037b999afbaa2fb6765280fc 100755
--- a/product/CMFCategory/tests/testCMFCategory.py
+++ b/product/CMFCategory/tests/testCMFCategory.py
@@ -405,7 +405,7 @@ class TestCMFCategory(ERP5TypeTestCase):
     self.assertEqual(p1.getRegion(), 'europe/ouest/france')
     self.failUnless(p1 in west.getRegionRelatedValueList())    
 
-  def test_14_multiplePortalTypes(self, quiet=0, run=run_all_test) :
+  def test_14_MultiplePortalTypes(self, quiet=0, run=run_all_test) :
     """ Checks that categories support different value per portal_type,
         like a colored graph on portal_type"""
     if not run: return
@@ -440,6 +440,56 @@ class TestCMFCategory(ERP5TypeTestCase):
           org_a.getDestinationValue(portal_type='Organisation'), org_b)
       self.assertEquals(len(org_a.getDestinationValueList()), 2)
 
+  def test_15_SortChildValues(self, quiet=0, run=run_all_test) :
+    """ Checks on sorting child categories"""
+    if not run: return
+    if not quiet:
+      message = 'Test Sort Child Values'
+      ZopeTestCase._print('\n '+message)
+      LOG('Testing... ', 0, message)
+    
+    pc = self.getCategoriesTool()
+    bc = pc.newContent(portal_type='Base Category', id='sort_test')
+    self.failUnless(bc is not None)
+    bc.newContent(portal_type='Category', id='1', title='a', int_index=3)
+    bc.newContent(portal_type='Category', id='2', title='b', int_index=1)
+    bc.newContent(portal_type='Category', id='3', title='c', int_index=1)
+
+    # simple sorting    
+    category_list = bc.getCategoryChildValueList(sort_on='title')
+    self.assertEquals(len(category_list), 3)
+    self.assertEquals(category_list[0].getId(), '1')
+    self.assertEquals(category_list[1].getId(), '2')
+    self.assertEquals(category_list[2].getId(), '3')
+
+    # reverse sorting
+    category_list = bc.getCategoryChildValueList(sort_on='title', sort_order='reverse')
+    self.assertEquals(len(category_list), 3)
+    self.assertEquals(category_list[0].getId(), '3')
+    self.assertEquals(category_list[1].getId(), '2')
+    self.assertEquals(category_list[2].getId(), '1')
+
+    # another reverse sorting
+    category_list = bc.getCategoryChildValueList(sort_on=(('title', 'reverse'),))
+    self.assertEquals(len(category_list), 3)
+    self.assertEquals(category_list[0].getId(), '3')
+    self.assertEquals(category_list[1].getId(), '2')
+    self.assertEquals(category_list[2].getId(), '1')
+
+    # multiple sort parameters
+    category_list = bc.getCategoryChildValueList(sort_on=('int_index', 'title'))
+    self.assertEquals(len(category_list), 3)
+    self.assertEquals(category_list[0].getId(), '2')
+    self.assertEquals(category_list[1].getId(), '3')
+    self.assertEquals(category_list[2].getId(), '1')
+
+    # another multiple sort parameters
+    category_list = bc.getCategoryChildValueList(sort_on=(('int_index', 'reverse'), 'title'))
+    self.assertEquals(len(category_list), 3)
+    self.assertEquals(category_list[0].getId(), '1')
+    self.assertEquals(category_list[1].getId(), '2')
+    self.assertEquals(category_list[2].getId(), '3')
+
 
 if __name__ == '__main__':
     framework()