source: timingandestimationplugin/branches/trac0.11/timingandestimationplugin/tande_filters.py

Last change on this file was 7011, checked in by Russ Tyndall, 14 years ago

fixed #6076 - Changed the way I was filtering TandE report rows, so that it would work with newer genshis and newer tracs

File size: 6.2 KB
RevLine 
[6591]1import re
[7000]2import dbhelper
[6591]3from trac import util
[2538]4from trac.web.api import ITemplateStreamFilter
5from trac.core import *
6from genshi.core import *
7from genshi.builder import tag
8from genshi.filters.transform import Transformer
9
[6269]10import sys 
11if sys.version_info < (2, 4, 0): 
12    from sets import Set as set
13
[7011]14def split_stream(stream):
15    """splits the stream based on toplevel START / END tags"""
16    cl = []
17    res = []
18    num_start=0
19    for kind, data, pos in stream:
20        cl.append((kind, data, pos))
21        if kind == Stream.START:
22            num_start = num_start+1
23        elif kind == Stream.END:
24            num_start = num_start-1
25            if num_start == 0:
26                res.append(Stream(cl))
27                cl=[]
28    if cl != []:
29        res.append(Stream(cl))
30    return res
31
32
[2538]33class RowFilter(object):
34    """A genshi filter that operates on table rows, completely hiding any that
35    are in the billing_reports table."""
36
[2948]37    def __init__(self, comp):
38        self.component = comp
[7000]39        rows = dbhelper.get_all(comp, "SELECT id FROM custom_report")[1]
40        if rows:
41            self.billing_reports = set([x[0] for x in rows])
42        else:
[2538]43            self.billing_reports = set()
[2948]44        self.component.log.debug('self.billing_reports= %r' % self.billing_reports)
[2538]45
46    def __call__(self, row_stream):
[7011]47        #stream = Stream(list(row_stream))
48        def tryInt(v):
49            try:
50                return int(v)
51            except:
52                return None
53        streams = split_stream(row_stream)
54        #report_urls = [tryInt(i.get('href').split('/')[-1]) for i in stream.select('td[@class="report"]/a/@href')]
55        #self.component.log.debug("ReportRowFilter: #%s#,  %r" % (len(streams), list(report_urls)))
56        for stream in streams:
57            show_row = True
58            try:
59                report_url = stream.select('td[@class="report"]/a/@href').render()
60                id = tryInt(report_url.split('/')[-1])
61                self.component.log.debug("Report row filter: about to filter: %s not in %s : %s" % (id, self.billing_reports,  not id in self.billing_reports) )
62                show_row = not id in self.billing_reports
63            except Exception, e:
64                self.component.log.exception("Report row filter failed")
65                show_row = True #Dont Hide Error Rows?
66            if show_row:
67                for kind,data,pos in stream:
[6826]68                    yield kind,data,pos
[2538]69
70# This can go away once they fix http://genshi.edgewall.org/ticket/136
71# At that point we should use Transformer.filter
72class FilterTransformation(object):
73    """Apply a normal stream filter to the selection. The filter is called once
74    for each contiguous block of marked events."""
75
76    def __init__(self, filter):
77        """Create the transform.
78
79        :param filter: The stream filter to apply.
80        """
81        self.filter = filter
82
83    def __call__(self, stream):
84        """Apply the transform filter to the marked stream.
85
86        :param stream: The marked event stream to filter
87        """
88        def flush(queue):
89            if queue:
90                for event in self.filter(queue):
91                    yield event
92                del queue[:]
93
94        queue = []
95        for mark, event in stream:
96            if mark:
97                queue.append(event)
98            else:
99                for e in flush(queue):
100                    yield None,e
101                yield None,event
102        for event in flush(queue):
103            yield None,event
104
105class ReportsFilter(Component):
106    """Remove all billing reports from the reports list."""
107    implements(ITemplateStreamFilter)
108
109    def match_stream(self, req, method, filename, stream, data):
110        return filename == 'report_view.html'
111
112    def filter_stream(self, req, method, filename, stream, data):
113        return stream | Transformer(
114            '//table[@class="listing reports"]/tbody/tr'
[2948]115            ).apply(FilterTransformation(RowFilter(self)))
[2538]116
[3960]117
118#@staticmethod
119def disable_field(field_stream):
120    value = Stream(field_stream).select('@value').render()
121   
122    for kind,data,pos in tag.span(value, id="field-totalhours").generate():
123        yield kind,data,pos
124
[2538]125class TotalHoursFilter(Component):
126    """Disable editing of the Total Hours field so that we don't need Javascript."""
127    implements(ITemplateStreamFilter)
128
129    def match_stream(self, req, method, filename, stream, data):
130        self.log.debug("matching: ticket.html")
131        return filename == 'ticket.html'
132
133    def filter_stream(self, req, method, filename, stream, data):
134        return stream | Transformer(
135            '//input[@id="field-totalhours" and @type="text" and @name="field_totalhours"]'
[3960]136            ).apply(FilterTransformation(disable_field))
[2538]137
138
139
140
[3960]141
[6591]142class TimeClickFilter(Component):
143    """Add a javascript onclick button to add the time since the change into the add hours box """
144    implements(ITemplateStreamFilter)
145   
146    def match_stream(self, req, method, filename, stream, data):
147        self.log.debug("matching: ticket.html")
148        return filename == 'ticket.html'
149
150    def filter_stream(self, req, method, filename, stream, data):
151        if not self.env.config.getbool('timingandestimationplugin','show_add_time_buttons'):
152            return stream
153        def add_time_click(field_stream):
154            time = Stream(field_stream).select('@title').render()
155            time = time.split(" ")[0] # get the time out of the title
156            #render the guts of the h3 without changes
157            for kind,data,pos in field_stream:
158                yield kind,data,pos
159            #create the button tag that to add hours
160            btn = tag.input(None, type='submit', title="add time elapsed since this comment", value="Add Time", time=time, onclick="onClickOfADateElement(this.getAttribute('time'));return false;")
161            #create a div with the class that all the other buttons have
162            new_stream = tag.div(btn, **{"class":"inlinebuttons"})
163            #output new div/button
164            for kind,data,pos in new_stream:
165                yield kind,data,pos                   
166
167        return stream | Transformer(
168            # we want the text and the nodes so that we can insert at the end
169            '//h3[@class="change"]/*|//h3[@class="change"]/text()'
170            ).apply(FilterTransformation(add_time_click))
171
172
173
174
175
Note: See TracBrowser for help on using the repository browser.