Ticket #2669: report-by-xls-for-trac0_9_5.diff
| File report-by-xls-for-trac0_9_5.diff, 7.1 KB (added by anonymous, 3 years ago) |
|---|
-
ticket/report.py
28 28 from trac.wiki import wiki_to_html, IWikiSyntaxProvider 29 29 30 30 31 try: 32 from pyExcelerator import * 33 class XlsDoc(CompoundDoc.XlsDoc): 34 def get(self, stream): 35 padding = '\x00' * (0x1000 - (len(stream) % 0x1000)) 36 self.book_stream_len = len(stream) + len(padding) 37 self.__build_directory() 38 self.__build_sat() 39 self.__build_header() 40 return '%s%s%s%s%s%s%s' % ( 41 self.header, 42 self.packed_MSAT_1st, 43 stream, 44 padding, 45 self.packed_MSAT_2nd, 46 self.packed_SAT, 47 self.dir_stream) 48 49 class Workbook(Workbook): 50 def get(self): 51 doc = XlsDoc() 52 return doc.get(self.get_biff_data()) 53 54 has_pyexcel = 1 55 except: 56 has_pyexcel = 0 57 31 58 class ColumnSorter: 32 59 33 def __init__(self, columnIndex, asc=1 ):60 def __init__(self, columnIndex, asc=1, enums=None): 34 61 self.columnIndex = columnIndex 35 62 self.asc = asc 63 self.enums = enums 36 64 37 65 def sort(self, x, y): 38 66 const = -1 … … 42 70 # make sure to ignore case in comparisons 43 71 realX = x[self.columnIndex] 44 72 if isinstance(realX, (str, unicode)): 45 realX = realX.lower() 73 if self.enums and self.enums.has_key(realX): 74 realX = self.enums[realX] 75 else: 76 realX = realX.lower() 46 77 realY = y[self.columnIndex] 47 78 if isinstance(realY, (str, unicode)): 48 realY = realY.lower() 79 if self.enums and self.enums.has_key(realY): 80 realY = self.enums[realY] 81 else: 82 realY = realY.lower() 49 83 50 84 result = 0 51 85 if realX < realY: … … 305 339 if colIndex != None: 306 340 k = 'report.headers.%d.asc' % (colIndex - hiddenCols) 307 341 asc = req.args.get('asc', None) 342 enums = None 343 from trac.ticket import model 344 clses = {'severity':model.Severity, 'priority':model.Priority, 345 'resolution':model.Resolution, 346 'type':model.Type, 'status':model.Status} 347 if clses.has_key(sortCol): 348 scls = clses[sortCol] 349 enums = dict([(enum.name, enum.value) for enum in scls.select(self.env, db=db)]) 308 350 if asc: 309 sorter = ColumnSorter(colIndex, int(asc) )351 sorter = ColumnSorter(colIndex, int(asc), enums=enums) 310 352 req.hdf[k] = asc 311 353 else: 312 sorter = ColumnSorter(colIndex )354 sorter = ColumnSorter(colIndex, enums=enums) 313 355 req.hdf[k] = 1 314 356 rows.sort(sorter.sort) 315 357 … … 372 414 elif format == 'tab': 373 415 self._render_csv(req, cols, rows, '\t') 374 416 return None 417 elif format == 'xls': 418 self._render_xls(req, cols, rows) 419 return None 375 420 376 421 return 'report.cs', None 377 422 … … 390 435 'Comma-delimited Text', 'text/plain') 391 436 add_link(req, 'alternate', '?format=tab' + href, 392 437 'Tab-delimited Text', 'text/plain') 438 if has_pyexcel: 439 if self.env.config.getbool('ticket', 'show_excel_link'): 440 add_link(req, 'alternate', '?format=xls' + href, 441 'Excel', 'application/vnd.ms-excel') 393 442 if req.perm.has_permission('REPORT_SQL_VIEW'): 394 443 add_link(req, 'alternate', '?format=sql', 'SQL Query', 395 444 'text/plain') … … 485 534 req.write('-- %s\n\n' % '\n-- '.join(description.splitlines())) 486 535 req.write(sql) 487 536 537 def _render_xls(self, req, cols, rows): 538 req.send_response(200) 539 req.send_header('Content-Type', 'application/vnd.ms-excel') 540 req.send_header('Content-Disposition', 541 'filename=Report%s.xls' % req.hdf['report.id']) 542 req.end_headers() 543 544 wb = Workbook() 545 sheetname = "%s - %s" % (req.hdf['report.title'], 546 req.hdf['project.name']) 547 ws = wb.add_sheet(sheetname.decode('utf-8')) 548 ws.panes_frozen = True 549 ro = 1 550 ws.horz_split_pos = ro 551 552 import copy 553 554 font0 = Font() 555 font0.charset = font0.CHARSET_SYS_DEFAULT 556 font0.name = 'MS UI Gothic' 557 font1 = copy.copy(font0) 558 font1.bold = True 559 font2 = copy.copy(font0) 560 font2.height = 0x00A0 561 align0 = Alignment() 562 align1 = copy.copy(align0) 563 align1.vert = align1.VERT_TOP 564 align2 = copy.copy(align1) 565 align2.wrap = align2.WRAP_AT_RIGHT 566 567 style0 = XFStyle() 568 style0.font = font0 569 style0.alignment = align1 570 style0.num_format_str = 'general' 571 style_colheader = copy.copy(style0) 572 style_colheader.num_format_str = '@' 573 style_colheader.font = font1 574 style_num = copy.copy(style0) 575 style_str = copy.copy(style0) 576 style_str.num_format_str = '@' 577 style_wrap_str = copy.copy(style0) 578 style_wrap_str.alignment = align2 579 style_wrap_str.font = font2 580 style_date = copy.copy(style0) 581 style_date.num_format_str = 'yyyy/mm/dd' 582 583 for col, cx in map(lambda x, y: [x, y], cols, range(len(cols))): 584 name = str(col[0]).replace('_','') 585 ws.write(ro-1, cx, name.decode('utf-8'), style_colheader) 586 conv = lambda x: str(x).replace('\r', '') \ 587 .rstrip('\r\n') \ 588 .decode('utf-8') 589 style = style_str 590 if name in ['time', 'date','changetime', 'created', 'modified']: 591 ws.col(cx).width = 0xb00 592 from datetime import datetime 593 conv = lambda x: datetime.fromtimestamp(float(x)) 594 style = style_date 595 elif name in ['summary', 'description']: 596 if name == 'description': 597 ws.col(cx).width = 0x7000 598 else: 599 ws.col(cx).width = 0x1a00 600 style = style_wrap_str 601 elif name in ['color', 'ticket', 'id']: 602 if name in ['color']: 603 ws.col(cx).hidden = 1 604 conv = lambda x: int(x) 605 style = style_num 606 elif name in ['style']: 607 ws.col(cx).hidden = 1 608 for value, rx in map(lambda x, y: [conv(x[cx]), ro + y], \ 609 rows, range(len(rows))): 610 ws.write(rx, cx, value, style) 611 req.write(wb.get()) 612 488 613 # IWikiSyntaxProvider methods 489 614 490 615 def get_link_resolvers(self):
