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

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