Package Products :: Package ZenWidgets :: Module ZenTableManager |
[hide private]
[frames] | no frames]

# Source Code for Module Products.ZenWidgets.ZenTableManager

      1  ##############################################################################
      2  #
      3  # Copyright (C) Zenoss, Inc. 2007, all rights reserved.
      4  #
      5  # This content is made available according to terms specified in
      6  # License.zenoss under the directory where your Zenoss product is installed.
      7  #
      8  ##############################################################################
      9
     10
     11  __doc__="""ZenTableManager
     12
     13  ZenTableManager is a Zope Product that helps manage and display
     14  large sets of tabular data.  It allows for column sorting,
     15  break down of the set into pages, and filtering of elements
     16  in the table.  It also allows users to store their own default
     17  page size (but publishes a hook to get this values from
     18  a different location).
     19
     20
     21  $Id: ZenTableManager.py,v 1.4 2004/04/03 04:18:22 edahl Exp $"""
     22
     23  __revision__ = "$Revision: 1.4 $"[11:-2]
     24
     25  import re
     26  import ZTUtils
     27  from Globals import InitializeClass
     28  from Acquisition import aq_base
     29  from OFS.SimpleItem import SimpleItem
     30  from OFS.PropertyManager import PropertyManager
     31  from DocumentTemplate.sequence.SortEx import sort
     32
     33  from ZenTableState import ZenTableState
     34
     35
     36 -class TableStateNotFound(Exception): pass
     37
     38
     39 -def manage_addZenTableManager(context, id="", REQUEST = None):
     40      """make a CVDeviceLoader"""
     41      if not id: id = "ZenTableManager"
     42      ztm = ZenTableManager(id)
     43      context._setObject(id, ztm)
     44      ztm = context._getOb(id)
     45      ztm.initTableManagerSkins()
     46
     47      if REQUEST is not None:
     48          REQUEST.RESPONSE.redirect(context.absolute_url()
     49                                       +'/manage_main')
     50
     51 -class ZenTableManager(SimpleItem, PropertyManager):
     52      """ZenTableManager manages display of tabular data"""
     53
     54      portal_type = meta_type = 'ZenTableManager'
     55
     56      _properties = (
     57          {'id':'defaultBatchSize', 'type':'int','mode':'w'},
     58          {'id':'abbrStartLabel', 'type':'int','mode':'w'},
     59          {'id':'abbrEndLabel', 'type':'int','mode':'w'},
     60          {'id':'abbrPadding', 'type':'int','mode':'w'},
     61          {'id':'abbrSeparator', 'type':'string','mode':'w'},
     62      )
     63
     64      manage_options = (
     65                          PropertyManager.manage_options +
     66                          SimpleItem.manage_options
     67                       )
     68
     69
     70 -    def __init__(self, id):
     71          self.id = id
     72          self.defaultBatchSize = 40
     73          self.abbrStartLabel = 15
     74          self.abbrEndLabel = 5
     75          self.abbrPadding = 5
     76          self.abbrSeparator = ".."
     77          self.abbrThresh = self.abbrStartLabel + \
     78                          self.abbrEndLabel + self.abbrPadding
     79
     80
     81 -    def getDefaultBatchSize(self):
     82          dbs = self.defaultBatchSize
     83          zu = getattr(self, "ZenUsers", None)
     84          if zu and zu.getUserSettings():
     85              dbs = zu.getUserSettings().defaultPageSize
     86          return dbs
     87
     88
     89 -    def setupTableState(self, tableName, **keys):
     90          """initialize or setup the session variable to track table state"""
     91          tableState = self.getTableState(tableName, **keys)
     92          request = self.REQUEST
     93          tableState.updateFromRequest(request)
     94          return tableState
     95
     96
     97 -    def getTableState(self, tableName, attrname=None, default=None, **keys):
     98          """return an existing table state or a single value from the state"""
     99          from Products.ZenUtils.Utils import unused
    100          unused(default)
    101          request = self.REQUEST
    102          tableStates = self.getTableStates()
    103          tableState = tableStates.get(tableName, None)
    104          if not tableState:
    105              dbs = self.getDefaultBatchSize()
    106              tableStates[tableName] = ZenTableState(request,tableName,dbs,**keys)
    107              tableState = tableStates[tableName]
    108          if attrname == None:
    109              return tableStates[tableName]
    110          return getattr(tableState, attrname, None)
    111
    112
    113 -    def getReqTableState(self, tableName, attrname):
    114          """
    115          Return attrname from request if present if not return from tableState.
    116          """
    117          request = self.REQUEST
    118          if request.has_key(attrname):
    119              return request[attrname]
    120          return self.getTableState(tableName, attrname)
    121
    122
    123 -    def setTableState(self, tableName, attrname, value):
    124          """Set the value of a table state attribute and return it."""
    125          tableState = self.getTableState(tableName)
    126          return tableState.setTableState(attrname, value)
    127
    128
    129 -    def setReqTableState(self, tableName, attrname, default=None, reset=False):
    130          """set the a value in the table state from the request"""
    131          tableState = self.getTableState(tableName)
    132          value = self.REQUEST.get(attrname, None)
    133          tableState = self.getTableState(tableName)
    134          return tableState.setTableState(attrname, value,
    135                                          default=default, reset=reset)
    136
    137
    138 -    def getBatch(self, tableName, objects, **keys):
    139          """Filter, sort and batch objects and pass return set.
    140          """
    141          if not objects:
    142              objects = []
    143          tableState = self.setupTableState(tableName, **keys)
    144          if tableState.onlyMonitored and objects:
    145              objects = [o for o in objects if getattr(o, 'isMonitored', o.monitored)()]
    146          if tableState.filter and objects:
    147              objects = self.filterObjects(objects, tableState.filter,
    148                                          tableState.filterFields)
    149          # objects is frequently a generator.  Need a list in order to sort
    150          if not isinstance(objects, list):
    151              objects = list(objects)
    152          if tableState.sortedHeader:
    153              objects = self.sortObjects(objects, tableState)
    154          tableState.totalobjs = len(objects)
    155          tableState.buildPageNavigation(objects)
    156          if not hasattr(self.REQUEST, 'doExport'):
    157              objects = ZTUtils.Batch(objects,
    158                          tableState.batchSize or len(objects),
    159                          start=tableState.start, orphan=0)
    160          return objects
    161
    162
    163 -    def getBatchForm(self, objects, request):
    164          """Create batch based on objects no sorting for filter applied.
    165          """
    166          batchSize = request.get('batchSize',self.defaultBatchSize)
    167          if batchSize in ['', '0']:
    168              batchSize = 0
    169          else:
    170              batchSize = int(batchSize)
    171          start = int(request.get('start',0))
    172          resetStart = int(request.get('resetStart',0))
    173          lastindex = request.get('lastindex',0)
    174          navbutton = request.get('navbutton',None)
    175          if navbutton == "first" or resetStart:
    176              start = 0
    177          elif navbutton == "last":
    178              start=lastindex
    179          elif navbutton == "next":
    180              start = start + batchSize
    181              if start > lastindex: start = lastindex
    182          elif navbutton == "prev":
    183              start = start - batchSize
    184          elif request.has_key("nextstart"):
    185              start = request.nextstart
    186          if 0 < start > len(objects): start = 0
    187          request.start = start
    188          objects = ZTUtils.Batch(objects, batchSize or len(objects),
    189                      start=request.start, orphan=0)
    190          return objects
    191
    192
    193 -    def filterObjects(self, objects, regex, filterFields):
    194          """filter objects base on a regex in regex and list of fields
    195          in filterFields."""
    196          if self.REQUEST.SESSION.has_key('message'):
    197              self.REQUEST.SESSION.delete('message')
    198          if not regex:
    199              return objects
    200          try: search = re.compile(regex,re.I).search
    201          except re.error:
    202              self.REQUEST.SESSION['message'] = "Invalid regular expression."
    203              return objects
    204          filteredObjects = []
    205          for obj in objects:
    206              target = []
    207              for field in filterFields:
    208                  if isinstance(obj, dict):
    209                      value = obj.get(field, None)
    210                  else:
    211                      value = getattr(obj, field, None)
    212                  if callable(value):
    213                      value = value()
    214                  if not isinstance(value, basestring):
    215                      value = str(value)
    216                  target.append(value)
    217              targetstring = " ".join(target)
    218              if search(targetstring): filteredObjects.append(obj)
    219          return filteredObjects
    220
    221
    222 -    def sortObjects(self, objects, request):
    223          """Sort objects.
    224          """
    225          def dictAwareSort(objects, field, rule, sence):
    226              if not objects:
    227                  return objects
    228              class Wrapper:
    229                  def __init__(self, field, cargo):
    230                      if callable(field): field = field()
    231                      self.field = field
    232                      self.cargo = cargo
    233              if isinstance(objects[0], dict):
    234                  objects = [Wrapper(o.get(field, ''), o) for o in objects]
    235              else:
    236                  objects = [Wrapper(getattr(o, field, ''), o) for o in objects]
    237              objects = sort(objects, (('field', rule, sence),))
    238              return [w.cargo for w in objects]
    239
    240          if (getattr(aq_base(request), 'sortedHeader', False)
    241              and getattr(aq_base(request),"sortedSence", False)):
    242              sortedHeader = request.sortedHeader
    243              sortedSence = request.sortedSence
    244              sortRule = getattr(aq_base(request), "sortRule", "cmp")
    245              objects = dictAwareSort(objects, sortedHeader, sortRule, sortedSence)
    246          return objects
    247
    248
    249 -    def getTableHeader(self, tableName, fieldName, fieldTitle,
    250                  sortRule='cmp', style='tableheader',attributes=""):
    251          """generate a <th></th> tag that allows column sorting"""
    252          href = self.getTableHeaderHref(tableName, fieldName, sortRule)
    253          style = self.getTableHeaderStyle(tableName, fieldName, style)
    254          tag = """<th class="%s" %s>""" % (style, attributes)
    255          tag += """<a class="%s" href="%s""" % (style, href)
    256          tag += fieldTitle + "</a></th>\n"
    257          return tag
    258
    259
    260 -    def getTableHeaderHref(self, tableName, fieldName,
    261                              sortRule='cmp',params=""):
    262          """build the href attribute for the table table headers"""
    263
    264          tableState = self.getTableState(tableName)
    265          sortedHeader = tableState.sortedHeader
    266          sortedSence = tableState.sortedSence
    267          if sortedHeader == fieldName:
    268              if sortedSence == 'asc':
    269                  sortedSence = 'desc'
    270              elif sortedSence == 'desc':
    271                  fieldName = ''
    272                  sortedSence = ''
    273          else:
    274              sortedSence = 'asc'
    275          href = "%s?tableName=%s&sortedHeader=%s&" % (
    276                  self.REQUEST.URL, tableName, fieldName)
    277          href += "sortedSence=%s&sortRule=%s%s\">" % (
    278                  sortedSence, sortRule, params)
    279          tableState.addFilterField(fieldName)
    280          return href
    281
    282
    283 -    def getTableHeaderStyle(self, tableName, fieldName, style):
    284          """apends "selected" onto the CSS style if this field is selected"""
    285          if self.getTableState(tableName, "sortedHeader") == fieldName:
    286              style = style + "selected"
    287          return style
    288
    289
    290 -    def getTableStates(self):
    291          session = self.REQUEST.SESSION
    292          try:
    293              return session['zentablestates']
    294          except KeyError:
    295              init = {}
    296              session['zentablestates'] = init
    297              return init
    298
    299
    300 -    def tableStatesHasTable(self, tableName):
    301          return self.getTableStates().has_key(tableName)
    302
    303
    304 -    def getNavData(self, objects, batchSize, sortedHeader):
    305          pagenav = []
    306          if batchSize in ['', '0']:
    307              batchSize = 0
    308          else:
    309              batchSize = int(batchSize)
    310          for index in range(0, len(objects), batchSize or len(objects)):
    311              if sortedHeader:
    312                  label = self._buildTextLabel(objects[index], sortedHeader)
    313              elif batchSize:
    314                  label = str(1+index/batchSize)
    315              else:
    316                  label = '1'
    317              pagenav.append({ 'label': label, 'index': index })
    318          return pagenav
    319
    320
    321 -    def _buildTextLabel(self, item, sortedHeader):
    322          startAbbr = ""
    323          endAbbr = ""
    324          attr = getattr(item, sortedHeader, "")
    325          if callable(attr): attr = attr()
    326          label = str(attr)
    327          if len(label) > self.abbrThresh:
    328              startAbbr = label[:self.abbrStartLabel]
    329              if self.abbrEndLabel > 0:
    330                  endAbbr = label[-self.abbrEndLabel:]
    331              label = "".join((startAbbr, self.abbrSeparator, endAbbr))
    332          return label
    333
    334
    335 -    def initTableManagerSkins(self):
    336          """setup the skins that come with ZenTableManager"""
    337          layers = ('zentablemanager','zenui')
    338          try:
    339              import string
    340              from Products.CMFCore.utils import getToolByName
    341              from Products.CMFCore.DirectoryView import addDirectoryViews
    342              skinstool = getToolByName(self, 'portal_skins')
    343              for layer in layers:
    344                  if layer not in skinstool.objectIds():
    345                      addDirectoryViews(skinstool, 'skins', globals())
    346              skins = skinstool.getSkinSelections()
    347              for skin in skins:
    348                  path = skinstool.getSkinPath(skin)
    349                  path = map(string.strip, string.split(path,','))
    350                  for layer in layers:
    351                      if layer not in path:
    352                          try:
    353                              path.insert(path.index('custom')+1, layer)
    354                          except ValueError:
    355                              path.append(layer)
    356                  path = ','.join(path)
    357                  skinstool.addSkinSelection(skin, path)
    358          except ImportError, e:
    359              if "Products.CMFCore.utils" in e.args: pass
    360              else: raise
    361          except AttributeError, e:
    362              if "portal_skin" in e.args: pass
    363              else: raise
    364
    365
    366  InitializeClass(ZenTableManager)
    367