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

Source Code for Module Products.ZenWidgets.ZenTableManager

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