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