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