1
2
3
4
5
6
7
8
9
10
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
40
41
53
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
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
90
91
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
124
125
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
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
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
194
195
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
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
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
284
285
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
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
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
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