Renderer.py 9.51 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
##############################################################################
#
# Copyright (c) 2002 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.
#
##############################################################################


30 31 32
from Products.CMFCategory.Filter import Filter

from zLOG import LOG
33 34 35 36

class Renderer(Filter):
  """
    Produces Item list out of category list
37 38

    FIXME: translation
39 40
  """

41
  def __init__(self, spec = None, filter = None, portal_type = None,
42 43
                     display_id = None, sort_id = None,
                     display_method = None, sort_method = None,
44 45
                     is_right_display = 0, translate_display = 0, 
                     translatation_domain = None, display_base_category = 0,
46
                     base_category = None, base = 1,
47
                     display_none_category = 1, current_category = None,**kw):
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
    """
    - *display_id*: the id of attribute to "call" to calculate the value to display
                      (getProperty(display_id) -> getDisplayId)

    - *display_method*: a callable method which is used to calculate the value to display

    - *sort_id*: the id of the attribute to "call" to calculate the value used for sorting.
                Sorting is only applied to default ItemList items.

                          self.getProperty(sort_id)
                    foo       3
                    foo1      1
                    foo2      5
          display order will be (foo1, foo, foo2)

63
    - *sort_method*: a callable method which provides a sort function (?la cmp)
64 65 66 67 68 69 70

    - *is_right_display*: use the right value in the couple as the display value.

    - *translate_display*: set to 1, we call translation on each item

    - *translatation_domain*: domain to use for translation

71 72 73
    - *display_base_category*: set to 1, display base_category before display
      value

74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
    - *recursive*: browse recursively to build the ItemList

    - *base_category*: the base category to consider (if None, default is used) API

    - *base*: if set to 0, do not include the base category. If set to 1,
              include the base category. If set to a string, use the string as base.

              (implementation trick: if set to string, use that string as the base string
              when recursing) IMPLEMENTATION HACK

    - *base*: if set to 0, do not include the base category. If set to 1,
              include the base category. If set to a string, use the string as base.
              This is useful for creationg multiple base categories sharing the same categories.
              (ex. target_region/region/europe)

    - *is_self_excluded*: allows to exclude this category from the displayed list

    - *current_category*: allows to provide a category which is not part of the
                          default ItemList. Very useful for displaying
                          values in a popup menu which can no longer
                          be selected.

    - *display_none_category*: allows to include an empty value. Very useful
                        to define None values or empty lists through
                        popup widgets. If both has_empty_item and
                        current_category are provided, current_category
                        is displayed first.


    """
104
    #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)))
105 106 107 108 109 110 111 112
    Filter.__init__(self, spec=spec, filter=filter, portal_type=portal_type)
    self.display_id = display_id
    self.sort_id = sort_id
    self.display_method = display_method
    self.sort_method = sort_method
    self.is_right_display = is_right_display
    self.translate_display = translate_display
    self.translatation_domain = translatation_domain
113
    self.display_base_category = display_base_category
114 115 116
    self.base_category = base_category
    self.base = base
    self.display_none_category = display_none_category
117
    self.current_category = current_category
118

119 120 121 122 123 124 125 126
  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

127
  def render(self, value_list):
128 129 130
    """
      Returns rendered items
    """
131 132 133
    #LOG('render', 0, repr(self.filter))
    #LOG('render', 10, repr(value_list))
    value_list = self.getObjectList(value_list)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
134
    #LOG('render', 5, repr(value_list))
135
    value_list = self.filter(value_list)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
136
    #LOG('render', 10, repr(value_list))
137 138 139 140 141
    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)))

142 143
    # If base=1 but base_category is None, it is necessary to guess the base category
    # by heuristic.
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
#    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:
#          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
#      LOG('render', 100, repr(guessed_base_category))
161 162 163 164 165 166 167 168 169 170 171

    # 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:
172 173
        #item = [None, '']
        item = ['', ''] # XXX Formulator prefer '' to None.
174
      else:
175 176
        #item = ['', None]
        item = ['', ''] # XXX Formulator prefer '' to None.
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
      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.
202 203
          # This is not the job for a Renderer to automatically remove values if we don not
          # specify a filter
Yoshinori Okuji's avatar
Yoshinori Okuji committed
204
          if not hasattr(value, 'getBaseCategoryId'):
205
            continue
206 207 208
          # Remove from now, it might be outdated and useless
          #if value.getBaseCategoryId() != guessed_base_category:
          #  continue
209 210 211 212 213 214 215 216 217 218 219 220
      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
221 222 223 224 225 226 227 228 229 230
      # Add base category in label
      if self.display_base_category:
        if self.base_category:
          bc = value.portal_categories.resolveCategory(self.base_category)
          label = '%s/%s' % (bc.getTitleOrId(), label) 
        else:
          if hasattr(value, 'getBaseCategoryValue'):
            bc = value.getBaseCategoryValue()
            label = '%s/%s' % (bc.getTitleOrId(), label) 

231 232 233 234 235 236 237
      if self.is_right_display:
        item = [url, label]
      else:
        item = [label, url]
      item_list.append(item)

    return item_list