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()