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 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
41
42
54
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
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
91
92
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
125
126
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
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
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
195
196
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
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
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
285
286
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
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
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
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