diff --git a/product/CMFCategory/Category.py b/product/CMFCategory/Category.py index f616419196de3577f311a7296dd13ae9e8cc0d42..cb0d52ada5631ee799859ddc2d513aeb78216a85 100755 --- a/product/CMFCategory/Category.py +++ b/product/CMFCategory/Category.py @@ -373,30 +373,22 @@ class Category(Folder): spec=spec, filter=filter, portal_type=portal_type,strict = strict) security.declareProtected( Permissions.AccessContentsInformation, 'getCategoryMemberItemList' ) - def getCategoryMemberItemList(self, base_category = None, - spec = (), filter=None, portal_type=(), strict = 0, display_id = None): + def getCategoryMemberItemList(self, **kw): """ Returns a list of objects or brains """ - - return self.portal_categories.getCategoryMemberItemList(self, - base_category = base_category, spec=spec, - filter=filter, portal_type=portal_type, strict=strict, display_id=display_id) - + #LOG('Category#getCategoryMemberItemList', 0, repr(kw)) + return self.portal_categories.getCategoryMemberItemList(self, **kw) security.declareProtected( Permissions.AccessContentsInformation, 'getCategoryMemberTitleItemList' ) - def getCategoryMemberTitleItemList(self, base_category = None, - spec = (), filter=None, portal_type=(), strict = 0): + def getCategoryMemberTitleItemList(self, **kw): """ Returns a list of objects or brains """ - - return self.portal_categories.getCategoryMemberItemList(self, - base_category = base_category, - spec=spec, filter=filter, portal_type=portal_type,strict = strict, display_id = 'getTitle') - - + kw['display_id'] = 'getTitle' + kw['display_method'] = None + return self.portal_categories.getCategoryMemberItemList(self, **kw) manage_addBaseCategoryForm=DTMLFile('dtml/base_category_add', globals()) diff --git a/product/CMFCategory/CategoryTool.py b/product/CMFCategory/CategoryTool.py index e81a9a19c3a165fe79c980db48c50a4cf02efa93..dee46d432cfe5f26ce922de52a4501d62133c024 100755 --- a/product/CMFCategory/CategoryTool.py +++ b/product/CMFCategory/CategoryTool.py @@ -39,6 +39,7 @@ from Products.ERP5Type import Permissions from Products.ERP5Type.Base import Base from Products.CMFCategory import _dtmldir from Products.CMFCore.PortalFolder import ContentFilter +from Products.CMFCategory.Renderer import Renderer import string, re @@ -332,7 +333,10 @@ class CategoryTool( UniqueObject, Folder, Base ): return result security.declareProtected(Permissions.AccessContentsInformation, 'getPathList') - getPathList = getCategoryChildRelativeUrlList + getPathList = getCategoryChildRelativeUrlList # Exists for backward compatibility + + security.declareProtected(Permissions.AccessContentsInformation, 'getCategoryChildList') + getCategoryChildList = getCategoryChildRelativeUrlList # This is more consistent security.declareProtected(Permissions.AccessContentsInformation, 'getCategoryChildTitleItemList') @@ -1010,7 +1014,6 @@ class CategoryTool( UniqueObject, Folder, Base ): sql_expr = string.join(sql_expr, ' OR ') return sql_expr - security.declareProtected( Permissions.AccessContentsInformation, 'getCategoryMemberValueList' ) def getCategoryMemberValueList(self, context, base_category = None, spec = (), filter=None, portal_type=(), strict = 0): @@ -1020,48 +1023,22 @@ class CategoryTool( UniqueObject, Folder, Base ): """ cat_sql = context.asSqlExpression() - if spec is (): catalog_search = self.portal_catalog(query = cat_sql) else: catalog_search = self.portal_catalog(portal_type = portal_type, query = cat_sql) - return catalog_search - security.declareProtected( Permissions.AccessContentsInformation, 'getCategoryMemberItemList' ) - def getCategoryMemberItemList(self, context, base_category = None, - spec = (), filter=None, portal_type=(), strict = 0, display_id = None, sort_id=None): + def getCategoryMemberItemList(self, context, strict = 0, **kw): """ - This returns with "display_id" method a list of items belonging to a category + This returns a list of items belonging to a category """ - result = [] - - if base_category is None: - base = '' - else: - base = base_category + '/' - catalog_search = self.getCategoryMemberValueList(context) - - for b in catalog_search: - if display_id is None: - v = base + b.relative_url - result += [(v,v)] - else: - try: - o = b.getObject() - v = getattr(o, display_id)() - result += [(v,base + b.relative_url)] - except: - LOG('WARNING: CategoriesTool',0, 'Unable to call %s on %s' % (display_id, b)) - - if sort_id is not None: - result.sort() - - return result + #LOG('getCategoryMemberItemList', 0, repr(kw)) + return Renderer(**kw).render(context, catalog_search) security.declareProtected( Permissions.AccessContentsInformation, 'getCategoryMemberTitleItemList' ) diff --git a/product/CMFCategory/Filter.py b/product/CMFCategory/Filter.py index 2942a656be06b86dbfbbabaa41fad05e780208ab..d358a6227f0af6c4a7813c1912fa758bc36d32f6 100755 --- a/product/CMFCategory/Filter.py +++ b/product/CMFCategory/Filter.py @@ -29,26 +29,38 @@ from Acquisition import Implicit +from zLOG import LOG + class Filter(Implicit): def __init__(self, spec=None, filter={}, portal_type=None): """ - A fil + Initialize attributes. spec and portal_type can be lists, tuples or strings. """ if type(filter) is type({}): - self.filter = filter + self.filter_dict = filter else: - self.filter = {} + self.filter_dict = {} if portal_type is not None: - self.filter['portal_type'] = portal_type + if type(portal_type) == type(''): + portal_type = [portal_type] + # XXX An empty list or tuple is the same as None here. + if len(portal_type) > 0: + self.filter_dict['portal_type'] = portal_type if spec is not None: - self.filter['meta_type'] = spec + if type(spec) == type(''): + spec = [spec] + # XXX An empty list or tuple is the same as None here. + if len(spec) > 0: + self.filter_dict['meta_type'] = spec def test(self, context): """ Test filter on a context """ - for k, v in self.filter.items(): + #LOG('test', 0, repr(context)) + for k, v in self.filter_dict.items(): + #LOG('Filter', 0, "%s, %s" % (repr(k), repr(v))) if type(v) in (type([]), type(())): if context.getProperty(k) not in v: return 0 @@ -61,7 +73,7 @@ class Filter(Implicit): """ Returns a dictionnary of parameters which can be passed to SQL Catalog """ - return self.filter + return self.filter_dict def asSql(self): """ @@ -70,4 +82,5 @@ class Filter(Implicit): # To be done def filter(self, value_list): + #LOG('filter', 0, repr(value_list)) return filter(lambda v: self.test(v), value_list) diff --git a/product/CMFCategory/Renderer.py b/product/CMFCategory/Renderer.py index f04be655f2d95a93b17afde5181ecaecd7ca206d..e0f18445f6373625b30a7150fc39b8e0df0d65ed 100755 --- a/product/CMFCategory/Renderer.py +++ b/product/CMFCategory/Renderer.py @@ -27,18 +27,23 @@ ############################################################################## -from Filter import Filter +from Products.CMFCategory.Filter import Filter + +from zLOG import LOG class Renderer(Filter): """ Produces Item list out of category list + + FIXME: translation """ - def __init__(self, spec=None, filter={}, portal_type=None, + def __init__(self, spec = None, filter = {}, portal_type = None, display_id = None, sort_id = None, display_method = None, sort_method = None, is_right_display = 0, translate_display = 0, translatation_domain = None, - base_category = None, base=1, display_none_category=0): + base_category = None, base = 1, + display_none_category = 0, current_category = None): """ - *display_id*: the id of attribute to "call" to calculate the value to display (getProperty(display_id) -> getDisplayId) @@ -54,7 +59,7 @@ class Renderer(Filter): foo2 5 display order will be (foo1, foo, foo2) - - *sort_method*: a callable method which provides a sort function (à la cmp) + - *sort_method*: a callable method which provides a sort function (?la cmp) - *is_right_display*: use the right value in the couple as the display value. @@ -92,6 +97,7 @@ class Renderer(Filter): """ + #LOG('Renderer', 0, 'spec = %s, filter = %s, portal_type = %s, display_id = %s, sort_id = %s, display_method = %s, sort_method = %s, is_right_display = %s, translate_display = %s, translatation_domain = %s, base_category = %s, base = %s, display_none_category = %s, current_category = %s' % (repr(spec), repr(filter), repr(portal_type), repr(display_id), repr(sort_id), repr(display_method), repr(sort_method), repr(is_right_display), repr(translate_display), repr(translatation_domain), repr(base_category), repr(base), repr(display_none_category), repr(current_category))) Filter.__init__(self, spec=spec, filter=filter, portal_type=portal_type) self.display_id = display_id self.sort_id = sort_id @@ -103,31 +109,105 @@ class Renderer(Filter): self.base_category = base_category self.base = base self.display_none_category = display_none_category + self.current_category = current_category - def render(self, category_tool, value_list, current_category): + def getObjectList(self, value_list): + new_value_list = [] + for value in value_list: + obj = value.getObject() + if obj is not None: + new_value_list.append(obj) + return new_value_list + + def render(self, category_tool, value_list): """ Returns rendered items """ + #LOG('render', 0, repr(self.filter)) + #LOG('render', 10, repr(value_list)) + value_list = self.getObjectList(value_list) value_list = self.filter(value_list) + LOG('render', 10, repr(value_list)) if self.sort_method is not None: value_list.sort(self.sort_method) elif self.sort_id is not None: value_list.sort(lambda x,y: cmp(x.getProperty(self.sort_id), y.getProperty(self.sort_id))) - """ - for b in catalog_search: - if display_id is None: - v = base + b.relative_url - result += [(v,v)] + # If base=1 but base_category is None, it is necessary to guess the base category + # by heuristic. + if self.base and self.base_category is None: + base_category_count_map = {} + for value in value_list: + if not getattr(value, 'isCategory', 0): + continue + b = value.getBaseCategoryId() + if b in base_category_count_map: + base_category_count_map[b] += 1 else: - try: - o = b.getObject() - v = getattr(o, display_id)() - result += [(v,base + b.relative_url)] - except: - LOG('WARNING: CategoriesTool',0, 'Unable to call %s on %s' % (display_id, b)) - - if sort_id is not None: - result.sort() - - """ \ No newline at end of file + base_category_count_map[b] = 1 + guessed_base_category = None + max_count = 0 + for k,v in base_category_count_map.items(): + if v > max_count: + guessed_base_category = k + max_count = v + + # Initialize the list of items. + item_list = [] + if self.current_category: + if self.is_right_display: + item = [None, self.current_category] + else: + item = [self.current_category, None] + item_list.append(item) + if self.display_none_category: + if self.is_right_display: + item = [None, ''] + else: + item = ['', None] + item_list.append(item) + + for value in value_list: + #LOG('Renderer', 10, repr(value)) + # Get the label. + if self.display_method is not None: + label = self.display_method(value) + elif self.display_id is not None: + try: + label = value.getProperty(self.display_id) + except: + LOG('WARNING: Renderer', 0, + 'Unable to call %s on %s' % (self.display_id, value.getRelativeUrl())) + label = None + else: + label = None + # Get the url. + url = value.getRelativeUrl() + if self.base: + if self.base_category: + # Prepend the specified base category to the url. + url = self.base_category + '/' + url + else: + # If the base category of this category does not match the guessed base category, + # merely ignore this category. + if value.getBaseCategoryId() != guessed_base_category: + continue + else: + if self.base_category: + # Nothing to do. + pass + else: + # Get rid of the base category of this url, only if this is a category. + if getattr(value, 'isCategory', 0): + b = value.getBaseCategoryId() + url = url[len(b)+1:] + # Add the pair of a label and an url. + if label is None: + label = url + if self.is_right_display: + item = [url, label] + else: + item = [label, url] + item_list.append(item) + + return item_list