1 """Generic widget to present and manipulate data in a grid (tabular) form.
2
3 See also: http://trac.turbogears.org/turbogears/wiki/DataGridWidget
4
5 """
6
7 from turbogears.widgets import Widget, CSSLink, static
8 from turbogears.widgets.base import CoreWD
9
10 NoDefault = object()
11
12 __all__ = ["DataGrid", "PaginateDataGrid"]
16 """Generic widget to present and manipulate data in a grid (tabular) form.
17
18 The columns to build the grid from are specified with fields ctor argument
19 which is a list. Currently an element can be either a two-element tuple or
20 instance of DataGrid.Column class. If tuple is used it a Column is then
21 build out of it, first element is assumed to be a title and second element -
22 field accessor.
23
24 You can specify columns' data statically, via fields ctor parameter, or
25 dynamically, by via 'fields' key.
26
27 """
28 css = [CSSLink(static, "grid.css")]
29 template = "turbogears.widgets.templates.datagrid"
30 fields = None
31
33 """Simple struct that describes single DataGrid column.
34
35 Column has:
36 - a name, which allows to uniquely identify column in a DataGrid
37 - getter, which is used to extract field's value
38 - title, which is displayed in the table's header
39 - options, which is a way to carry arbitrary user-defined data
40 - attrwrapper, which is a function returning an object's attribute
41
42 """
43 - def __init__(self, name,
44 getter=None, title=None, options=None, attrwrapper=None):
66 return self.getter(row)
68 return "<DataGrid.Column %s>" % self.name
69
71 """Helper class that returns an object's attribute when called.
72
73 This allows to access 'dynamic' attributes (properties) as well as
74 simple static ones, and also allows nested access.
75
76 """
78 if not isinstance(name, (int, str)):
79 raise ValueError('attribute name must be'
80 ' an integer index or a string attribute')
81 self.name = name
83 if isinstance(obj, (dict, list, tuple)):
84 return obj[self.name]
85 for name in self.name.split('.'):
86 obj = getattr(obj, name)
87 if obj is None:
88 break
89 return obj
90
98
100 """Return DataGrid.Column with specified name.
101
102 Raises KeyError if no such column exists.
103
104 """
105 for col in self.columns:
106 if col.name == name:
107 return col
108 raise KeyError(name)
109
113
114 @staticmethod
116 """Return a function to access the fields of table by row, col."""
117 idx = {}
118 for col in columns:
119 idx[col.name] = col
120 def _get_field(row, col):
121 return idx[col].get_field(row)
122 return _get_field
123
133
135 """Parse field specifications into a list of Columns.
136
137 A specification can be a DataGrid.Column, an accessor
138 (attribute name or function), a tuple (title, accessor)
139 or a tuple (title, accessor, options).
140
141 """
142 columns = []
143 names = set()
144 for n, col in enumerate(fields):
145 if not isinstance(col, self.Column):
146 if isinstance(col, (str, int)) or callable(col):
147 name_or_f = col
148 title = options = None
149 else:
150 title, name_or_f = col[:2]
151 try:
152 options = col[2]
153 except IndexError:
154 options = None
155 name = 'column-' + str(n)
156 col = self.Column(name,
157 name_or_f, title, options, self.attrwrapper)
158 if col.name in names:
159 raise ValueError('Duplicate column name: %s' % name)
160 columns.append(col)
161 names.add(col.name)
162 return columns
163
166
167 name = "DataGrid"
168
169 for_widget = DataGrid(fields=[('Name', lambda row: row[1]),
170 ('Country', lambda row: row[2]),
171 ('Age', lambda row: row[0])],
172 default=[(33, "Anton Bykov", "Bulgaria"),
173 (23, "Joe Doe", "Great Britain"),
174 (44, "Pablo Martelli", "Brazil")])
175
178 """A data grid widget that supports the paginate decorator."""
179
180 template = "turbogears.widgets.templates.paginate_datagrid"
181
184
185 name = "PaginateDataGrid"
186
187 for_widget = DataGridDesc.for_widget
188
190
191 page_count = 5
192 pages = range(1, page_count + 1)
193 limit = 3
194 current_page = page_count // 2
195 href_first = "javascript:alert('This is only a mock-up.')"
196 href_prev = href_next = href_last = href_first
197 get_href = lambda self, page, **kw: self.href_first
198
205