source: simplemultiprojectplugin/trunk/simplemultiproject/timeline.py @ 14000

Last change on this file since 14000 was 14000, checked in by falkb, 10 years ago

fixed #11854: attachments added to wiki pages are not shown with this plugin enabled (patch of Hauke Münting, thank you very much!)

File size: 5.9 KB
Line 
1# -*- coding: utf-8 -*-
2#
3# Copyright (C) 2012 Thomas Doering, falkb
4#
5
6from genshi.builder import tag
7from genshi.filters.transform import Transformer
8from trac.ticket.model import Ticket
9from simplemultiproject.model import *
10from trac.util.text import to_unicode
11from trac.core import *
12from trac.web.api import IRequestFilter, ITemplateStreamFilter
13from operator import itemgetter
14from simplemultiproject.model import smp_filter_settings
15
16class SmpTimelineProjectFilter(Component):
17    """Allows for filtering by 'Project'
18    """
19    _old_render_fn = []
20    _current_project = []
21    _read_idx = -1
22   
23    implements(IRequestFilter, ITemplateStreamFilter)
24   
25    def __init__(self):
26        self.__SmpModel = SmpModel(self.env)
27
28    # IRequestFilter methods
29
30    def pre_process_request(self, req, handler):
31        return handler
32       
33    def post_process_request(self, req, template, data, content_type):
34        if template == 'timeline.html':
35            filter_off = False
36            displayed_projects = self._filtered_projects(req)
37            if not displayed_projects: #no filter means likely more than 1 project, so we insert the project name
38                filter_off = True
39                displayed_projects = [project[1] for project in self.__SmpModel.get_all_projects()]
40
41            if displayed_projects:
42                filtered_events = []
43                tickettypes = ("newticket", "editedticket", "closedticket", "attachment", "reopenedticket")
44                self._old_render_fn = []
45                self._current_project = []
46                self._read_idx = -1
47                for event in data['events']:
48                    if event['kind'] in tickettypes:
49                        resource = event['kind'] == "attachment" and event['data'][0].parent or event['data'][0]
50                        if resource.realm == "ticket":
51                            ticket = Ticket( self.env, resource.id )   
52                            project = ticket.get_value_or_default('project')
53                            if not project:
54                                if filter_off: #display all tickets without a set project
55                                    filtered_events.append(event)
56                            elif project in displayed_projects:
57                                if len(displayed_projects) > 1: #only if more than 1 filtered project
58                                    #store the old render function and the project to be inserted
59                                    self._old_render_fn.append(event['render'])
60                                    self._current_project.append(project)
61                                    #redirect to our new render function (which will insert the project name)
62                                    event['render'] = self._render_ticket_event
63                                #add to the list of displayed events
64                                filtered_events.append(event)
65                        elif resource.realm == "wiki":
66                            filtered_events.append(event)
67                    else:
68                        filtered_events.append(event)
69   
70                data['events'] = filtered_events
71
72        return template, data, content_type
73
74    # ITemplateStreamFilter methods
75
76    def filter_stream(self, req, method, filename, stream, data):
77        if filename == 'timeline.html':
78            filter_projects = self._filtered_projects(req) 
79
80            filter = Transformer('//form[@id="prefs"]/div[1]')
81            stream = stream | filter.before(tag.label("Filter Projects:")) | filter.before(tag.br()) | filter.before(self._projects_field_input(req, filter_projects)) | filter.before(tag.br()) | filter.before(tag.br())
82
83        return stream
84
85    # Internal
86    def _render_ticket_event(self, field, context):
87        if (field == 'url'):
88            self._read_idx += 1 #next index now
89
90        if self._read_idx < len(self._old_render_fn):
91            #call the original render function
92            output = self._old_render_fn[self._read_idx](field, context)
93   
94            if field == 'title': #now it's time to insert the project name
95                #split the whole string until we can insert
96                splitted_output = to_unicode(output).split("</em>")
97                tooltip = splitted_output[0].split('\"')
98                ticket_no = splitted_output[0].split('>')
99                if len(tooltip) == 3: #it's a ticket
100                    #now rebuild the puzzle by inserting the name
101                    output = tag('Ticket' + ' ', tag.em(ticket_no[1], title=tooltip[1]), ' ', tag.span(self._current_project[self._read_idx], style="background-color: #ffffd0;"), splitted_output[1])
102                elif len(tooltip) == 1 and len(splitted_output) == 3: #it's an attachment
103                    output += tag(' ', tag.span(self._current_project[self._read_idx], style="background-color: #ffffd0;"))
104            return output
105
106    def _projects_field_input(self, req, selectedcomps):
107        cursor = self.__SmpModel.get_all_projects_filtered_by_conditions(req)
108
109        sorted_project_names_list = sorted(cursor, key=itemgetter(1))
110        number_displayed_entries = len(sorted_project_names_list)+1     # +1 for special entry 'All'
111        if number_displayed_entries > 15:
112            number_displayed_entries = 15
113
114        select = tag.select(name="filter-projects", id="filter-projects", multiple="multiple", size=("%s" % number_displayed_entries), style="overflow:auto;")
115        select.append(tag.option("All", value="All"))
116       
117        for component in sorted_project_names_list:
118            project = to_unicode(component[1])
119            if selectedcomps and project in selectedcomps:
120                select.append(tag.option(project, value=project, selected="selected"))
121            else:
122                select.append(tag.option(project, value=project))
123        return select
124       
125    def _filtered_projects(self, req):
126        filtered_projects = smp_filter_settings(req, 'timeline', 'projects')
127
128        return filtered_projects
Note: See TracBrowser for help on using the repository browser.