Merge lp:~openerp-dev/openerp-web/trunk-new-graphview-ged into lp:openerp-web
- trunk-new-graphview-ged
- Merge into trunk
Proposed by
Géry Debongnie
Status: | Merged |
---|---|
Merged at revision: | 3929 |
Proposed branch: | lp:~openerp-dev/openerp-web/trunk-new-graphview-ged |
Merge into: | lp:openerp-web |
Diff against target: |
545 lines (+292/-153) 6 files modified
addons/web_graph/__init__.py (+1/-0) addons/web_graph/controllers/__init__.py (+1/-0) addons/web_graph/controllers/main.py (+88/-0) addons/web_graph/static/src/js/graph_widget.js (+195/-153) addons/web_graph/static/src/js/pivot_table.js (+4/-0) addons/web_graph/static/src/xml/web_graph.xml (+3/-0) |
To merge this branch: | bzr merge lp:~openerp-dev/openerp-web/trunk-new-graphview-ged |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Xavier (Open ERP) (community) | Needs Fixing | ||
Review via email:
|
Commit message
Description of the change
Export functionality... Only code that changed is in addon web_graph (web)
To post a comment you must log in.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Xavier (Open ERP) (xmo-deactivatedaccount) wrote : | # |
review:
Needs Fixing
- 4119. By Géry Debongnie
-
[FIX] many small tweaks, add some comment, rename variables to have better more informative names in excel export functionality in graph view (addon web_graph)
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Géry Debongnie (gery-debongnie) wrote : | # |
The fixing has been done...
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'addons/web_graph/__init__.py' | |||
2 | --- addons/web_graph/__init__.py 2012-10-23 15:26:46 +0000 | |||
3 | +++ addons/web_graph/__init__.py 2014-02-05 13:14:23 +0000 | |||
4 | @@ -0,0 +1,1 @@ | |||
5 | 1 | import controllers | ||
6 | 0 | 2 | ||
7 | === added directory 'addons/web_graph/controllers' | |||
8 | === added file 'addons/web_graph/controllers/__init__.py' | |||
9 | --- addons/web_graph/controllers/__init__.py 1970-01-01 00:00:00 +0000 | |||
10 | +++ addons/web_graph/controllers/__init__.py 2014-02-05 13:14:23 +0000 | |||
11 | @@ -0,0 +1,1 @@ | |||
12 | 1 | import main | ||
13 | 0 | \ No newline at end of file | 2 | \ No newline at end of file |
14 | 1 | 3 | ||
15 | === added file 'addons/web_graph/controllers/main.py' | |||
16 | --- addons/web_graph/controllers/main.py 1970-01-01 00:00:00 +0000 | |||
17 | +++ addons/web_graph/controllers/main.py 2014-02-05 13:14:23 +0000 | |||
18 | @@ -0,0 +1,88 @@ | |||
19 | 1 | from openerp import http | ||
20 | 2 | import simplejson | ||
21 | 3 | from openerp.http import request, serialize_exception as _serialize_exception | ||
22 | 4 | from cStringIO import StringIO | ||
23 | 5 | from collections import deque | ||
24 | 6 | |||
25 | 7 | try: | ||
26 | 8 | import xlwt | ||
27 | 9 | except ImportError: | ||
28 | 10 | xlwt = None | ||
29 | 11 | |||
30 | 12 | class TableExporter(http.Controller): | ||
31 | 13 | |||
32 | 14 | @http.route('/web_graph/check_xlwt', type='json', auth='none') | ||
33 | 15 | def check_xlwt(self): | ||
34 | 16 | return xlwt is not None | ||
35 | 17 | |||
36 | 18 | |||
37 | 19 | @http.route('/web_graph/export_xls', type='http', auth="user") | ||
38 | 20 | def export_xls(self, data, token): | ||
39 | 21 | jdata = simplejson.loads(data) | ||
40 | 22 | nbr_measures = jdata['nbr_measures'] | ||
41 | 23 | workbook = xlwt.Workbook() | ||
42 | 24 | worksheet = workbook.add_sheet(jdata['title']) | ||
43 | 25 | header_bold = xlwt.easyxf("font: bold on; pattern: pattern solid, fore_colour gray25;") | ||
44 | 26 | header_plain = xlwt.easyxf("pattern: pattern solid, fore_colour gray25;") | ||
45 | 27 | bold = xlwt.easyxf("font: bold on;") | ||
46 | 28 | |||
47 | 29 | # Step 1: writing headers | ||
48 | 30 | headers = jdata['headers'] | ||
49 | 31 | |||
50 | 32 | # x,y: current coordinates | ||
51 | 33 | # carry: queue containing cell information when a cell has a >= 2 height | ||
52 | 34 | # and the drawing code needs to add empty cells below | ||
53 | 35 | x, y, carry = 1, 0, deque() | ||
54 | 36 | for i, header_row in enumerate(headers): | ||
55 | 37 | worksheet.write(i,0, '', header_plain) | ||
56 | 38 | for header in header_row: | ||
57 | 39 | while (carry and carry[0]['x'] == x): | ||
58 | 40 | cell = carry.popleft() | ||
59 | 41 | for i in range(nbr_measures): | ||
60 | 42 | worksheet.write(y, x+i, '', header_plain) | ||
61 | 43 | if cell['height'] > 1: | ||
62 | 44 | carry.append({'x': x, 'height':cell['height'] - 1}) | ||
63 | 45 | x = x + nbr_measures | ||
64 | 46 | style = header_plain if 'expanded' in header else header_bold | ||
65 | 47 | for i in range(header['width']): | ||
66 | 48 | worksheet.write(y, x + i, header['title'] if i == 0 else '', style) | ||
67 | 49 | if header['height'] > 1: | ||
68 | 50 | carry.append({'x': x, 'height':header['height'] - 1}) | ||
69 | 51 | x = x + header['width']; | ||
70 | 52 | while (carry and carry[0]['x'] == x): | ||
71 | 53 | cell = carry.popleft() | ||
72 | 54 | for i in range(nbr_measures): | ||
73 | 55 | worksheet.write(y, x+i, '', header_plain) | ||
74 | 56 | if cell['height'] > 1: | ||
75 | 57 | carry.append({'x': x, 'height':cell['height'] - 1}) | ||
76 | 58 | x = x + nbr_measures | ||
77 | 59 | x, y = 1, y + 1 | ||
78 | 60 | |||
79 | 61 | # Step 2: measure row | ||
80 | 62 | if nbr_measures > 1: | ||
81 | 63 | worksheet.write(y,0, '', header_plain) | ||
82 | 64 | for measure in jdata['measure_row']: | ||
83 | 65 | style = header_bold if measure['is_bold'] else header_plain | ||
84 | 66 | worksheet.write(y, x, measure['text'], style); | ||
85 | 67 | x = x + 1 | ||
86 | 68 | y = y + 1 | ||
87 | 69 | |||
88 | 70 | # Step 3: writing data | ||
89 | 71 | x = 0 | ||
90 | 72 | for row in jdata['rows']: | ||
91 | 73 | worksheet.write(y, x, row['indent'] * ' ' + row['title'], header_plain) | ||
92 | 74 | for cell in row['cells']: | ||
93 | 75 | x = x + 1 | ||
94 | 76 | if cell.get('is_bold', False): | ||
95 | 77 | worksheet.write(y, x, cell['value'], bold) | ||
96 | 78 | else: | ||
97 | 79 | worksheet.write(y, x, cell['value']) | ||
98 | 80 | x, y = 0, y + 1 | ||
99 | 81 | |||
100 | 82 | response = request.make_response(None, | ||
101 | 83 | headers=[('Content-Type', 'application/vnd.ms-excel'), | ||
102 | 84 | ('Content-Disposition', 'attachment; filename=table.xls;')], | ||
103 | 85 | cookies={'fileToken': token}) | ||
104 | 86 | workbook.save(response.stream) | ||
105 | 87 | |||
106 | 88 | return response | ||
107 | 0 | 89 | ||
108 | === modified file 'addons/web_graph/static/src/js/graph_widget.js' | |||
109 | --- addons/web_graph/static/src/js/graph_widget.js 2014-01-28 15:11:13 +0000 | |||
110 | +++ addons/web_graph/static/src/js/graph_widget.js 2014-02-05 13:14:23 +0000 | |||
111 | @@ -25,6 +25,7 @@ | |||
112 | 25 | this.bar_ui = options.bar_ui || 'group'; | 25 | this.bar_ui = options.bar_ui || 'group'; |
113 | 26 | this.graph_view = options.graph_view || null; | 26 | this.graph_view = options.graph_view || null; |
114 | 27 | this.pivot_options = options; | 27 | this.pivot_options = options; |
115 | 28 | this.title = options.title || 'Data'; | ||
116 | 28 | }, | 29 | }, |
117 | 29 | 30 | ||
118 | 30 | start: function() { | 31 | start: function() { |
119 | @@ -39,6 +40,10 @@ | |||
120 | 39 | this.$('.graph_heatmap label').addClass('disabled'); | 40 | this.$('.graph_heatmap label').addClass('disabled'); |
121 | 40 | } | 41 | } |
122 | 41 | 42 | ||
123 | 43 | openerp.session.rpc('/web_graph/check_xlwt').then(function (result) { | ||
124 | 44 | self.$('.graph_options_selection label').toggle(result); | ||
125 | 45 | }); | ||
126 | 46 | |||
127 | 42 | return this.model.call('fields_get', []).then(function (f) { | 47 | return this.model.call('fields_get', []).then(function (f) { |
128 | 43 | self.fields = f; | 48 | self.fields = f; |
129 | 44 | self.fields.__count = {field:'__count', type: 'integer', string:_t('Quantity')}; | 49 | self.fields.__count = {field:'__count', type: 'integer', string:_t('Quantity')}; |
130 | @@ -85,8 +90,8 @@ | |||
131 | 85 | groupbys = _.flatten(_.map(filters, function (filter) { | 90 | groupbys = _.flatten(_.map(filters, function (filter) { |
132 | 86 | var groupby = py.eval(filter.attrs.context).group_by; | 91 | var groupby = py.eval(filter.attrs.context).group_by; |
133 | 87 | if (!(groupby instanceof Array)) { groupby = [groupby]; } | 92 | if (!(groupby instanceof Array)) { groupby = [groupby]; } |
136 | 88 | return _.map(groupby, function(g) { | 93 | return _.map(groupby, function(g) { |
137 | 89 | return {field: g, filter: filter}; | 94 | return {field: g, filter: filter}; |
138 | 90 | }); | 95 | }); |
139 | 91 | })); | 96 | })); |
140 | 92 | 97 | ||
141 | @@ -264,6 +269,9 @@ | |||
142 | 264 | case 'update_values': | 269 | case 'update_values': |
143 | 265 | this.pivot.update_data().then(this.proxy('display_data')); | 270 | this.pivot.update_data().then(this.proxy('display_data')); |
144 | 266 | break; | 271 | break; |
145 | 272 | case 'export_data': | ||
146 | 273 | this.export_xls(); | ||
147 | 274 | break; | ||
148 | 267 | } | 275 | } |
149 | 268 | }, | 276 | }, |
150 | 269 | 277 | ||
151 | @@ -356,13 +364,117 @@ | |||
152 | 356 | }, | 364 | }, |
153 | 357 | 365 | ||
154 | 358 | // ---------------------------------------------------------------------- | 366 | // ---------------------------------------------------------------------- |
155 | 367 | // Convert Pivot data structure into table structure : | ||
156 | 368 | // compute rows, cols, colors, cell width, cell height, ... | ||
157 | 369 | // ---------------------------------------------------------------------- | ||
158 | 370 | build_table: function() { | ||
159 | 371 | return { | ||
160 | 372 | headers: this.build_headers(), | ||
161 | 373 | measure_row: this.build_measure_row(), | ||
162 | 374 | rows: this.build_rows(), | ||
163 | 375 | nbr_measures: this.pivot.measures.length, | ||
164 | 376 | title: this.title, | ||
165 | 377 | }; | ||
166 | 378 | }, | ||
167 | 379 | |||
168 | 380 | build_headers: function () { | ||
169 | 381 | var pivot = this.pivot, | ||
170 | 382 | nbr_measures = pivot.measures.length, | ||
171 | 383 | height = _.max(_.map(pivot.cols.headers, function(g) {return g.path.length;})), | ||
172 | 384 | rows = []; | ||
173 | 385 | |||
174 | 386 | _.each(pivot.cols.headers, function (col) { | ||
175 | 387 | if (col.path.length === 0) { return;} | ||
176 | 388 | var cell_width = nbr_measures * (col.expanded ? pivot.get_ancestor_leaves(col).length : 1), | ||
177 | 389 | cell_height = col.expanded ? 1 : height - col.path.length + 1, | ||
178 | 390 | cell = {width: cell_width, height: cell_height, title: col.title, id: col.id, expanded: col.expanded}; | ||
179 | 391 | if (rows[col.path.length - 1]) { | ||
180 | 392 | rows[col.path.length - 1].push(cell); | ||
181 | 393 | } else { | ||
182 | 394 | rows[col.path.length - 1] = [cell]; | ||
183 | 395 | } | ||
184 | 396 | }); | ||
185 | 397 | |||
186 | 398 | if (pivot.get_cols_leaves().length > 1) { | ||
187 | 399 | rows[0].push({width: nbr_measures, height: height, title: _t('Total'), id: pivot.main_col().id }); | ||
188 | 400 | } | ||
189 | 401 | if (pivot.cols.headers.length === 1) { | ||
190 | 402 | rows = [[{width: nbr_measures, height: 1, title: _t('Total'), id: pivot.main_col().id, expanded: false}]]; | ||
191 | 403 | } | ||
192 | 404 | return rows; | ||
193 | 405 | }, | ||
194 | 406 | |||
195 | 407 | build_measure_row: function () { | ||
196 | 408 | var nbr_leaves = this.pivot.get_cols_leaves().length, | ||
197 | 409 | nbr_cols = nbr_leaves + ((nbr_leaves > 1) ? 1 : 0), | ||
198 | 410 | result = [], | ||
199 | 411 | add_total = this.pivot.get_cols_leaves().length > 1, | ||
200 | 412 | i, m; | ||
201 | 413 | for (i = 0; i < nbr_cols; i++) { | ||
202 | 414 | for (m = 0; m < this.pivot.measures.length; m++) { | ||
203 | 415 | result.push({ | ||
204 | 416 | text:this.pivot.measures[m].string, | ||
205 | 417 | is_bold: add_total && (i === nbr_cols - 1) | ||
206 | 418 | }); | ||
207 | 419 | } | ||
208 | 420 | } | ||
209 | 421 | return result; | ||
210 | 422 | }, | ||
211 | 423 | |||
212 | 424 | make_cell: function (row, col, value, index) { | ||
213 | 425 | var formatted_value = openerp.web.format_value(value, {type:this.pivot.measures[index].type}), | ||
214 | 426 | cell = {value:formatted_value}; | ||
215 | 427 | |||
216 | 428 | if (this.heatmap_mode === 'none') { return cell; } | ||
217 | 429 | var total = (this.heatmap_mode === 'both') ? this.pivot.get_total()[index] | ||
218 | 430 | : (this.heatmap_mode === 'row') ? this.pivot.get_total(row)[index] | ||
219 | 431 | : this.pivot.get_total(col)[index]; | ||
220 | 432 | var color = Math.floor(90 + 165*(total - Math.abs(value))/total); | ||
221 | 433 | if (color < 255) { | ||
222 | 434 | cell.color = color; | ||
223 | 435 | } | ||
224 | 436 | return cell; | ||
225 | 437 | }, | ||
226 | 438 | |||
227 | 439 | build_rows: function () { | ||
228 | 440 | var self = this, | ||
229 | 441 | pivot = this.pivot, | ||
230 | 442 | m, cell; | ||
231 | 443 | |||
232 | 444 | return _.map(pivot.rows.headers, function (row) { | ||
233 | 445 | var cells = []; | ||
234 | 446 | _.each(pivot.get_cols_leaves(), function (col) { | ||
235 | 447 | var values = pivot.get_values(row.id,col.id); | ||
236 | 448 | for (m = 0; m < pivot.measures.length; m++) { | ||
237 | 449 | cells.push(self.make_cell(row,col,values[m], m)); | ||
238 | 450 | } | ||
239 | 451 | }); | ||
240 | 452 | if (pivot.get_cols_leaves().length > 1) { | ||
241 | 453 | var totals = pivot.get_total(row); | ||
242 | 454 | for (m = 0; m < pivot.measures.length; m++) { | ||
243 | 455 | cell = self.make_cell(row, pivot.main_col(), totals[m], m); | ||
244 | 456 | cell.is_bold = 'true'; | ||
245 | 457 | cells.push(cell); | ||
246 | 458 | } | ||
247 | 459 | } | ||
248 | 460 | return { | ||
249 | 461 | id: row.id, | ||
250 | 462 | indent: row.path.length, | ||
251 | 463 | title: row.title, | ||
252 | 464 | expanded: row.expanded, | ||
253 | 465 | cells: cells, | ||
254 | 466 | }; | ||
255 | 467 | }); | ||
256 | 468 | }, | ||
257 | 469 | |||
258 | 470 | // ---------------------------------------------------------------------- | ||
259 | 359 | // Main display method | 471 | // Main display method |
260 | 360 | // ---------------------------------------------------------------------- | 472 | // ---------------------------------------------------------------------- |
261 | 361 | display_data: function () { | 473 | display_data: function () { |
262 | 362 | this.$('.graph_main_content svg').remove(); | 474 | this.$('.graph_main_content svg').remove(); |
263 | 363 | this.$('.graph_main_content div').remove(); | 475 | this.$('.graph_main_content div').remove(); |
264 | 364 | this.table.empty(); | 476 | this.table.empty(); |
266 | 365 | this.table.toggleClass('heatmap', this.heatmap_mode !== 'none') | 477 | this.table.toggleClass('heatmap', this.heatmap_mode !== 'none'); |
267 | 366 | this.width = this.$el.width(); | 478 | this.width = this.$el.width(); |
268 | 367 | this.height = Math.min(Math.max(document.documentElement.clientHeight - 116 - 60, 250), Math.round(0.8*this.$el.width())); | 479 | this.height = Math.min(Math.max(document.documentElement.clientHeight - 116 - 60, 250), Math.round(0.8*this.$el.width())); |
269 | 368 | 480 | ||
270 | @@ -384,159 +496,75 @@ | |||
271 | 384 | // Drawing the table | 496 | // Drawing the table |
272 | 385 | // ---------------------------------------------------------------------- | 497 | // ---------------------------------------------------------------------- |
273 | 386 | draw_table: function () { | 498 | draw_table: function () { |
333 | 387 | this.draw_top_headers(); | 499 | var table = this.build_table(); |
334 | 388 | _.each(this.pivot.rows.headers, this.proxy('draw_row')); | 500 | this.draw_headers(table.headers); |
335 | 389 | }, | 501 | this.draw_measure_row(table.measure_row); |
336 | 390 | 502 | this.draw_rows(table.rows); | |
337 | 391 | make_border_cell: function (colspan, rowspan, headercell) { | 503 | }, |
338 | 392 | var tag = (headercell) ? $('<th>') : $('<td>'); | 504 | |
339 | 393 | return tag.addClass('graph_border') | 505 | make_header_cell: function (header) { |
340 | 394 | .attr('colspan', colspan || 1) | 506 | var cell = (_.has(header, 'cells') ? $('<td>') : $('<th>')) |
341 | 395 | .attr('rowspan', rowspan || 1); | 507 | .addClass('graph_border') |
342 | 396 | }, | 508 | .attr('rowspan', header.height) |
343 | 397 | 509 | .attr('colspan', header.width); | |
344 | 398 | make_header_title: function (header) { | 510 | var content = $('<span>').addClass('web_graph_click') |
345 | 399 | return $('<span> ') | 511 | .attr('href','#') |
346 | 400 | .addClass('web_graph_click') | 512 | .text(' ' + (header.title || _t('Undefined'))) |
347 | 401 | .attr('href', '#') | 513 | .attr('data-id', header.id); |
348 | 402 | .addClass((header.expanded) ? 'fa fa-minus-square' : 'fa fa-plus-square') | 514 | if (_.has(header, 'expanded')) { |
349 | 403 | .text(' ' + (header.title || 'Undefined')); | 515 | content.addClass(header.expanded ? 'fa fa-minus-square' : 'fa fa-plus-square'); |
291 | 404 | }, | ||
292 | 405 | |||
293 | 406 | draw_top_headers: function () { | ||
294 | 407 | var self = this, | ||
295 | 408 | thead = $('<thead>'), | ||
296 | 409 | pivot = this.pivot, | ||
297 | 410 | height = _.max(_.map(pivot.cols.headers, function(g) {return g.path.length;})), | ||
298 | 411 | header_cells = [[this.make_border_cell(1, height, true)]]; | ||
299 | 412 | |||
300 | 413 | function set_dim (cols) { | ||
301 | 414 | _.each(cols.children, set_dim); | ||
302 | 415 | if (cols.children.length === 0) { | ||
303 | 416 | cols.height = height - cols.path.length + 1; | ||
304 | 417 | cols.width = 1; | ||
305 | 418 | } else { | ||
306 | 419 | cols.height = 1; | ||
307 | 420 | cols.width = _.reduce(cols.children, function (sum,c) { return sum + c.width;}, 0); | ||
308 | 421 | } | ||
309 | 422 | } | ||
310 | 423 | |||
311 | 424 | function make_col_header (col) { | ||
312 | 425 | var cell = self.make_border_cell(col.width*pivot.measures.length, col.height, true); | ||
313 | 426 | return cell.append(self.make_header_title(col).attr('data-id', col.id)); | ||
314 | 427 | } | ||
315 | 428 | |||
316 | 429 | function make_cells (queue, level) { | ||
317 | 430 | var col = queue[0]; | ||
318 | 431 | queue = _.rest(queue).concat(col.children); | ||
319 | 432 | if (col.path.length == level) { | ||
320 | 433 | _.last(header_cells).push(make_col_header(col)); | ||
321 | 434 | } else { | ||
322 | 435 | level +=1; | ||
323 | 436 | header_cells.push([make_col_header(col)]); | ||
324 | 437 | } | ||
325 | 438 | if (queue.length !== 0) { | ||
326 | 439 | make_cells(queue, level); | ||
327 | 440 | } | ||
328 | 441 | } | ||
329 | 442 | |||
330 | 443 | set_dim(pivot.main_col()); // add width and height info to columns headers | ||
331 | 444 | if (pivot.main_col().children.length === 0) { | ||
332 | 445 | make_cells(pivot.cols.headers, 0); | ||
350 | 446 | } else { | 516 | } else { |
413 | 447 | make_cells(pivot.main_col().children, 1); | 517 | content.css('font-weight', 'bold'); |
414 | 448 | if (pivot.get_cols_leaves().length > 1) { | 518 | } |
415 | 449 | header_cells[0].push(self.make_border_cell(pivot.measures.length, height, true).text(_t('Total')).css('font-weight', 'bold')); | 519 | if (_.has(header, 'indent')) { |
416 | 450 | } | 520 | for (var i = 0; i < header.indent; i++) { cell.prepend($('<span>', {class:'web_graph_indent'})); } |
417 | 451 | } | 521 | } |
418 | 452 | 522 | return cell.append(content); | |
419 | 453 | _.each(header_cells, function (cells) { | 523 | }, |
420 | 454 | thead.append($('<tr>').append(cells)); | 524 | |
421 | 455 | }); | 525 | draw_headers: function (headers) { |
422 | 456 | 526 | var make_cell = this.make_header_cell, | |
423 | 457 | if (pivot.measures.length >= 2) { | 527 | empty_cell = $('<th>').attr('rowspan', headers.length), |
424 | 458 | thead.append(self.make_measure_row()); | 528 | thead = $('<thead>'); |
425 | 459 | } | 529 | |
426 | 460 | 530 | _.each(headers, function (row) { | |
427 | 461 | self.table.append(thead); | 531 | var html_row = $('<tr>'); |
428 | 462 | }, | 532 | _.each(row, function (header) { |
429 | 463 | 533 | html_row.append(make_cell(header)); | |
430 | 464 | make_measure_cells: function () { | 534 | }); |
431 | 465 | return _.map(this.pivot.measures, function (measure) { | 535 | thead.append(html_row); |
432 | 466 | return $('<th>').addClass('measure_row').text(measure.string); | 536 | }); |
433 | 467 | }); | 537 | thead.children(':first').prepend(empty_cell); |
434 | 468 | }, | 538 | this.table.append(thead); |
435 | 469 | 539 | }, | |
436 | 470 | make_measure_row: function() { | 540 | |
437 | 471 | var self = this, | 541 | draw_measure_row: function (measure_row) { |
438 | 472 | cols = this.pivot.cols.headers, | 542 | if (this.pivot.measures.length === 1) { return; } |
439 | 473 | measure_row = $('<tr>'); | 543 | var html_row = $('<tr>').append('<th>'); |
440 | 474 | 544 | _.each(measure_row, function (cell) { | |
441 | 475 | measure_row.append($('<th>')); | 545 | var measure_cell = $('<th>').addClass('measure_row').text(cell.text); |
442 | 476 | 546 | if (cell.is_bold) {measure_cell.css('font-weight', 'bold');} | |
443 | 477 | _.each(cols, function (col) { | 547 | html_row.append(measure_cell); |
444 | 478 | if (!col.children.length) { | 548 | }); |
445 | 479 | measure_row.append(self.make_measure_cells()); | 549 | this.$('thead').append(html_row); |
446 | 480 | } | 550 | }, |
447 | 481 | }); | 551 | |
448 | 482 | 552 | draw_rows: function (rows) { | |
449 | 483 | if (this.pivot.get_cols_leaves().length > 1) { | 553 | var table = this.table, |
450 | 484 | measure_row.append(self.make_measure_cells()); | 554 | make_cell = this.make_header_cell; |
451 | 485 | } | 555 | |
452 | 486 | return measure_row; | 556 | _.each(rows, function (row) { |
453 | 487 | }, | 557 | var html_row = $('<tr>').append(make_cell(row)); |
454 | 488 | 558 | _.each(row.cells, function (cell) { | |
455 | 489 | draw_row: function (row) { | 559 | var html_cell = $('<td>').text(cell.value); |
456 | 490 | var self = this, | 560 | if (_.has(cell, 'color')) { |
457 | 491 | pivot = this.pivot, | 561 | html_cell.css('background-color', $.Color(255, cell.color, cell.color)); |
396 | 492 | measure_types = _.pluck(this.pivot.measures, 'type'), | ||
397 | 493 | html_row = $('<tr>'), | ||
398 | 494 | row_header = this.make_border_cell(1,1) | ||
399 | 495 | .append(this.make_header_title(row).attr('data-id', row.id)) | ||
400 | 496 | .addClass('graph_border'); | ||
401 | 497 | |||
402 | 498 | for (var i = 0; i < row.path.length; i++) { | ||
403 | 499 | row_header.prepend($('<span>', {class:'web_graph_indent'})); | ||
404 | 500 | } | ||
405 | 501 | |||
406 | 502 | html_row.append(row_header); | ||
407 | 503 | |||
408 | 504 | _.each(pivot.cols.headers, function (col) { | ||
409 | 505 | if (!col.children.length) { | ||
410 | 506 | var values = pivot.get_values(row.id, col.id); | ||
411 | 507 | for (var i = 0; i < values.length; i++) { | ||
412 | 508 | html_row.append(make_cell(values[i], measure_types[i], i, col)); | ||
458 | 509 | } | 562 | } |
460 | 510 | } | 563 | if (cell.is_bold) { html_cell.css('font-weight', 'bold'); } |
461 | 564 | html_row.append(html_cell); | ||
462 | 565 | }); | ||
463 | 566 | table.append(html_row); | ||
464 | 511 | }); | 567 | }); |
465 | 512 | |||
466 | 513 | if (pivot.get_cols_leaves().length > 1) { | ||
467 | 514 | var total_vals = pivot.get_total(row); | ||
468 | 515 | for (var j = 0; j < total_vals.length; j++) { | ||
469 | 516 | var cell = make_cell(total_vals[j], measure_types[j], j, pivot.cols[0]).css('font-weight', 'bold'); | ||
470 | 517 | html_row.append(cell); | ||
471 | 518 | } | ||
472 | 519 | } | ||
473 | 520 | |||
474 | 521 | this.table.append(html_row); | ||
475 | 522 | |||
476 | 523 | function make_cell (value, measure_type, index, col) { | ||
477 | 524 | var cell = $('<td>'); | ||
478 | 525 | if (value === undefined) { | ||
479 | 526 | return cell; | ||
480 | 527 | } | ||
481 | 528 | cell.text(openerp.web.format_value(value, {type: measure_type})); | ||
482 | 529 | var total = (self.heatmap_mode === 'both') ? pivot.get_total()[index] | ||
483 | 530 | : (self.heatmap_mode === 'row') ? pivot.get_total(row)[index] | ||
484 | 531 | : (self.heatmap_mode === 'col') ? pivot.get_total(col)[index] | ||
485 | 532 | : undefined; | ||
486 | 533 | |||
487 | 534 | if (self.heatmap_mode !== 'none') { | ||
488 | 535 | var color = Math.floor(90 + 165*(total - Math.abs(value))/total); | ||
489 | 536 | cell.css('background-color', $.Color(255, color, color)); | ||
490 | 537 | } | ||
491 | 538 | return cell; | ||
492 | 539 | } | ||
493 | 540 | }, | 568 | }, |
494 | 541 | 569 | ||
495 | 542 | // ---------------------------------------------------------------------- | 570 | // ---------------------------------------------------------------------- |
496 | @@ -693,6 +721,20 @@ | |||
497 | 693 | }); | 721 | }); |
498 | 694 | }, | 722 | }, |
499 | 695 | 723 | ||
500 | 724 | // ---------------------------------------------------------------------- | ||
501 | 725 | // Controller stuff... | ||
502 | 726 | // ---------------------------------------------------------------------- | ||
503 | 727 | export_xls: function() { | ||
504 | 728 | var c = openerp.webclient.crashmanager; | ||
505 | 729 | openerp.web.blockUI(); | ||
506 | 730 | this.session.get_file({ | ||
507 | 731 | url: '/web_graph/export_xls', | ||
508 | 732 | data: {data: JSON.stringify(this.build_table())}, | ||
509 | 733 | complete: openerp.web.unblockUI, | ||
510 | 734 | error: c.rpc_error.bind(c) | ||
511 | 735 | }); | ||
512 | 736 | }, | ||
513 | 737 | |||
514 | 696 | }); | 738 | }); |
515 | 697 | 739 | ||
516 | 698 | // Utility function: returns true if the beginning of array2 is array1 and | 740 | // Utility function: returns true if the beginning of array2 is array1 and |
517 | 699 | 741 | ||
518 | === modified file 'addons/web_graph/static/src/js/pivot_table.js' | |||
519 | --- addons/web_graph/static/src/js/pivot_table.js 2014-01-28 15:11:57 +0000 | |||
520 | +++ addons/web_graph/static/src/js/pivot_table.js 2014-02-05 13:14:23 +0000 | |||
521 | @@ -127,6 +127,10 @@ | |||
522 | 127 | return this._get_headers_with_depth(this.rows.headers, depth); | 127 | return this._get_headers_with_depth(this.rows.headers, depth); |
523 | 128 | }, | 128 | }, |
524 | 129 | 129 | ||
525 | 130 | get_ancestor_leaves: function (header) { | ||
526 | 131 | return _.where(this.get_ancestors_and_self(header), {expanded:false}); | ||
527 | 132 | }, | ||
528 | 133 | |||
529 | 130 | // return all non expanded rows | 134 | // return all non expanded rows |
530 | 131 | get_rows_leaves: function () { | 135 | get_rows_leaves: function () { |
531 | 132 | return _.where(this.rows.headers, {expanded:false}); | 136 | return _.where(this.rows.headers, {expanded:false}); |
532 | 133 | 137 | ||
533 | === modified file 'addons/web_graph/static/src/xml/web_graph.xml' | |||
534 | --- addons/web_graph/static/src/xml/web_graph.xml 2014-01-17 14:43:03 +0000 | |||
535 | +++ addons/web_graph/static/src/xml/web_graph.xml 2014-02-05 13:14:23 +0000 | |||
536 | @@ -41,6 +41,9 @@ | |||
537 | 41 | <label class="btn btn-default" data-choice="update_values" title="Reload Data"> | 41 | <label class="btn btn-default" data-choice="update_values" title="Reload Data"> |
538 | 42 | <span class="fa fa-refresh"></span> | 42 | <span class="fa fa-refresh"></span> |
539 | 43 | </label> | 43 | </label> |
540 | 44 | <label class="btn btn-default" data-choice="export_data" title="Export Data" style="display:none"> | ||
541 | 45 | <span class="fa fa-download"></span> | ||
542 | 46 | </label> | ||
543 | 44 | </div> | 47 | </div> |
544 | 45 | <div class="btn-group"> | 48 | <div class="btn-group"> |
545 | 46 | <label class="btn btn-default dropdown-toggle" data-toggle="dropdown"> | 49 | <label class="btn btn-default dropdown-toggle" data-toggle="dropdown"> |
* `if (result) { self.$( '.graph_ options_ selection label') .toggle( true); }` could be replaced by `self.$ ('.graph_ options_ selection label') .toggle( result) ;` I think
* The Response object returned by make_response has a write-only `stream` attribute, so maybe (depending how complex workbook.save is) the StringIO dance could be replaced by:
response = self.make_ response( params) save(response. stream)
workbook.
return response
* maybe give a better name to the sheet e.g. the model name?
* `L` could probably benefit from comments to explain what it and its purpose are, maybe even a renaming. It seems to be used as a queue, but I'm not sure a queue of what. Also since it's a FIFO, should probably use collection.deque (.pop(0) is O(n) on a list, it's ~O(1) on deque, also it's called .popleft() which is clearer)
* in many worksheet.write() calls, there's a space missing after the first argument's comma, spacing also somewhat inconsistent in JS e.g. {width: nbr_measures, height:height, title: _t('Total'), id: pivot.cols. headers[ 0].id } some colons are followed by a space, others not
* maybe bold_style and non_bold_style should be renamed to header (or header_plain) and header_bold? Something like that? They seem to be header styles of sort (I may be wrong)