Example #1
0
 def fn(stream):
     for kind, data, pos in stream:
         if kind is END and data.localname == 'body':
             first_time = req._tracdeveloper_hdlr.buf \
                          and req._tracdeveloper_hdlr.buf[0].created
             
             elm = tag.div(tag.table(tag.thead(tag.tr(
                 tag.th('Time'),
                 tag.th('Module'),
                 tag.th('Level'),
                 tag.th('Message'),
             )), class_='listing')([
                 tag.tr(
                     tag.td(int((r.created - first_time) * 1000)),
                     tag.td(r.module),
                     tag.td(r.levelname),
                     tag.td(r.getMessage()),
                     class_=(i%2 and 'even' or 'odd'),
                 )
                 for i, r in enumerate(req._tracdeveloper_hdlr.buf)
             ]), id='tracdeveloper-log')
             for evt in elm.generate():
                 yield evt
             del elm
             req._tracdeveloper_hdlr.formatter = None
             del req._tracdeveloper_hdlr.buf[:]
             self.log.removeHandler(req._tracdeveloper_hdlr)
             del req._tracdeveloper_hdlr
         yield kind, data, pos
Example #2
0
 def render(self, context, mimetype, content, filename=None, url=None):
     content = content.read()
     content = re.split('\r[\n]', content) 
     if not content:
         return None
     head = content[0]
     if not head:
         return None
     head = re.split(',', head)
     
     if not head:
         return None
     thead = tag.thead(tag.tr([tag.th(h) for h in head]))
     content = content[1:]
     if not content:
         return None
     tbody = []
     for r in content:
         if r:
             r = re.split(',', r)
             if r:
                 tbody.append(tag.tr([tag.td(c) for c in r ]))
     
     return tag.table(thead,tag.tbody(tbody), 
         class_="wiki")
Example #3
0
    def expand_macro(self, formatter, name, content):
        from trac.mimeview.api import Mimeview
        mime_map = Mimeview(self.env).mime_map
        mime_type_filter = ''
        args, kw = parse_args(content)
        if args:
            mime_type_filter = args.pop(0).strip().rstrip('*')

        mime_types = {}
        for key, mime_type in mime_map.iteritems():
            if (not mime_type_filter or
                mime_type.startswith(mime_type_filter)) and key != mime_type:
                mime_types.setdefault(mime_type, []).append(key)

        return tag.div(class_='mimetypes')(
            tag.table(class_='wiki')(
                tag.thead(tag.tr(
                    tag.th(_("MIME Types")),  # always use plural
                    tag.th(tag.a("WikiProcessors",
                                 href=formatter.context.href.wiki(
                                     'WikiProcessors'))))),
                tag.tbody(
                    tag.tr(tag.th(tag.tt(mime_type),
                                  style="text-align: left"),
                           tag.td(tag.code(
                               ' '.join(sorted(mime_types[mime_type])))))
                    for mime_type in sorted(mime_types.keys()))))
Example #4
0
        def fn(stream):
            for kind, data, pos in stream:
                if kind is END and data.localname == 'body':
                    first_time = req._tracdeveloper_hdlr.buf \
                                 and req._tracdeveloper_hdlr.buf[0].created

                    elm = tag.div(tag.table(
                        tag.thead(
                            tag.tr(
                                tag.th('Time'),
                                tag.th('Module'),
                                tag.th('Level'),
                                tag.th('Message'),
                            )),
                        class_='listing')([
                            tag.tr(
                                tag.td(int((r.created - first_time) * 1000)),
                                tag.td(r.module),
                                tag.td(r.levelname),
                                tag.td(r.getMessage()),
                                class_=(i % 2 and 'even' or 'odd'),
                            )
                            for i, r in enumerate(req._tracdeveloper_hdlr.buf)
                        ]),
                                  id='tracdeveloper-log')
                    for evt in elm.generate():
                        yield evt
                    del elm
                    req._tracdeveloper_hdlr.formatter = None
                    del req._tracdeveloper_hdlr.buf[:]
                    self.log.removeHandler(req._tracdeveloper_hdlr)
                    del req._tracdeveloper_hdlr
                yield kind, data, pos
Example #5
0
    def expand_macro(self, formatter, name, content):
        from trac.mimeview.api import Mimeview
        mime_map = Mimeview(self.env).mime_map
        mime_type_filter = ''
        args, kw = parse_args(content)
        if args:
            mime_type_filter = args.pop(0).strip().rstrip('*')

        mime_types = {}
        for key, mime_type in mime_map.iteritems():
            if (not mime_type_filter or
                mime_type.startswith(mime_type_filter)) and key != mime_type:
                mime_types.setdefault(mime_type, []).append(key)

        return tag.div(class_='mimetypes')(
            tag.table(class_='wiki')(
                tag.thead(tag.tr(
                    tag.th(_("MIME Types")),  # always use plural
                    tag.th(tag.a("WikiProcessors",
                                 href=formatter.context.href.wiki(
                                     'WikiProcessors'))))),
                tag.tbody(
                    tag.tr(tag.th(tag.code(mime_type),
                                  style="text-align: left"),
                           tag.td(tag.code(
                               ' '.join(sorted(mime_types[mime_type])))))
                    for mime_type in sorted(mime_types.keys()))))
Example #6
0
    def _render_source(self, context, stream, annotations):
        from trac.web.chrome import add_warning
        annotators, labels, titles = {}, {}, {}
        for annotator in self.annotators:
            atype, alabel, atitle = annotator.get_annotation_type()
            if atype in annotations:
                labels[atype] = alabel
                titles[atype] = atitle
                annotators[atype] = annotator
        annotations = [a for a in annotations if a in annotators]

        if isinstance(stream, list):
            stream = HTMLParser(StringIO(u'\n'.join(stream)))
        elif isinstance(stream, unicode):
            text = stream

            def linesplitter():
                for line in text.splitlines(True):
                    yield TEXT, line, (None, -1, -1)

            stream = linesplitter()

        annotator_datas = []
        for a in annotations:
            annotator = annotators[a]
            try:
                data = (annotator, annotator.get_annotation_data(context))
            except TracError as e:
                self.log.warning("Can't use annotator '%s': %s", a, e.message)
                add_warning(
                    context.req,
                    tag.strong(
                        tag_("Can't use %(annotator)s annotator: %(error)s",
                             annotator=tag.em(a),
                             error=tag.pre(e.message))))
                data = (None, None)
            annotator_datas.append(data)

        def _head_row():
            return tag.tr([
                tag.th(labels[a], class_=a, title=titles[a])
                for a in annotations
            ] + [tag.th(u'\xa0', class_='content')])

        def _body_rows():
            for idx, line in enumerate(_group_lines(stream)):
                row = tag.tr()
                for annotator, data in annotator_datas:
                    if annotator:
                        annotator.annotate_row(context, row, idx + 1, line,
                                               data)
                    else:
                        row.append(tag.td())
                row.append(tag.td(line))
                yield row

        return tag.table(class_='code')(tag.thead(_head_row()),
                                        tag.tbody(_body_rows()))
        def table_header(self):
		# use genshi to build header row, also use th for table headings
		# (note, we don't start the table here, as all genshi objects have to be self-contained)
		return tag.thead(tag.tr(tag.th('Ticket'),
			      tag.th('Summary'),
			      tag.th('Modified'),
			      tag.th('Owner'),
			      tag.th('Component'),
			      tag.th('Status')))
    def expand_macro(self, formatter, name, args):
        if not args:
            return Markup()

        config = None
        if name == self.CONFIG_KEY:
            lines = args.splitlines()
            if not lines or not lines[0].startswith('#!'):
                return Markup()
            config = self._parse_config([i.strip() for i in lines[0][2:].split(',')])
        else:
            config = self.CONFIG[name]

        if not config:
            return Markup()

        def to_html(text):
            if not text:
                return ''
            return Markup('<br>'.join([format_to_oneliner(self.env, formatter.context, line) \
                                for line in text.splitlines()]))

        def has_keys(dict, keys):
            for key in keys:
                if dict.has_key(key):
                    return True
            return False

        rows = self.parse_doc(args)
        if not rows:
            return Markup()

        seen = []
        for desc, keys in config:
            if [row for row in rows if has_keys(row, keys)]:
                seen.append(desc)

        thead = tag.thead()
        for desc, keys in config:
            if not desc in seen:
                continue
            thead(tag.td(tag.b(desc)))

        tbody = tag.tbody()
        for row in rows:
            trow = tag.tr()
            for desc, keys in config:
                if not desc in seen:
                    continue
                tcol = tag.td()
                for key in keys:
                    if row.has_key(key):
                        tcol(to_html(row[key]))
                trow(tcol)
            tbody(trow)

        return tag.table([thead, tbody], class_='wiki')
Example #9
0
File: api.py Project: pkdevbox/trac
    def _render_source(self, context, stream, annotations):
        from trac.web.chrome import add_warning

        annotators, labels, titles = {}, {}, {}
        for annotator in self.annotators:
            atype, alabel, atitle = annotator.get_annotation_type()
            if atype in annotations:
                labels[atype] = alabel
                titles[atype] = atitle
                annotators[atype] = annotator
        annotations = [a for a in annotations if a in annotators]

        if isinstance(stream, list):
            stream = HTMLParser(StringIO(u"\n".join(stream)))
        elif isinstance(stream, unicode):
            text = stream

            def linesplitter():
                for line in text.splitlines(True):
                    yield TEXT, line, (None, -1, -1)

            stream = linesplitter()

        annotator_datas = []
        for a in annotations:
            annotator = annotators[a]
            try:
                data = (annotator, annotator.get_annotation_data(context))
            except TracError as e:
                self.log.warning("Can't use annotator '%s': %s", a, e)
                add_warning(
                    context.req,
                    tag.strong(
                        tag_("Can't use %(annotator)s annotator: %(error)s", annotator=tag.em(a), error=tag.pre(e))
                    ),
                )
                data = None, None
            annotator_datas.append(data)

        def _head_row():
            return tag.tr(
                [tag.th(labels[a], class_=a, title=titles[a]) for a in annotations]
                + [tag.th(u"\xa0", class_="content")]
            )

        def _body_rows():
            for idx, line in enumerate(_group_lines(stream)):
                row = tag.tr()
                for annotator, data in annotator_datas:
                    if annotator:
                        annotator.annotate_row(context, row, idx + 1, line, data)
                    else:
                        row.append(tag.td())
                row.append(tag.td(line))
                yield row

        return tag.table(class_="code")(tag.thead(_head_row()), tag.tbody(_body_rows()))
Example #10
0
def render_refs_box(self, req, ids, order = 'year', desc = 1, headhref=False,
    path=[],args=[],page=None,max=None ):
    # Check parameters
    if not ids:
        return []     
    
    columns = self.env.config.get('zotero', 'columns','firstCreator, year, publicationTitle, title' )
    columns = columns.split(',')
    columns = [c.strip() for c in columns]
   
    model = ZoteroModelProvider(self.env)
    if page:
        page = (page-1)*max
    data = model.get_item_columns_by_iids(ids,columns, order, desc = desc, offset=page,limit=max)
    
    apath = args_path(args)
    
    heads = []
    for idx, column in enumerate(columns):
        label = column
        if zotero_fields_mapping_name.has_key(column):
            label = zotero_fields_mapping_name[column]['label']
        if headhref and path:
            head = []
            th_class = ''
            th_href = req.href(path, order=column)+apath
            if order == column:
                if desc:
                    th_class = 'desc'
                else:
                    th_class = 'asc'
                    th_href = req.href(path, order=column, desc = str(1))+apath
            head = tag.th(tag.a(label, href = th_href),class_= th_class)
            heads.append(head)
        else:
            heads.append(tag.th(label))
    body = []
    for idx, item in enumerate(data):
        item_class = 'even'
        if idx % 2 == 1:
            item_class = 'odd'
        item_td = []
        for idx, col in enumerate(columns):
            col_td = []
            if not col or item[idx+1] == 'None':
                col_td = tag.td()
            elif col == 'title':
                col_td = tag.td(tag.a(item[idx+1], 
                    href = req.href.zotero('item',str(item[0]))))
            else:   
                col_td = tag.td(item[idx+1])
            item_td.append(col_td)
        item_tr = tag.tr( item_td,class_=item_class)
        body.append(item_tr)
    return tag.table( tag.thead( heads ), tag.tbody(body),
        class_="listing dirlist", id="dirlist")
Example #11
0
  def expand_macro(self, formatter, name, content, args):

    title = 'Color Scheme'
    classes = 'colormacro' 

    if args and 'title' in args:
      title = args['title']

    if args and 'class' in args:
      classes  += ' ' + args['class']


    tbody = []
    have_comment = False
    colors = self._parse_arguments(content)

    for color in colors:
      if len(color['title']) > 0:
        have_comment = True
      ## Create row
      tbody.append(
        [
          tag.td()(tag.strong(color['title'])),
          tag.td(
              style='background-color:' + color['orig']
            )(
              tag.div(style='color: black')(color['hex']),
              tag.div(style='color: white')(color['hex'])
          ),
          tag.td(
              style='background-color:' + color['orig']
            )(
              tag.div(style='color: black')(color['rgbp']),
              tag.div(style='color: white')(color['rgbp'])
          ),
        ]
      )
      ## end for loop

    if len(tbody) > 0:
      colcount = len(tbody[0])
      if not have_comment:
        colcount -= 1
      
      table = tag.table(class_=classes)
      table()(tag.thead()(tag.th(colspan='%d' % colcount)(title)))
      ## Attach row in table.
      if have_comment:
        table()(tag.tbody(class_='colorlist')([tag.tr(row) for row in tbody]))
      else:
        table()(tag.tbody(class_='colorlist')([tag.tr(row[1:]) for row in tbody]))

      return table;
    else:
      return tag.div(class_='colormacro')('Nothing to display')
Example #12
0
  def expand_macro(self, formatter, name, content, args):
    title = 'Color Gradient'
    classes = 'colorgradient';

    if args and 'title' in args:
      title = args['title']

    if args and 'class' in args:
      classes  += ' ' + args['class']

    colors = self._parse_arguments(content)

    lastcolor = {}
    tbody = []

    for color in colors:
      if 'orig' in lastcolor:
        tbody.append(self._create_gradient(lastcolor, color))
        
      tbody.append([
        tag.td(
          style='background-color:' + color['orig']
        )(
          tag.div(style='color: black')(color['hex']),
          tag.div(style='color: white')(color['hex'])
        ),
        tag.td(
          style='background-color:' + color['orig']
        )(
          tag.div(style='color: black')(color['rgbp']),
          tag.div(style='color: white')(color['rgbp'])
        )
      ])

      lastcolor = color

    ## end for loop

    if len(tbody) > 0:
      
      table = tag.table(class_=classes)
      table()(tag.thead()(tag.th(colspan="2")(title)))
     
      table()(tag.tbody(class_='colorgradient')([tag.tr()(td) for td in tbody]))

      return table;
    else:
      return tag.div(class_='colorgradient')('Nothing to display')
Example #13
0
    def expand_macro(self, formatter, name, content):
        content = content.strip() if content else ''
        name_filter = content.strip('*')
        items = {}
        for subscriber in NotificationSystem(self.env).subscribers:
            name = subscriber.__class__.__name__
            if not name_filter or name.startswith(name_filter):
                items[name] = subscriber.description()

        return tag.div(class_='trac-subscriberlist')(tag.table(class_='wiki')(
            tag.thead(tag.tr(tag.th(_("Subscriber")),
                             tag.th(_("Description")))),
            tag.tbody(
                tag.tr(tag.td(tag.code(name)),
                       tag.td(items[name]),
                       class_='odd' if idx % 2 else 'even')
                for idx, name in enumerate(sorted(items.keys())))))
    def expand_macro(self, formatter, name, content):

        if self.ACCESS_KEY is None:
            return tag.p("[EC2 access key is missing from trac.ini]")
        
        if self.SECRET_KEY is None:
            return tag.p("[EC2 secret key is missing from trac.ini]")

        ec2 = EC2Connection(self.ACCESS_KEY, self.SECRET_KEY)

        headings = ("Instance", "AMI", "Key", "IP", "State", "Monitored")
        table = tag.table(tag.thead(tag.tr([tag.th(title) for title in headings])), class_="listing")
        tbody = tag.tbody()

        try:
            instance_data = ec2.get_all_instances()
        except UnicodeDecodeError, e:
            self.log.exception("Failed to ec2.get_all_instances() for AWSInstanceTableMacro")
            return tag.div("AWSInstanceTable macro failed.")
Example #15
0
    def _add_custom_field_tables(self, stream, ticket):
        ticket_body = Transformer('//div[@id="ticket"]')

        for table_info in self._get_table_fields(ticket):
            headers = table_info["headers"]
            columns = table_info["columns"]
            tickets = table_info["tickets"]

            table = tag.div(
                tag.h3(table_info["title"]),
                tag.table(
                    tag.thead(self._get_header(headers)),
                    tag.tbody(self._get_body(tickets, columns)),
                    class_="listing tickets",
                ),
            )
            stream = stream | ticket_body.after(table)

        return stream
Example #16
0
    def expand_macro(self, formatter, name, content):
        content = content.strip() if content else ''
        name_filter = content.strip('*')
        items = {}
        for subscriber in NotificationSystem(self.env).subscribers:
            name = subscriber.__class__.__name__
            if not name_filter or name.startswith(name_filter):
                items[name] = subscriber.description()

        return tag.div(class_='trac-subscriberlist')(
            tag.table(class_='wiki')(
                tag.thead(tag.tr(
                    tag.th(_("Subscriber")),
                    tag.th(_("Description")))),
                tag.tbody(
                    tag.tr(tag.td(tag.code(name)),
                           tag.td(items[name]),
                           class_='odd' if idx % 2 else 'even')
                    for idx, name in enumerate(sorted(items.keys())))))
Example #17
0
    def expand_macro(self, formatter, name, content):
        evs = EarnValueSystem(self.env)
        kwargs = self._parse_arg(content)
        users = evs.get_users(formatter.req, kwargs.get('users', 'authenticated'))
        format = kwargs.get('format', 'table')
        start_time = self._parse_date(kwargs.get('start'), 0)
        end_time = self._parse_date(kwargs.get('end'), None)

        if format == 'plain':
            ev = dict([(u, evs.get_user_ev(u, start_time, end_time)) for u in users])
            tags = []
            for k, v in ev.items():
                tags.append(tag.span(k + ': ' + str(v)))
                tags.append(tag.br)
            return tag.p(*tags)

        elif format == 'table':
            evc = evs.get_users_ev_detail(users, start_time, end_time)
            rows = [tag.tr(
                tag.td(ev['action_name']),
                tag.td(ev['value']),
                tag.td(ev['fullname']),
                tag.td(ev['time']),
                tag.td(ev['summary'])
            ) for evcs in evc.values() for ev in evcs ]
            return tag.div(
                tag.table(tag.thead(
                    tag.tr(
                        tag.th('Action'),
                        tag.th('Value'),
                        tag.th('User'),
                        tag.th('Date'),
                        tag.th('Summary'), class_='trac-columns')
                ),
                tag.tbody(
                    *rows
                ), class_='listing tickets')
            )

        return None
    def _contruct_tickets_table(self, req, ticket, childtickets, priorities):
        # trac.ini : Which columns to display in child ticket listing?
        columns = self.config.getlist('childtickets', 'parent.%s.table_headers' % ticket['type'], default=['summary','owner'])

        tablediv = tag.div()
        tablediv.append(tag.label(tag.input(type="checkbox", id="cb_show_closed"),
                                  "show closed tickets"))

        for tkt_types, type_tickets in groupby(childtickets, lambda t: t['type']):
            tablediv.append(tag.h2("Type: %s" % tkt_types, class_="report-result"))
            tablediv.append(
                    tag.table(
                        tag.thead(
                            tag.tr(
                                tag.th("Ticket",class_="id"),
                                [ tag.th(s.title(),class_=s) for s in columns ])
                            ),
                        tag.tbody([ self._table_row(req,tkt,columns,priorities) for tkt in type_tickets]),
                        class_="listing tickets",
                        )
                    )

        return tablediv
Example #19
0
    def render(self, context, mimetype, content, filename=None, url=None):
        content = content.read()
        content = re.split('\r[\n]', content)
        if not content:
            return None
        head = content[0]
        if not head:
            return None
        head = re.split(',', head)

        if not head:
            return None
        thead = tag.thead(tag.tr([tag.th(h) for h in head]))
        content = content[1:]
        if not content:
            return None
        tbody = []
        for r in content:
            if r:
                r = re.split(',', r)
                if r:
                    tbody.append(tag.tr([tag.td(c) for c in r]))

        return tag.table(thead, tag.tbody(tbody), class_="wiki")
    def expand_macro(self, formatter, name, arguments):

        self.ref = formatter
        self.tz_info = formatter.req.tz
        self.thistime = datetime.datetime.now(self.tz_info)

        # Parse arguments from macro invocation
        args, kwargs = parse_args(arguments, strict=False)

        # Find out whether use http param, current or macro param year/month
        http_param_year = formatter.req.args.get('year','')
        http_param_month = formatter.req.args.get('month','')

        if http_param_year == "":
            # not clicked on a prev or next button
            if len(args) >= 1 and args[0] <> "*":
                # year given in macro parameters
                year = int(args[0])
            else:
                # use current year
                year = self.thistime.year
        else:
            # year in http params (clicked by user) overrides everything
            year = int(http_param_year)

        if http_param_month == "":
            # not clicked on a prev or next button
            if len(args) >= 2 and args[1] <> "*":
                # month given in macro parameters
                month = int(args[1])
            else:
                # use current month
                month = self.thistime.month
        else:
            # month in http params (clicked by user) overrides everything
            month = int(http_param_month)

        showbuttons = True
        if len(args) >= 3 or kwargs.has_key('nav'):
            try:
                showbuttons = kwargs['nav'] in ["True", "true", "yes", "1"]
            except KeyError:
                showbuttons = args[2] in ["True", "true", "yes", "1"]

        wiki_page_format = "%Y-%m-%d"
        if len(args) >= 4 and args[3] != "*" or kwargs.has_key('wiki'):
            try:
                wiki_page_format = str(kwargs['wiki'])
            except KeyError:
                wiki_page_format = str(args[3])

        show_t_open_dates = True
        if len(args) >= 5 or kwargs.has_key('cdate'):
            try:
                show_t_open_dates = kwargs['cdate'] in \
                                               ["True", "true", "yes", "1"]
            except KeyError:
                show_t_open_dates = args[4] in ["True", "true", "yes", "1"]

        # template name tried to create new pages
        # optional, default (empty page) is used, if name is invalid
        wiki_page_template = ""
        if len(args) >= 6 or kwargs.has_key('base'):
            try:
                wiki_page_template = kwargs['base']
            except KeyError:
                wiki_page_template = args[5]

        # TracQuery support for ticket selection
        query_args = "id!=0"
        if len(args) >= 7 or kwargs.has_key('query'):
            # prefer query arguments provided by kwargs
            try:
                query_args = kwargs['query']
            except KeyError:
                query_args = args[6]
        self.tickets = self._ticket_query(formatter, query_args)

        # compress long ticket lists
        list_condense = 0
        if len(args) >= 8 or kwargs.has_key('short'):
            # prefer query arguments provided by kwargs
            try:
                list_condense = int(kwargs['short'])
            except KeyError:
                list_condense = int(args[7])

        # control calendar display width
        cal_width = "100%;"
        if len(args) >= 9 or kwargs.has_key('width'):
            # prefer query arguments provided by kwargs
            try:
                cal_width = kwargs['width']
            except KeyError:
                cal_width = args[8]


        # Can use this to change the day the week starts on,
        # but this is a system-wide setting.
        calendar.setfirstweekday(calendar.MONDAY)
        cal = calendar.monthcalendar(year, month)

        curr_day = None
        if year == self.thistime.year and month == self.thistime.month:
            curr_day = self.thistime.day

        # Compile regex pattern before use for better performance
        pattern_del  = '(?:<span .*?>)|(?:</span>)'
        pattern_del += '|(?:<p>)|(?:<p .*?>)|(?:</p>)'
        pattern_del += '|(?:</table>)|(?:<td.*?\n)|(?:<tr.*?</tr>)'
        self.end_RE  = re.compile('(?:</a>)')
        self.del_RE  = re.compile(pattern_del)
        self.item_RE = re.compile('(?:<img .*?>)')
        self.open_RE = re.compile('(?:<a .*?>)')
        self.tab_RE  = re.compile('(?:<table .*?>)')

        # for prev/next navigation links
        prevMonth = month - 1
        nextMonth = month + 1
        nextYear = prevYear = year
        # check for year change (KISS version)
        if prevMonth == 0:
            prevMonth = 12
            prevYear -= 1
        if nextMonth == 13:
            nextMonth = 1
            nextYear += 1

        # for fast-forward/-rewind navigation links
        ffYear = frYear = year
        if month < 4:
            frMonth = month + 9
            frYear -= 1
        else:
            frMonth = month - 3
        if month > 9:
            ffMonth = month - 9
            ffYear += 1
        else:
            ffMonth = month + 3


        # Finally building the output
        # Prepending inline CSS definitions
        styles = """ \
<!--
table.wikiTicketCalendar th { font-weight: bold; }
table.wikiTicketCalendar th.workday { width: 17%; }
table.wikiTicketCalendar th.weekend { width: 7%; }
table.wikiTicketCalendar caption {
    font-size: 120%; white-space: nowrap;
    }
table.wikiTicketCalendar caption a {
    display: inline; margin: 0; border: 0; padding: 0;
    background-color: transparent; color: #b00; text-decoration: none;
    }
table.wikiTicketCalendar caption a.prev { padding-right: 5px; font: bold; }
table.wikiTicketCalendar caption a.next { padding-left: 5px; font: bold; }
table.wikiTicketCalendar caption a:hover { background-color: #eee; }
table.wikiTicketCalendar td.today {
    background: #fbfbfb; border-color: #444444; color: #444;
    border-style: solid; border-width: 1px;
    }
table.wikiTicketCalendar td.day {
    background: #e5e5e5; border-color: #444444; color: #333;
    border-style: solid; border-width: 1px;
    }
table.wikiTicketCalendar td.fill {
    background: #eee; border-color: #ccc;
    border-style: solid; border-width: 1px;
    }
table.wikiTicketCalendar div.milestone {
    font-size: 9px; background: #f7f7f0; border: 1px solid #d7d7d7;
    border-bottom-color: #999; text-align: left;
    }
table.wikiTicketCalendar a.day {
    width: 2em; height: 100%; margin: 0; border: 0px; padding: 0;
    color: #333; text-decoration: none;
    }
table.wikiTicketCalendar a.day_haspage {
    width: 2em; height: 100%; margin: 0; border: 0px; padding: 0;
    color: #b00 !important; text-decoration: none;
    }
table.wikiTicketCalendar a.day:hover {
    border-color: #eee; background-color: #eee; color: #000;
    }
table.wikiTicketCalendar div.open, span.open   {
    font-size: 9px; color: #000000;
    }
table.wikiTicketCalendar div.closed, span.closed {
    font-size: 9px; color: #777777; text-decoration: line-through;
    }
table.wikiTicketCalendar div.opendate_open, span.opendate_open {
    font-size: 9px; color: #000077;
    }
table.wikiTicketCalendar div.opendate_closed, span.opendate_closed {
    font-size: 9px; color: #000077; text-decoration: line-through;
    }
table.wikiTicketCalendar div.condense { background-color: #e5e5e5; }
table.wikiTicketCalendar div.opendate_condense { background-color: #cdcdfa; }

/* pure CSS style tooltip */
a.tip {
    position: relative; cursor: help;
    }
a.tip span { display: none; }
a.tip:hover span {
    display: block; z-index: 1;
    font-size: 0.75em; text-decoration: none;
    /* big left move because of z-index render bug in IE<8 */
    position: absolute; top: 0.8em; left: 6em;
    border: 1px solid #000; background-color: #fff; padding: 5px;
    }
-->
"""

        # create inline style definition as Genshi fragment
        styles = tag.style(Markup(styles))
        styles(type='text/css')

        # Build caption and optional navigation links
        buff = tag.caption()

        if showbuttons is True:
            # calendar navigation buttons
            nx = 'next'
            pv = 'prev'
            nav_pvY = self._mknav('&nbsp;&lt;&lt;', pv, month, year-1)
            nav_frM = self._mknav('&nbsp;&lt;&nbsp;', pv, frMonth, frYear)
            nav_pvM = self._mknav('&nbsp;&laquo;&nbsp;', pv, prevMonth,
                                                                 prevYear)
            nav_nxM = self._mknav('&nbsp;&raquo;&nbsp;', nx, nextMonth,
                                                                 nextYear)
            nav_ffM = self._mknav('&nbsp;&gt;&nbsp;', nx, ffMonth, ffYear)
            nav_nxY = self._mknav('&nbsp;&gt;&gt;', nx, month, year+1)

            # add buttons for going to previous months and year
            buff(nav_pvY, nav_frM, nav_pvM)

        # The caption will always be there.
        buff(tag.strong(to_unicode(format_date(self._mkdatetime(
                                               year, month), '%B %Y'))))

        if showbuttons is True:
            # add buttons for going to next months and year
            buff(nav_nxM, nav_ffM, nav_nxY)

        buff = tag.table(buff)
        width=":".join(['min-width', cal_width]) 
        buff(class_='wikiTicketCalendar', style=width)

        heading = tag.tr()
        heading(align='center')

        for day in calendar.weekheader(2).split()[:-2]:
            col = tag.th(day)
            col(class_='workday', scope='col')
            heading(col)
        for day in calendar.weekheader(2).split()[-2:]:
            col = tag.th(day)
            col(class_='weekend', scope='col')
            heading(col)

        heading = buff(tag.thead(heading))

        # Building main calendar table body
        buff = tag.tbody()
        for row in cal:
            line = tag.tr()
            line(align='right')
            for day in row:
                if not day:
                    cell = tag.td('')
                    cell(class_='fill')
                    line(cell)
                else:
                    # check for wikipage with name specified in
                    # 'wiki_page_format'
                    wiki = format_date(self._mkdatetime(year, month, day),
                                                         wiki_page_format)
                    url = self.env.href.wiki(wiki)
                    if WikiSystem(self.env).has_page(wiki):
                        a_class = "day_haspage"
                        title = "Go to page %s" % wiki
                    else:
                        a_class = "day"
                        url += "?action=edit"
                        # adding template name, if specified
                        if wiki_page_template != "":
                            url += "&template=" + wiki_page_template
                        title = "Create page %s" % wiki
                    if day == curr_day:
                        td_class = 'today'
                    else:
                        td_class = 'day'

                    cell = tag.a(tag.b(day), href=url)
                    cell(class_=a_class, title_=title)
                    cell = tag.td(cell)
                    cell(class_=td_class, valign='top')

                    day_dt = self._mkdatetime(year, month, day)
                    if uts:
                        day_ts = to_utimestamp(day_dt)
                        day_ts_eod = day_ts + 86399999999
                    else:
                        day_ts = to_timestamp(day_dt)
                        day_ts_eod = day_ts + 86399

                    # check for milestone(s) on that day
                    db = self.env.get_db_cnx()
                    cursor = db.cursor()
                    cursor.execute("""
                        SELECT name
                          FROM milestone
                         WHERE due >= %s and due <= %s
                    """, (day_ts, day_ts_eod))
                    while (1):
                        row = cursor.fetchone()
                        if row is None:
                            cell(tag.br())
                            break
                        else:
                            name = to_unicode(row[0])
                            url = self.env.href.milestone(name)
                            milestone = '* ' + name
                            milestone = tag.div(tag.a(milestone, href=url))
                            milestone(class_='milestone')

                            cell(milestone)

                    match = []
                    match_od = []
                    ticket_heap = tag('')
                    ticket_list = tag.div('')
                    ticket_list(align='left', class_='condense')

                    # get tickets with due date set to day
                    for t in self.tickets:
                        due = t.get(self.due_field_name)
                        if due is None or due in ['', '--']:
                            continue
                        else:
                            if self.due_field_fmt == 'ts':
                                if not isinstance(due, datetime.datetime):
                                    continue
                                else:
                                    if uts:
                                        due_ts = to_utimestamp(due)
                                    else:
                                        due_ts = to_timestamp(due)
                                if due_ts < day_ts or \
                                    due_ts > day_ts_eod:
                                    continue
                            else:
                                duedate = format_date(day_dt,
                                                      self.due_field_fmt)
                                if not due == duedate:
                                    continue

                        id = t.get('id')
                        ticket, short = self._gen_ticket_entry(t)
                        ticket_heap(ticket)
                        if not id in match:
                            if len(match) == 0:
                                ticket_list(short)
                            else:
                                ticket_list(', ', short)
                            match.append(id)

                    # optionally get tickets created on day
                    if show_t_open_dates is True:
                        ticket_od_list = tag.div('')
                        ticket_od_list(align='left',
                                       class_='opendate_condense')

                        for t in self.tickets:
                            if uts:
                                ticket_ts = to_utimestamp(t.get('time'))
                            else:
                                ticket_ts = to_timestamp(t.get('time'))
                            if ticket_ts < day_ts or ticket_ts > day_ts_eod:
                                continue

                            a_class = 'opendate_'
                            id = t.get('id')
                            ticket, short = self._gen_ticket_entry(t, a_class)
                            ticket_heap(ticket)
                            if not id in match:
                                if len(match_od) == 0:
                                    ticket_od_list(short)
                                else:
                                    ticket_od_list(', ', short)
                                match_od.append(id)

                    matches = len(match) + len(match_od)
                    if list_condense > 0 and matches >= list_condense:
                        if len(match_od) > 0:
                            if len(match) > 0:
                                ticket_list(', ')
                            ticket_list = tag(ticket_list, ticket_od_list)
                        line(cell(ticket_list))
                    else:
                        line(cell(ticket_heap))

            buff(line)

        buff = tag.div(heading(buff))
        if cal_width.startswith('+') is True:
            width=":".join(['width', cal_width]) 
            buff(class_='wikiTicketCalendar', style=width)
        else:
            buff(class_='wikiTicketCalendar')

        # Finally prepend prepared CSS styles
        buff = tag(styles, buff) 
        
        return buff
Example #21
0
    def expand_macro(self, formatter, name, args):
        """
        Called by the formatter to render the parsed
        wiki text.
        """

        def to_html(text):
            """
            Format the parsed text from the rows into HTML.
            """
            if not text:
                return ''

            # simple check to determine whether format_to_html or 
            # format_to_oneliner should be used. If there are multiple
            # lines, use format_to_html, otherwise use format_to_oneliner

            stripped_text = text.strip()
            splitlines = stripped_text.splitlines()

            if len(splitlines) > 1:
                formatted_text = format_to_html(self.env, formatter.context, text)
            else:
                formatted_text = '<br />'.join( [format_to_oneliner(self.env, formatter.context, line) \
                    for line in text.splitlines()] ) 
            return Markup( formatted_text )

        if not args:
            return Markup()

        # use the formatter to find the TablePluginStyles
        if not formatter.wiki.has_page('TablePluginStyles'):
            # if our
            build_table_plugin_styles_page(self.env)

        if formatter.wiki.has_page('TablePluginStyles'):
            # at this point, the new style page should exist
            # so use the styles defined there.
            config_args = self._parse_wiki_style_page(self.env)
        else:
            # nice error handling in here possible incase
            # the page cannot be created for whatever reason?
            pass

        config_table_styles, config_css_styles = self._parse_styles(config_args)

        args_table_styles, args_css_styles = self._parse_styles(args)
        global_css_styles = dict(config_css_styles.items() + args_css_styles.items())

        column_list = []
        row_count = 0

        row_dict = {}
        row_list = []

        heading = False
        body_name = ''
        heading_set = False
        body_set_first = False
        first_row_as_header = False
        is_row = False

        table_id = ''
        table_data = ''

        table_style = ''
        column_style_dict = {}

        for attribute in self._parse_args(args):
            if 'table' in attribute:
                # get the table id to use
                table_id = attribute['table']['name']
                table_data = attribute['table']['data']
                table_style = attribute['table']['style'].replace('@', '')
            elif 'css' in attribute:
                pass
            elif 'column' in attribute:
                column_name = attribute['column']['name']
                column_list.append(column_name)
                if attribute['column']['style']:
                    column_style_dict[column_name] = attribute['column']['style']
            elif 'header' in attribute:
                heading = True
                heading_set = True
            elif 'body' in attribute:
                body_name = str(uuid4())
                if not heading_set and not first_row_as_header:
                    body_set_first = True
                heading = False
            elif 'row' in attribute:
                is_row = True
                row_count = 0
                row_style = attribute['row']['style']
            else:
                if not heading_set and not body_set_first:
                    first_row_as_header = True
                for key, value in attribute.items():
                    value['heading'] = heading
                    if body_name:
                        value['body_name'] = body_name
                    if is_row:
                        # if its a row, apply row style
                        original_style = value['style']
                        value['style'] = ' '.join([original_style, row_style])
                if row_count == (len(column_list) - 1):
                    row_dict.update(attribute)
                    row_list.append(row_dict)
                    row_dict = {}
                    row_count = 0
                    is_row = False
                else:
                    row_dict.update(attribute)
                    row_count += 1

        thead = tag.thead()
        for row in row_list:
            if body_set_first:
                break
            header_row = tag.tr()
            for column in column_list:
                header_cell = ''
                if row[column]['heading'] or first_row_as_header:
                    header_cell = tag.th()
                    header_cell(to_html(row[column]['data']), class_=row[column]['style'].replace('@', ''))
                    header_row(header_cell)
            if header_cell:
                thead(header_row)
            if first_row_as_header:
                break

        if table_style:
            table_id = table_style
            table_data = config_table_styles[table_style]['data']


        css_data = self._build_css_template(global_css_styles)

        full_style_data = ''
        full_style_data += table_data
        full_style_data += css_data

        tstyle = tag.style()
        tstyle = tag.style(full_style_data)

        tbody = tag.tbody()
        body_name = ''
        body_set = False

        tbody_list = []
        for row in row_list:
            if first_row_as_header:
                heading_set = False
                first_row_as_header = False
                continue
            trow = tag.tr()
            tcol = ''
            for column in column_list:
                if row[column]['heading']:
                    continue
                if row[column]['body_name'] == body_name and not body_set:
                    body_set = True
                elif row[column]['body_name'] != body_name and not body_set:
                    body_name = row[column]['body_name']
                    body_set = True
                elif row[column]['body_name'] != body_name and body_set:
                    tbody_list.append(tbody)
                    tbody = tag.tbody()
                    trow = tag.tr()
                    body_name = row[column]['body_name']
                tcol = tag.td()
                # if there is a column style available,
                # add it to what is already there
                formatted_column_style = ''
                if column in column_style_dict:
                    column_style = column_style_dict[column].replace('@', '')
                    formatted_column_style = column_style.replace(';', ' ')
                class_styles = row[column]['style'].replace('@', '')
                formatted_class_styles = class_styles.replace(';', ' ')
                formatted_item = ' '.join([formatted_class_styles, formatted_column_style])
                tcol(to_html(row[column]['data']), class_=formatted_item)
                trow(tcol)
            if tcol:
                tbody(trow)
        tbody_list.append(tbody)

        return tag.table([tstyle, thead, tbody_list], class_=table_id)
    def render(self, ticketset):
        '''
      Generate a HTML Table for the Fields/Extensions given
    '''
        # style overwritten to prevent browser rendering issues
        #outer = tag.table( class_="listing pptickettable tablesorter pplisting" , style = 'width:auto;')
        outer = tag.table(class_="listing pptickettable tablesorter pplisting",
                          style='width:auto;')
        srtlist = self.keysortedids(ticketset)
        tablehead = tag.thead()
        inner = tag.tr()

        # TODO: problem: if the ticketset is empty, then the default rows will appear,
        # solution: get the fields from somewhere else
        if self.allfields == True and len(ticketset.getIDList()) > 0:
            self.fields = []
            for f in (ticketset.getTicket(
                    ticketset.getIDList()[0])).getfielddefs():
                if not (f.lower() in self.allfieldsexclude):
                    self.fields.append(f)

        # generate HTML: Table head
        for f in self.fields:
            cssheaderclass = self.getcssheaderclass(f)
            if self.macroenv.get_bool_arg(
                    'showdescription',
                    'F') == True:  # workaround for this parameter
                cssheaderclass = '{sorter: false}'

            self.macroenv.tracenv.log.debug('cssheaderclass of ' + f + ': ' +
                                            cssheaderclass)
            if f in self.headermap:
                inner(tag.th(self.headermap[f], title=f,
                             class_=cssheaderclass))
            else:
                inner(tag.th(f, class_=cssheaderclass))
        for e in self.extensions:
            if e in self.headermap:
                inner(
                    tag.th(self.headermap[e],
                           title=e,
                           class_=self.getcssheaderclass(e)))
            else:
                inner(tag.th(e), class_=self.getcssheaderclass(e))
        tablehead(inner)
        outer(tablehead)

        customdatefields = [
            self.macroenv.conf.get('custom_due_assign_field'),
            self.macroenv.conf.get('custom_due_close_field')
        ]

        def getSortableTableCell(f):
            field = t.getfielddef(f, '')
            cssclass, style = self.getcsscolstyle(f, field)
            if f == 'id':
                if t.getfielddef('status', '') == 'closed':
                    cssclass = "ticket closed"
                else:
                    cssclass = "ticket "
                text = tag.p(
                    tag.a('#' + str(t.getfielddef(f, '')),
                          href=t.getfielddef('href', ''),
                          class_=cssclass))
            elif f == 'priority':  # special case
                # two-digit integer representation of priority sorting (as definend in trac admin panel)
                text = tag.span(
                    str(99 - int(t.getfielddef('priority_value', '0'))),
                    class_='invisible') + self.wiki2html(field)
            elif f in customdatefields:  # special case: date string
                text = tag.span(self.getNormalizedDateStringOfSegment(field),
                                class_='invisible') + self.wiki2html(field)
            else:
                text = self.wiki2html(field)
            return (text, cssclass, style)

        # generate HTML: Table body
        _odd = True
        for k in srtlist:
            t = ticketset.getTicket(k)
            _odd = not _odd
            if _odd:
                inner = tag.tr(class_='odd')
            else:
                inner = tag.tr(class_='even')
            for f in self.fields:
                text, cssclass, style = getSortableTableCell(f)
                inner(tag.td(text, style=style, class_=cssclass))
            for e in self.extensions:
                if t.hasextension(e):
                    cssclass, style = self.getcsscolstyle(
                        e, t.getfielddef(e, ''))
                    inner(
                        tag.td(t.getextension(e), style=style,
                               class_=cssclass))
                else:
                    #inner( tag.td( '0', title='no statement possible', class_ = 'ppinvisibletabletext' ) )
                    inner(
                        tag.td('',
                               title='no statement possible',
                               class_='ppinvisibletabletext'))
            outer(inner)

            # if macro parameter "showdescription" is set to True, then a long description is rendered into a second row spanning of all cols
            if _odd:
                inner2 = tag.tr(class_='odd')
            else:
                inner2 = tag.tr(class_='even')
            if self.macroenv.get_bool_arg('showdescription', 'F') == True:
                outer(
                    inner2(
                        tag.td(
                            self.wiki2html(t.getfielddef('description', '')),
                            colspan=len(self.fields) + len(self.extensions))))

            if self.limitlines > 0:
                self.limitlines -= 1
                if self.limitlines <= 0:
                    break

        return outer
Example #23
0
    def expand_macro(self, formatter, name, arguments):

        self.ref = formatter
        self.tz_info = formatter.req.tz
        self.thistime = datetime.datetime.now(self.tz_info)

        # Parse arguments from macro invocation
        args, kwargs = parse_args(arguments, strict=False)

        # Find out whether use http param, current or macro param year/month
        http_param_year = formatter.req.args.get('year', '')
        http_param_month = formatter.req.args.get('month', '')

        if http_param_year == "":
            # not clicked on a prev or next button
            if len(args) >= 1 and args[0] <> "*":
                # year given in macro parameters
                year = int(args[0])
            else:
                # use current year
                year = self.thistime.year
        else:
            # year in http params (clicked by user) overrides everything
            year = int(http_param_year)

        if http_param_month == "":
            # not clicked on a prev or next button
            if len(args) >= 2 and args[1] <> "*":
                # month given in macro parameters
                month = int(args[1])
            else:
                # use current month
                month = self.thistime.month
        else:
            # month in http params (clicked by user) overrides everything
            month = int(http_param_month)

        showbuttons = True
        if len(args) >= 3 or kwargs.has_key('nav'):
            try:
                showbuttons = kwargs['nav'] in ["True", "true", "yes", "1"]
            except KeyError:
                showbuttons = args[2] in ["True", "true", "yes", "1"]

        wiki_page_format = "%Y-%m-%d"
        if len(args) >= 4 and args[3] != "*" or kwargs.has_key('wiki'):
            try:
                wiki_page_format = str(kwargs['wiki'])
            except KeyError:
                wiki_page_format = str(args[3])
        # Support relative paths in macro arguments for wiki page links.
        wiki_page_format = self._resolve_relative_name(wiki_page_format,
                                                       formatter.resource.id)

        list_condense = 0
        show_t_open_dates = True
        wiki_page_template = ""
        wiki_subpages = []

        # Read optional check plan.
        check = []
        if kwargs.has_key('check'):
            check = kwargs['check'].split('.')

        if name == 'WikiTicketCalendar':
            if len(args) >= 5 or kwargs.has_key('cdate'):
                try:
                    show_t_open_dates = kwargs['cdate'] in \
                                               ["True", "true", "yes", "1"]
                except KeyError:
                    show_t_open_dates = args[4] in \
                                               ["True", "true", "yes", "1"]

        # Optional page template to create new wiki pages.
        # The default (empty page) is used, if the template name is invalid.
        if len(args) >= 6 or kwargs.has_key('base'):
            try:
                wiki_page_template = kwargs['base']
            except KeyError:
                wiki_page_template = args[5]

        if name == 'WikiTicketCalendar':
            # TracQuery support for ticket selection
            query_args = "id!=0"
            if len(args) >= 7 or kwargs.has_key('query'):
                # prefer query arguments provided by kwargs
                try:
                    query_args = kwargs['query']
                except KeyError:
                    query_args = args[6]
            tickets = WikiCalendarTicketProvider(self.env)
            self.tickets = tickets.harvest(formatter.req, query_args)

            # compress long ticket lists
            if len(args) >= 8 or kwargs.has_key('short'):
                # prefer query arguments provided by kwargs
                try:
                    list_condense = int(kwargs['short'])
                except KeyError:
                    list_condense = int(args[7])

            # control calendar display width
            cal_width = "100%;"
            if len(args) >= 9 or kwargs.has_key('width'):
                # prefer query arguments provided by kwargs
                try:
                    cal_width = kwargs['width']
                except KeyError:
                    cal_width = args[8]

            # multiple wiki (sub)pages per day
            if kwargs.has_key('subpages'):
                wiki_subpages = kwargs['subpages'].split('|')

            # Can use this to change the day the week starts on,
            # but this is a system-wide setting.
            calendar.setfirstweekday(calendar.MONDAY)

        cal = calendar.monthcalendar(year, month)
        curr_day = None
        if year == self.thistime.year and month == self.thistime.month:
            curr_day = self.thistime.day

        # for prev/next navigation links
        prevMonth = month - 1
        nextMonth = month + 1
        nextYear = prevYear = year
        # check for year change (KISS version)
        if prevMonth == 0:
            prevMonth = 12
            prevYear -= 1
        if nextMonth == 13:
            nextMonth = 1
            nextYear += 1

        # for fast-forward/-rewind navigation links
        ffYear = frYear = year
        if month < 4:
            frMonth = month + 9
            frYear -= 1
        else:
            frMonth = month - 3
        if month > 9:
            ffMonth = month - 9
            ffYear += 1
        else:
            ffMonth = month + 3

        last_week_prevMonth = calendar.monthcalendar(prevYear, prevMonth)[-1]
        first_week_nextMonth = calendar.monthcalendar(nextYear, nextMonth)[0]

        # Switch to user's locale, if available.
        try:
            loc_req = str(formatter.req.locale)
        except AttributeError:
            # Available since in Trac 0.12 .
            loc_req = None
        if loc_req:
            loc = locale.getlocale()
            loc_prop = locale.normalize(loc_req)
            try:
                locale.setlocale(locale.LC_TIME, loc_prop)
            except locale.Error:
                try:
                    # Re-try with UTF-8 as last resort.
                    loc_prop = '.'.join([loc_prop.split('.')[0], 'utf8'])
                    locale.setlocale(locale.LC_TIME, loc_prop)
                except locale.Error:
                    loc_prop = None
            self.env.log.debug('Locale setting for calendar: ' + str(loc_prop))

        # Finally building the output
        # Begin with caption and optional navigation links
        buff = tag.tr()

        if showbuttons is True:
            # calendar navigation buttons
            nx = 'next'
            pv = 'prev'
            nav_pvY = self._mknav('&lt;&lt;', pv, month, year - 1)
            nav_frM = self._mknav('&nbsp;&lt;', pv, frMonth, frYear)
            nav_pvM = self._mknav('&nbsp;&laquo;', pv, prevMonth, prevYear)
            nav_nxM = self._mknav('&raquo;&nbsp;', nx, nextMonth, nextYear)
            nav_ffM = self._mknav('&gt;&nbsp;', nx, ffMonth, ffYear)
            nav_nxY = self._mknav('&gt;&gt;', nx, month, year + 1)

            # add buttons for going to previous months and year
            buff(nav_pvY, nav_frM, nav_pvM)

        # The caption will always be there.
        heading = tag.td(
            to_unicode(format_date(self._mkdatetime(year, month), '%B %Y')))
        buff = buff(heading(class_='y'))

        if showbuttons is True:
            # add buttons for going to next months and year
            buff(nav_nxM, nav_ffM, nav_nxY)
        buff = tag.caption(tag.table(tag.tbody(buff)))
        buff = tag.table(buff)
        if name == 'WikiTicketCalendar':
            if cal_width.startswith('+') is True:
                width = ":".join(['min-width', cal_width])
                buff(class_='wikitcalendar', style=width)
            else:
                buff(class_='wikitcalendar')
        if name == 'WikiCalendar':
            buff(class_='wiki-calendar')

        heading = tag.tr()
        heading(align='center')

        for day in calendar.weekheader(2).split()[:-2]:
            col = tag.th(to_unicode(day))
            col(class_='workday', scope='col')
            heading(col)
        for day in calendar.weekheader(2).split()[-2:]:
            col = tag.th(to_unicode(day))
            col(class_='weekend', scope='col')
            heading(col)

        heading = buff(tag.thead(heading))

        # Building main calendar table body
        buff = tag.tbody()
        w = -1
        for week in cal:
            w = w + 1
            line = tag.tr()
            line(align='right')
            d = -1
            for day in week:
                d = d + 1
                if day:
                    # check for wikipage with name specified in
                    # 'wiki_page_format'
                    wiki = format_date(self._mkdatetime(year, month, day),
                                       wiki_page_format)
                    if day == curr_day:
                        a_class = 'day today'
                        td_class = 'today'
                    else:
                        a_class = 'day'
                        td_class = 'day'

                    day_dt = self._mkdatetime(year, month, day)
                    if uts:
                        day_ts = to_utimestamp(day_dt)
                        day_ts_eod = day_ts + 86399999999
                    else:
                        day_ts = to_timestamp(day_dt)
                        day_ts_eod = day_ts + 86399

                    # check for milestone(s) on that day
                    db = self.env.get_db_cnx()
                    cursor = db.cursor()
                    cursor.execute(
                        """
                        SELECT name
                          FROM milestone
                         WHERE due >= %s and due <= %s
                    """, (day_ts, day_ts_eod))
                    milestones = tag()
                    for row in cursor:
                        if not a_class.endswith('milestone'):
                            a_class += ' milestone'
                        milestone = to_unicode(row[0])
                        url = self.env.href.milestone(milestone)
                        milestone = '* ' + milestone
                        milestones = tag(
                            milestones,
                            tag.div(tag.a(milestone, href=url),
                                    class_='milestone'))
                    day = tag.span(day)
                    day(class_='day')
                    if len(wiki_subpages) > 0:
                        pages = tag(day, Markup('<br />'))
                        for page in wiki_subpages:
                            label = tag(' ', page[0])
                            page = '/'.join([wiki, page])
                            url = self.env.href.wiki(page)
                            pages(
                                self._gen_wiki_links(page, label, 'subpage',
                                                     url, wiki_page_template,
                                                     check))
                    else:
                        url = self.env.href.wiki(wiki)
                        pages = self._gen_wiki_links(wiki, day, a_class, url,
                                                     wiki_page_template, check)
                    cell = tag.td(pages)
                    cell(class_=td_class, valign='top')
                    if name == 'WikiCalendar':
                        line(cell)
                    else:
                        if milestones:
                            cell(milestones)
                        else:
                            cell(tag.br())

                        match = []
                        match_od = []
                        ticket_heap = tag('')
                        ticket_list = tag.div('')
                        ticket_list(align='left', class_='condense')

                        # get tickets with due date set to day
                        for t in self.tickets:
                            due = t.get(self.tkt_due_field)
                            if due is None or due in ['', '--']:
                                continue
                            else:
                                if self.tkt_due_format == 'ts':
                                    if not isinstance(due, datetime.datetime):
                                        continue
                                    if uts:
                                        due_ts = to_utimestamp(due)
                                    else:
                                        due_ts = to_timestamp(due)
                                    if due_ts < day_ts or due_ts > day_ts_eod:
                                        continue
                                else:
                                    # Beware: Format might even be unicode str
                                    duedate = format_date(
                                        day_dt, str(self.tkt_due_format))
                                    if not due == duedate:
                                        continue

                            id = t.get('id')
                            ticket, short = self._gen_ticket_entry(t)
                            ticket_heap(ticket)
                            if not id in match:
                                if len(match) == 0:
                                    ticket_list(short)
                                else:
                                    ticket_list(', ', short)
                                match.append(id)

                        # optionally get tickets created on day
                        if show_t_open_dates is True:
                            ticket_od_list = tag.div('')
                            ticket_od_list(align='left',
                                           class_='opendate_condense')

                            for t in self.tickets:
                                if uts:
                                    ticket_ts = to_utimestamp(t.get('time'))
                                else:
                                    ticket_ts = to_timestamp(t.get('time'))
                                if ticket_ts < day_ts or \
                                        ticket_ts > day_ts_eod:
                                    continue

                                a_class = 'opendate_'
                                id = t.get('id')
                                ticket, short = self._gen_ticket_entry(
                                    t, a_class)
                                ticket_heap(ticket)
                                if not id in match:
                                    if len(match_od) == 0:
                                        ticket_od_list(short)
                                    else:
                                        ticket_od_list(', ', short)
                                    match_od.append(id)

                        matches = len(match) + len(match_od)
                        if list_condense > 0 and matches >= list_condense:
                            if len(match_od) > 0:
                                if len(match) > 0:
                                    ticket_list(', ')
                                ticket_list = tag(ticket_list, ticket_od_list)
                            line(cell(ticket_list))
                        else:
                            line(cell(ticket_heap))
                else:
                    if name == 'WikiCalendar':
                        if w == 0:
                            day = last_week_prevMonth[d]
                            wiki = format_date(
                                self._mkdatetime(prevYear, prevMonth, day),
                                wiki_page_format)
                        else:
                            day = first_week_nextMonth[d]
                            wiki = format_date(
                                self._mkdatetime(nextYear, nextMonth, day),
                                wiki_page_format)
                        url = self.env.href.wiki(wiki)
                        a_class = 'day adjacent_month'
                        pages = self._gen_wiki_links(wiki, day, a_class, url,
                                                     wiki_page_template)

                        cell = tag.td(pages)
                        cell(class_='day adjacent_month')
                        line(cell)
                    else:
                        cell = tag.td('')
                        cell(class_='day adjacent_month')
                        line(cell)
            buff(line)

        if loc_req and loc_prop:
            # We may have switched to users locale, resetting now.
            try:
                locale.setlocale(locale.LC_ALL, loc)
                self.env.log.debug('Locale setting restored: ' + str(loc))
            except locale.Error:
                pass

        buff = tag.div(heading(buff))
        if name == 'WikiTicketCalendar':
            if cal_width.startswith('+') is True:
                width = ":".join(['width', cal_width])
                buff(class_='wikitcalendar', style=width)
            else:
                buff(class_='wikitcalendar')
        if name == 'WikiCalendar':
            buff(class_='wiki-calendar')
        # Add common CSS stylesheet
        if self.internal_css and not self.ref.req.args.get('wikicalendar'):
            # Put definitions directly into the output.
            f = open('/'.join([self.htdocs_path, 'wikicalendar.css']), 'Ur')
            css = tag.style(Markup('<!--\n'), '\n'.join(f.readlines()),
                            Markup('-->\n'))(type="text/css")
            f.close()
            # Add hint to prevent multiple inclusions.
            self.ref.req.args['wikicalendar'] = True
            return tag(css, buff)
        elif not self.ref.req.args.get('wikicalendar'):
            add_stylesheet(self.ref.req, 'wikicalendar/wikicalendar.css')
        return buff
Example #24
0
    def LastChangesBy(self, formatter, content):
        """
This macro prints a table similar to the `[[ListOfWikiPages]]` only with the 
''By'' column missing and the author name in the table head.
{{{
[[LastChangesBy(martin_s)]]          # the last 5 changes by user `martin_s`
[[LastChangesBy(martin_s,10)]]       # the last 10 changes by user `martin_s`

[[LastChangesBy]]                    # or
[[LastChangesBy()]]                  # the last 5 changes by the current user (i.e. every user sees it's own changes, if logged-on)
[[LastChangesBy(,12)]]               # the last 12 changes by the current user

[[LastChangesBy(...,format=...]]     # Selects `long` or `short` table format
[[LastChangesBy(...,from=..,to=..]]  # Selects `from` and `to` time/date range

[[LastChangesBy(...,headline=...]]   # Overwrites headline, may not contain `','`

[[LastChangesBy(...,order=reverse]]  # Lists the wikis in reverse order. Only really useful with few wikis or with `to`/`from`.

[[LastChangesBy(..,exclude=pattern]] # Excludes wikis matching `pattern`. Wildcards `*` and `?` are supported.
}}}
        """

        largs, kwargs = parse_args(content)

        #self.base_path = formatter.req.base_path
        self.href = formatter.req.href
        section = 'listofwikipages'

        long_format = self.env.config.get(section, 'default_format',
                                          'short').lower() == 'long'
        if 'format' in kwargs:
            long_format = kwargs['format'].lower() == 'long'
        self.long_format = long_format

        self.kwargs = kwargs
        dfrom, fromtext = self.timeval('from', (0, ''))
        dto, totext = self.timeval('to', (int(unixtime()), ''))

        if 'from' in kwargs or 'to' in kwargs:
            sql_time = " AND time BETWEEN %d AND %d " % (dfrom, dto)
        else:
            sql_time = ''

        sql_exclude = ''
        if 'exclude' in kwargs:
            sql_exclude = self._get_sql_exclude(kwargs['exclude'])

        author = len(largs) > 0 and largs[0] or formatter.req.authname
        count = len(largs) > 1 and largs[1] or 5
        try:
            count = int(count)
            if count < 1:
                raise
        except:
            raise TracError("Second list argument must be a positive integer!")

        db = self.env.get_db_cnx()
        cursor = db.cursor()
        #cursor.log = self.env.log

        if kwargs.get('order', 'normal') == 'reverse':
            order = " "
        else:
            order = " DESC "

        cursor.execute(
            """
              SELECT name,time,version,comment
              FROM wiki AS w1 WHERE author = %s """ + sql_time + sql_exclude +
            """
              AND version=(SELECT MAX(version) FROM wiki AS w2 WHERE w1.name=w2.name)
              ORDER BY time
          """ + order + " LIMIT 0,%d " % count, (author, ))

        rows = [
            self.formatrow(n, name, time, version, comment)
            for n, [name, time, version, comment] in enumerate(cursor)
            if n < count
        ]
        if count == 1:
            count = ''
            s = ''
        else:
            s = 's'

        if self.long_format:
            cols = ("WikiPage", "Last Changed At", "Version", "Diff",
                    "History", "Comment")
        else:
            cols = ("WikiPage", "Last Changed At")

        headline = "Last %s change%s by  " % (count, s)
        if sql_time:
            if fromtext:
                if totext:
                    timetag = " between %s and %s ago" % (fromtext, totext)
                else:
                    timetag = " in the last %s" % fromtext
            else:
                if totext:
                    timetag = " before the last %s" % totext
                else:
                    timetag = ""
        else:
            timetag = ''

        if 'headline' in kwargs:
            headlinetag = tag.tr(tag.th(kwargs['headline'], colspan=len(cols)))
        else:
            headlinetag = tag.tr(
                tag.th(headline,
                       tag.strong(author),
                       timetag,
                       colspan=len(cols)))

        head = tag.thead(
            headlinetag,
            tag.tr(
                map(lambda x: tag.th(x, class_=x.replace(" ", "").lower()),
                    cols)))
        table = tag.table(head, rows, class_='lastchangesby')

        self.href = None
        return table
    def filter_stream(self, req, method, filename, stream, data):

        # Tickets will be modified to show the child tickets as a list under the 'Description' section.
        if filename == 'ticket.html':

            # Get the ticket info.
            ticket = data.get('ticket')

            # Modify ticket.html with sub-ticket table, create button, etc...
            # As follows:
            # - If ticket has no child tickets and child tickets are NOT allowed then skip.
            # - If ticket has child tickets and child tickets are NOT allowed (ie. rules changed or ticket type changed after children were assigned),
            #   print list of tickets but do not allow any tickets to be created.
            # - If child tickets are allowed then print list of child tickets or 'No Child Tickets' if non are currently assigned.
            # 
            if ticket and ticket.exists:

                filter = Transformer('//div[@class="description"]')
                snippet = tag()

                # Are there any child tickets to display?
                childtickets = [ Ticket(self.env, n) for n in self.env.childtickets.get(ticket.id, []) ]

                # trac.ini : Which columns to display in child ticket listing?
                columns = self.config.getlist('childtickets', 'parent.%s.table_headers' % ticket['type'], default = ['summary', 'owner'])

                # Forcing default setting to inherit from the parent ticket
                default_child_milestone = ticket['milestone']
                default_child_type = ticket['type']

                # Test if the ticket has children: If so, then list in pretty table.
                if childtickets:
                    snippet.append(
                            tag.div(tag.h3("Child Tickets:", id = "comment:child_tickets"),
                                tag.table(
                                    tag.thead(
                                        tag.tr(
                                            tag.th("Ticket", class_ = "id"),
                                            [ tag.th(s.title(), class_ = s) for s in columns ])
                                        ),
                                    tag.tbody([ self._table_row(req, tkt, columns) for tkt in childtickets ]),
                                    class_ = "listing",
                                    ),
                                )
                            )
                else:
                    snippet.append(tag.div(tag.h3("Child Tickets:", id = "comment:child_tickets"), tag.p("NO SUB-TICKETS.")))

                # Can user create a new ticket? If not, just display title (ie. no 'create' button).
                if 'TICKET_CREATE' in req.perm(ticket.resource):
                        snippet.append(
                            tag.div(
                                tag.form(
                                    tag.div(
                                        tag.span(
                                            tag.input(type = "hidden", name = "parent", value = '#' + str(ticket.id)),
                                            tag.input(type = "hidden", name = "milestone", value = default_child_milestone),
                                            tag.input(type = "hidden", name = "type", value = default_child_type),
                                            tag.input(type = "submit", name = "childticket", value = "Create", title = "Create a child ticket"),
                                            class_ = "primaryButton"),
                                        class_ = "buttons"),
                                    method = "get", action = req.href.newticket()
                                    )
                                )
                            )

                return stream | filter.append(snippet)

        return stream
Example #26
0
    def expand_macro(self, formatter, name, arguments):
        """Returns macro content."""
        env = self.env
        req = formatter.req
        tz = req.tz

        # Parse arguments from macro invocation.
        args, kwargs = parse_args(arguments, strict=False)

        # Enable week number display regardless of argument position.
        week_pref = "w" in args and args.pop(args.index("w"))

        week_pref = week_pref and week_pref or kwargs.get("w")
        week_start = None
        week_num_start = None
        # Parse per-instance week calculation rules, if available.
        if week_pref:
            if ":" not in week_pref:
                # Treat undelimitted setting as week start.
                week_pref += ":"
            w_start, wn_start = week_pref.split(":")
            try:
                week_start = int(w_start)
            except ValueError:
                week_start = None
            else:
                week_start = week_start > -1 and week_start < 7 and week_start or None
            try:
                week_num_start = int(wn_start)
            except ValueError:
                week_num_start = None
            else:
                week_num_start = week_num_start in (1, 4, 7) and week_num_start or None

        # Respect user's locale, if available.
        try:
            locale = Locale.parse(str(req.locale))
        except (AttributeError, UnknownLocaleError):
            # Attribute 'req.locale' vailable since Trac 0.12.
            locale = None
        if has_babel:
            if locale:
                if not locale.territory:
                    # Search first locale, which has the same `language` and
                    # territory in preferred languages.
                    for l in req.languages:
                        l = l.replace("-", "_").lower()
                        if l.startswith(locale.language.lower() + "_"):
                            try:
                                l = Locale.parse(l)
                                if l.territory:
                                    locale = l
                                    break  # first one rules
                            except UnknownLocaleError:
                                pass
                if not locale.territory and locale.language in LOCALE_ALIASES:
                    locale = Locale.parse(LOCALE_ALIASES[locale.language])
            else:
                # Default fallback.
                locale = Locale("en", "US")
            env.log.debug("Locale setting for wiki calendar: %s" % locale.get_display_name("en"))
        if not week_start:
            if week_pref and week_pref.lower().startswith("iso"):
                week_start = 0
                week_num_start = 4
            elif has_babel:
                week_start = locale.first_week_day
            else:
                import calendar

                week_start = calendar.firstweekday()
        # ISO calendar will remain as default.
        if not week_num_start:
            if week_start == 6:
                week_num_start = 1
            else:
                week_num_start = 4
        env.log.debug(
            "Effective settings: first_week_day=%s, " "1st_week_of_year_rule=%s" % (week_start, week_num_start)
        )

        # Find year and month of interest.
        year = req.args.get("year")
        # Not clicked on any previous/next button, next look for macro args.
        if not year and len(args) >= 1 and args[0] != "*":
            year = args[0]
        year = year and year.isnumeric() and int(year) or None

        month = req.args.get("month")
        # Not clicked on any previous/next button, next look for macro args.
        if not month and len(args) >= 2 and args[1] != "*":
            month = args[1]
        month = month and month.isnumeric() and int(month) or None

        now = datetime.now(tz)
        # Force offset from start-of-day to avoid a false 'today' marker,
        # but use it only on request of different month/year.
        now.replace(second=1)
        today = None
        if month and month != now.month:
            today = now.replace(month=month)
        if year and year != now.year:
            today = today and today.replace(year=year) or now.replace(year=year)
        # Use current month and year, if nothing else has been requested.
        if not today:
            today = now.replace(hour=0, minute=0, second=0, microsecond=0)

        showbuttons = True
        if len(args) >= 3 or kwargs.has_key("nav"):
            try:
                showbuttons = kwargs["nav"] in _TRUE_VALUES
            except KeyError:
                showbuttons = args[2] in _TRUE_VALUES

        wiki_page_format = "%Y-%m-%d"
        if len(args) >= 4 and args[3] != "*" or kwargs.has_key("wiki"):
            try:
                wiki_page_format = str(kwargs["wiki"])
            except KeyError:
                wiki_page_format = str(args[3])
        # Support relative paths in macro arguments for wiki page links.
        wiki_page_format = resolve_relative_name(wiki_page_format, formatter.resource.id)

        list_condense = 0
        show_t_open_dates = True
        wiki_subpages = []

        # Read optional check plan.
        check = []
        if kwargs.has_key("check"):
            check = kwargs["check"].split(".")

        if name == "WikiTicketCalendar":
            if len(args) >= 5 or kwargs.has_key("cdate"):
                try:
                    show_t_open_dates = kwargs["cdate"] in _TRUE_VALUES
                except KeyError:
                    show_t_open_dates = args[4] in _TRUE_VALUES

            # TracQuery support for ticket selection
            query_args = "id!=0"
            if len(args) >= 7 or kwargs.has_key("query"):
                # prefer query arguments provided by kwargs
                try:
                    query_args = kwargs["query"]
                except KeyError:
                    query_args = args[6]
            provider = WikiCalendarTicketProvider(env)
            tickets = provider.harvest(req, query_args)

            # compress long ticket lists
            if len(args) >= 8 or kwargs.has_key("short"):
                # prefer query arguments provided by kwargs
                try:
                    list_condense = int(kwargs["short"])
                except KeyError:
                    list_condense = int(args[7])

            # control calendar display width
            cal_width = "100%;"
            if len(args) >= 9 or kwargs.has_key("width"):
                # prefer query arguments provided by kwargs
                try:
                    cal_width = kwargs["width"]
                except KeyError:
                    cal_width = args[8]

            # multiple wiki (sub)pages per day
            if kwargs.has_key("subpages"):
                wiki_subpages = kwargs["subpages"].split("|")

        # Prepare datetime objects for previous/next navigation link creation.
        prev_year = month_offset(today, -12)
        prev_quarter = month_offset(today, -3)
        prev_month = month_offset(today, -1)
        next_month = month_offset(today, 1)
        next_quarter = month_offset(today, 3)
        next_year = month_offset(today, 12)

        # Find first and last calendar day, probably in last/next month,
        # using datetime objects exactly at start-of-day here.
        # Note: Calendar days are numbered 0 (Mo) - 6 (Su).
        first_day_month = today.replace(day=1, second=0)
        first_day = first_day_month - timedelta(week_index(first_day_month, week_start))
        last_day_month = next_month.replace(day=1) - timedelta(1)
        if ((last_day_month - first_day).days + 1) % 7 > 0:
            last_day = last_day_month + timedelta(7 - ((last_day_month - first_day).days + 1) % 7)
        else:
            last_day = last_day_month

        # Finally building the output now.
        # Begin with caption and optional navigation links.
        buff = tag.tr()

        if showbuttons is True:
            # Create calendar navigation buttons.
            nx = "next"
            pv = "prev"
            nav_pv_y = _nav_link(req, "&lt;&lt;", pv, prev_year, locale)
            nav_pv_q = _nav_link(req, "&nbsp;&laquo;", pv, prev_quarter, locale)
            nav_pv_m = _nav_link(req, "&nbsp;&lt;", pv, prev_month, locale)
            nav_nx_m = _nav_link(req, "&gt;&nbsp;", nx, next_month, locale)
            nav_nx_q = _nav_link(req, "&raquo;&nbsp;", nx, next_quarter, locale)
            nav_nx_y = _nav_link(req, "&gt;&gt;", nx, next_year, locale)

            # Add buttons for going to previous months and year.
            buff(nav_pv_y, nav_pv_q, nav_pv_m)

        # The caption will always be there.
        if has_babel:
            heading = tag.td(format_datetime(today, "MMMM y", locale=locale))
        else:
            heading = tag.td(format_date(today, "%B %Y"))
        buff = buff(heading(class_="y"))

        if showbuttons is True:
            # Add buttons for going to next months and year.
            buff(nav_nx_m, nav_nx_q, nav_nx_y)
        buff = tag.caption(tag.table(tag.tbody(buff)))
        buff = tag.table(buff)
        if name == "WikiTicketCalendar":
            if cal_width.startswith("+") is True:
                width = ":".join(["min-width", cal_width])
                buff(class_="wikitcalendar", style=width)
            else:
                buff(class_="wikitcalendar")
        if name == "WikiCalendar":
            buff(class_="wiki-calendar")

        heading = tag.tr()
        heading(align="center")
        if week_pref:
            # Add an empty cell matching the week number column below.
            heading(tag.th())

        day_names = [(idx, day_name) for idx, day_name in get_day_names("abbreviated", "format", locale).iteritems()]
        # Read day names after shifting into correct position.
        for idx, name_ in day_names[week_start:7] + day_names[0:week_start]:
            col = tag.th(name_)
            if has_babel:
                weekend = idx >= locale.weekend_start and idx <= locale.weekend_end
            else:
                weekend = idx > 4
            col(class_=("workday", "weekend")[weekend], scope="col")
            heading(col)
        heading = buff(tag.thead(heading))

        # Building main calendar table body
        buff = tag.tbody()
        day = first_day
        while day.date() <= last_day.date():
            # Insert a new row for every week.
            if (day - first_day).days % 7 == 0:
                line = tag.tr()
                line(align="right")
                if week_pref:
                    cell = tag.td(week_num(env, day, week_start, week_num_start))
                    line(cell(class_="week"))
            if not (day < first_day_month or day > last_day_month):
                wiki = format_date(day, wiki_page_format)
                if day == today:
                    a_class = "day today"
                    td_class = "today"
                else:
                    a_class = "day"
                    td_class = "day"

                if uts:
                    day_ts = to_utimestamp(day)
                    day_ts_eod = day_ts + 86399999999
                else:
                    day_ts = to_timestamp(day)
                    day_ts_eod = day_ts + 86399

                # Check for milestone(s) on that day.
                db = env.get_db_cnx()
                cursor = db.cursor()
                cursor.execute(
                    """
                    SELECT name
                      FROM milestone
                     WHERE due >= %s and due <= %s
                """,
                    (day_ts, day_ts_eod),
                )
                milestones = tag()
                for row in cursor:
                    if not a_class.endswith("milestone"):
                        a_class += " milestone"
                    milestone = to_unicode(row[0])
                    url = env.href.milestone(milestone)
                    milestone = "* " + milestone
                    milestones = tag(milestones, tag.div(tag.a(milestone, href=url), class_="milestone"))
                label = tag.span(day.day)
                label(class_="day")
                # Generate wiki page links with name specified in
                # 'wiki_page_format', and check their existence.
                if len(wiki_subpages) > 0:
                    pages = tag(label, Markup("<br />"))
                    for page in wiki_subpages:
                        label = tag(" ", page[0])
                        page = "/".join([wiki, page])
                        pages(self._wiki_link(req, args, kwargs, page, label, "subpage", check))
                else:
                    pages = self._wiki_link(req, args, kwargs, wiki, label, a_class, check)
                cell = tag.td(pages)
                cell(class_=td_class, valign="top")
                if name == "WikiCalendar":
                    line(cell)
                else:
                    if milestones:
                        cell(milestones)
                    else:
                        cell(tag.br())

                    match = []
                    match_od = []
                    ticket_heap = tag("")
                    ticket_list = tag.div("")
                    ticket_list(align="left", class_="condense")

                    # Get tickets with due date set to day.
                    for t in tickets:
                        due = t.get(self.tkt_due_field)
                        if due is None or due in ("", "--"):
                            continue
                        else:
                            if self.tkt_due_format == "ts":
                                if not isinstance(due, datetime):
                                    continue
                                if uts:
                                    due_ts = to_utimestamp(due)
                                else:
                                    due_ts = to_timestamp(due)
                                if due_ts < day_ts or due_ts > day_ts_eod:
                                    continue
                            else:
                                # Beware: Format might even be unicode string,
                                # but str is required by the function.
                                duedate = format_date(day, str(self.tkt_due_format))
                                if not due == duedate:
                                    continue

                        tkt_id = t.get("id")
                        ticket, short = _ticket_links(env, formatter, t)
                        ticket_heap(ticket)
                        if not tkt_id in match:
                            if len(match) == 0:
                                ticket_list(short)
                            else:
                                ticket_list(", ", short)
                            match.append(tkt_id)

                    # Optionally, get tickets created on day too.
                    if show_t_open_dates is True:
                        ticket_od_list = tag.div("")
                        ticket_od_list(align="left", class_="opendate_condense")

                        for t in tickets:
                            if uts:
                                ticket_ts = to_utimestamp(t.get("time"))
                            else:
                                ticket_ts = to_timestamp(t.get("time"))
                            if ticket_ts < day_ts or ticket_ts > day_ts_eod:
                                continue

                            a_class = "opendate_"
                            tkt_id = t.get("id")
                            ticket, short = _ticket_links(env, formatter, t, a_class)
                            ticket_heap(ticket)
                            if not tkt_id in match:
                                if len(match_od) == 0:
                                    ticket_od_list(short)
                                else:
                                    ticket_od_list(", ", short)
                                match_od.append(tkt_id)

                    matches = len(match) + len(match_od)
                    if list_condense > 0 and matches >= list_condense:
                        if len(match_od) > 0:
                            if len(match) > 0:
                                ticket_list(", ")
                            ticket_list = tag(ticket_list, ticket_od_list)
                        line(cell(ticket_list))
                    else:
                        line(cell(ticket_heap))
            else:
                if name == "WikiCalendar":
                    wiki = format_date(day, wiki_page_format)
                    a_class = "day adjacent_month"
                    pages = self._wiki_link(req, args, kwargs, wiki, day.day, a_class)
                    cell = tag.td(pages, class_="day adjacent_month")
                    line(cell)
                else:
                    cell = tag.td("", class_="day adjacent_month")
                    line(cell)
            # Append completed week rows.
            if (day - first_day).days % 7 == 6:
                buff(line)
            day += timedelta(1)

        buff = tag.div(heading(buff))
        if name == "WikiTicketCalendar":
            if cal_width.startswith("+") is True:
                width = ":".join(["width", cal_width])
                buff(class_="wikitcalendar", style=width)
            else:
                buff(class_="wikitcalendar")
        if name == "WikiCalendar":
            buff(class_="wiki-calendar")
        # Add common CSS stylesheet.
        if self.internal_css and not req.args.get("wikicalendar"):
            # Put definitions directly into the output.
            f = open("/".join([self.htdocs_path, "wikicalendar.css"]), "Ur")
            css = tag.style(Markup("<!--\n"), "\n".join(f.readlines()), Markup("-->\n"))(type="text/css")
            f.close()
            # Add hint to prevent multiple inclusions.
            req.args["wikicalendar"] = True
            return tag(css, buff)
        elif not req.args.get("wikicalendar"):
            add_stylesheet(req, "wikicalendar/wikicalendar.css")
        return buff
    def render(self, ticketset):
        return_div = tag.div(class_=self.cssclass + ' projectplanrender')

        # check for missing parameters
        missingparameter = False
        if self.rows == [] or self.rows == None:
            return_div(
                tag.div(
                    'Missing parameter "rows": use a semicolon-separated list to input the "'
                    + self.rowtype + '".',
                    class_='ppwarning'))
            missingparameter = True
        if self.rowtype == None or str(self.rowtype).strip() == '':
            return_div(
                tag.div(
                    'Missing parameter "rowtype": specifies the ticket attribute that should be showed at the rows.',
                    class_='ppwarning'))
            missingparameter = True
        if self.cols == [] or self.cols == None:
            return_div(
                tag.div(
                    'Missing parameter: use a semicolon-separated list to input the "cols".',
                    class_='ppwarning'))
            missingparameter = True
        if self.coltype == None or str(self.coltype).strip() == '':
            return_div(
                tag.div(
                    'Missing parameter "coltype": specifies the ticket attribute that should be showed in the columns.',
                    class_='ppwarning'))
            missingparameter = True
        if missingparameter:
            return return_div

        #ul = tag.ul()
        #for tid in ticketset.getIDSortedList():
        #ticket = ticketset.getTicket(tid)
        #ul( tag.li(tid, " ",ticket.getfield('component') , " ", ticket.getfield('owner') ))
        #return_div(ul)
        def getstatistictitle(statusdict):
            mytitle = ''
            mysum = 0
            for status in statusdict:
                mytitle += "%s: %s\n" % (status, str(statusdict[status]))
                mysum += int(statusdict[status])
            mytitle += "%s: %s" % ('number', mysum)
            return mytitle

        def setKV(myStruct, myKey, newValue):
            '''
        shortcut to set the values correctly
        used to reduce the code needed while using a list as key of a dict
      '''
            myStruct[str(myKey)] = newValue

        def tableKeyPrettyPrint(mylist):
            '''
        transform a list of keys to a user readable string
        in: ['a','b'] --> out: 'a|b'
      '''
            return '|'.join(mylist)

        def tableKeyQueryParameter(parameter, mylist):
            '''
        transform a list of keys to a Trac query string parameter  (OR)
        in: x, ['a','b'] --> out: 'x=a&x=b'
      '''
            return '&'.join(["%s=%s" % (parameter, s) for s in mylist])

        chartheight = 80
        chartwidth = 170

        data = {}
        statistics = {}

        # init table data
        for row in self.rows:
            colstatistics = {}
            colkeys = {}
            for col in self.cols:
                # colkeys[col] = []
                setKV(colkeys, col, [])
                # colstatistics[col] = {}
                setKV(colstatistics, col, {})
            # data[row] = colkeys
            setKV(data, row, colkeys)
            # statistics[row] = colstatistics
            setKV(statistics, row, colstatistics)

        for tid in ticketset.getIDSortedList():
            ticket = ticketset.getTicket(tid)
            ticket_rowtype = ticket.getfield(self.rowtype)
            ticket_coltype = ticket.getfield(self.coltype)

            # determine the data cell where the ticket has to be added, keep in mind that rows and cols are list of lists
            for row in self.rows:
                for col in self.cols:
                    if ticket_rowtype in row and ticket_coltype in col:
                        data[str(row)][str(col)].append(
                            ticket
                        )  # save tickets at precise values of row and col
                        self.log_debug('row:%s col:%s append:%s' %
                                       (row, col, tid))

            # if ticket_rowtype in self.rows and ticket_coltype in self.cols :

        # create HTML table
        table = tag.table(class_="data pptableticketperday",
                          border="1",
                          style='width:auto;')

        # create HTML table head
        thead = tag.thead()
        tr = tag.tr()
        tr(tag.th("%s vs %s" % (self.rowtype, self.coltype)))
        for colkey in self.cols:
            tr(
                tag.th(tag.h4(
                    tag.a(tableKeyPrettyPrint(colkey),
                          href=self.macroenv.tracenv.href() +
                          ('/query?%s&order=%s' % (tableKeyQueryParameter(
                              self.coltype, colkey), self.rowtype)))),
                       title="%s is %s" %
                       (self.coltype, tableKeyPrettyPrint(colkey)))
            )  # first line with all colkeys
        if self.showsummarypiechart:
            tr(tag.th(tag.h4("Ticket Overview")))
        thead(tr)
        table(thead)

        # create HTML table body
        tbody = tag.tbody()
        counter = 0

        for rowkey in self.rows:
            # switch line color
            if counter % 2 == 1:
                class_ = 'odd'
            else:
                class_ = 'even'
            counter += 1
            tr = tag.tr(class_=class_)  # new line

            td = tag.td()  # new cell
            td(tag.h5(
                tag.a(tableKeyPrettyPrint(rowkey),
                      href=self.macroenv.tracenv.href() +
                      ('/query?%s&order=%s' % (tableKeyQueryParameter(
                          self.rowtype, rowkey), self.coltype)))),
               title="%s is %s" %
               (self.rowtype,
                tableKeyPrettyPrint(rowkey)))  # first cell contains row key
            tr(td)
            for colkey in self.cols:
                td = tag.td()
                for ticket in data[str(rowkey)][str(colkey)]:
                    td(tag.span(self.createTicketLink(ticket),
                                class_='ticket_inner'),
                       " ",
                       mytitle="%s is %s and %s is %s" %
                       (self.rowtype, rowkey, self.coltype,
                        colkey))  # mytitle might be used later by javascript
                    if not statistics[str(rowkey)][str(colkey)].has_key(
                            ticket.getstatus()):
                        statistics[str(rowkey)][str(colkey)][
                            ticket.getstatus()] = 0
                    statistics[str(rowkey)][str(colkey)][
                        ticket.getstatus()] += 1
                tr(td)

            # compute statistics
            rowstatistics = {}
            count = 0
            for colkey in statistics[str(rowkey)]:
                for status in statistics[str(rowkey)][str(colkey)]:
                    if not rowstatistics.has_key(status):
                        rowstatistics[status] = 0
                    try:
                        rowstatistics[status] += statistics[str(rowkey)][str(
                            colkey)][status]
                        count += statistics[str(rowkey)][str(colkey)][status]
                    except:
                        pass

            if self.showsummarypiechart:
                tr(
                    tag.td(tag.img(src=self.createGoogleChartFromDict(
                        'ColorForStatus',
                        rowstatistics,
                        '%s tickets' % (count, ),
                        height=chartheight)),
                           class_='ppstatistics',
                           title=getstatistictitle(rowstatistics)))  # Summary

            tbody(tr)
        table(tbody)

        # create HTML table foot
        if self.showsummarypiechart:
            fullstatistics = {}
            tfoot = tag.tfoot()
            tr = tag.tr()

            tr(tag.td(tag.h5('Ticket Overview')))

            # create statistics for col
            fullcount = 0
            for colkey in self.cols:
                colstatistics = {}
                colcount = 0
                for rowkey in self.rows:
                    for status in statistics[str(rowkey)][str(colkey)]:
                        if not fullstatistics.has_key(status):
                            fullstatistics[status] = 0
                        if not colstatistics.has_key(status):
                            colstatistics[status] = 0
                        try:
                            colstatistics[status] += statistics[str(rowkey)][
                                str(colkey)][status]
                            colcount += statistics[str(rowkey)][str(
                                colkey)][status]
                            fullstatistics[status] += statistics[str(rowkey)][
                                str(colkey)][status]
                            fullcount += statistics[str(rowkey)][str(
                                colkey)][status]
                        except:
                            pass
                tr(
                    tag.td(
                        tag.img(src=self.createGoogleChartFromDict(
                            'ColorForStatus',
                            colstatistics,
                            '%s tickets' % (colcount, ),
                            height=chartheight)),
                        title=getstatistictitle(colstatistics)))  # Col Summary
            tr(
                tag.td(
                    tag.img(src=self.createGoogleChartFromDict(
                        'ColorForStatus',
                        fullstatistics,
                        '%s tickets' % (fullcount, ),
                        height=chartheight)),
                    class_='ppstatistics',
                    title=getstatistictitle(fullstatistics)))  # Full Summary
            tfoot(tr)
            table(tfoot)

        return_div(table)

        return return_div
                tag.th(
                    tag.h4(segment, class_=myclass),
                    tag.h5(subtitle,
                           style=mystyle,
                           title=mytitle,
                           class_=myclass)))
            counttickets[segment] = 0
        if self.showsummarypiechart:
            tr(
                tag.th(
                    tag.h4('Summary', class_=myclass_org),
                    tag.h5('of all tickets',
                           style=mystyle_org,
                           title=mytitle_org,
                           class_=myclass_org)))
        table(tag.thead(tr))  # Summary

        self.macroenv.tracenv.log.debug('tickets in table: ' +
                                        repr(orderedtickets))

        # table body
        tbody = tag.tbody()
        counter = 0

        for o in self.rows:
            if counter % 2 == 1:
                class_ = 'odd'
            else:
                class_ = 'even'
            counter += 1
            tr = tag.tr(class_=class_)
Example #29
0
  def render(self, ticketset):
    '''
      Generate a HTML Table for the Fields/Extensions given
    '''
    # style overwritten to prevent browser rendering issues 
    #outer = tag.table( class_="listing pptickettable tablesorter pplisting" , style = 'width:auto;')
    outer = tag.table( class_="listing pptickettable tablesorter pplisting" , style = 'width:auto;')
    srtlist = self.keysortedids( ticketset )
    tablehead = tag.thead()
    inner = tag.tr()
    
    # TODO: problem: if the ticketset is empty, then the default rows will appear, 
    # solution: get the fields from somewhere else
    if self.allfields == True and len(ticketset.getIDList()) > 0:
      self.fields = []
      for f in (ticketset.getTicket(ticketset.getIDList()[0])).getfielddefs():
        if not ( f.lower() in self.allfieldsexclude ):
          self.fields.append( f )
    
    # generate HTML: Table head
    for f in self.fields:
      cssheaderclass = self.getcssheaderclass(f)
      if self.macroenv.get_bool_arg('showdescription', 'F') == True: # workaround for this parameter
        cssheaderclass = '{sorter: false}'
	
      self.macroenv.tracenv.log.debug('cssheaderclass of '+f+': '+cssheaderclass)
      if f in self.headermap:
        inner( tag.th( self.headermap[ f ] , title=f, class_ = cssheaderclass ) )
      else:
        inner( tag.th( f , class_ = cssheaderclass ) )
    for e in self.extensions:
      if e in self.headermap:
        inner( tag.th( self.headermap[ e ], title=e, class_ = self.getcssheaderclass(e) ) )
      else:
        inner( tag.th( e ), class_ = self.getcssheaderclass(e) )
    tablehead(inner)
    outer(tablehead)
   
   
    customdatefields = [ self.macroenv.conf.get( 'custom_due_assign_field' ), self.macroenv.conf.get( 'custom_due_close_field' ) ]
    def getSortableTableCell( f ):
      field = t.getfielddef( f, '' )
      cssclass,style = self.getcsscolstyle(f, field )
      if f == 'id':
        if t.getfielddef( 'status', '' )=='closed':
          cssclass ="ticket closed"
        else:
          cssclass ="ticket "
        text = tag.p(tag.a( '#'+str(t.getfielddef( f, '' )), href=t.getfielddef( 'href', '' ), class_ = cssclass ) )
      elif f == 'priority' : # special case 
        # two-digit integer representation of priority sorting (as definend in trac admin panel)
        text = tag.span(str(99-int(t.getfielddef( 'priority_value', '0' ))), class_ = 'invisible')+self.wiki2html(field)
      elif f in customdatefields : # special case: date string 
        text =  tag.span(self.getNormalizedDateStringOfSegment(field), class_='invisible')+self.wiki2html(field)
      else :
        text =  self.wiki2html(field)
      return (text,cssclass,style)
    
    
    
    
    # generate HTML: Table body
    _odd = True
    for k in srtlist:
      t = ticketset.getTicket( k )
      _odd = not _odd
      if _odd:
        inner = tag.tr( class_='odd' )
      else:
        inner = tag.tr( class_='even' )
      for f in self.fields:
        text,cssclass,style = getSortableTableCell(f)
        inner( tag.td( text, style = style, class_ = cssclass ) )
      for e in self.extensions:
        if t.hasextension( e ):
          cssclass,style = self.getcsscolstyle(e, t.getfielddef( e, '' ) )
          inner( tag.td( t.getextension( e ), style = style, class_ = cssclass  ) )
        else:
          #inner( tag.td( '0', title='no statement possible', class_ = 'ppinvisibletabletext' ) )
          inner( tag.td( '', title='no statement possible', class_ = 'ppinvisibletabletext' ) )
      outer(inner)
      
      # if macro parameter "showdescription" is set to True, then a long description is rendered into a second row spanning of all cols
      if _odd:
        inner2 = tag.tr( class_='odd' )
      else:
        inner2 = tag.tr( class_='even' )
      if self.macroenv.get_bool_arg('showdescription', 'F') == True:
        outer(inner2(tag.td(self.wiki2html(t.getfielddef( 'description', '' )), colspan=len(self.fields)+len(self.extensions) )))
      
      if self.limitlines>0:
        self.limitlines-=1;
        if self.limitlines<=0:
          break
    
    return outer
Example #30
0
    def expand_macro(self, formatter, name, arguments):

        self.ref = formatter
        self.tz_info = formatter.req.tz
        self.thistime = datetime.datetime.now(self.tz_info)

        # Parse arguments from macro invocation
        args, kwargs = parse_args(arguments, strict=False)

        # Find out whether use http param, current or macro param year/month
        http_param_year = formatter.req.args.get('year','')
        http_param_month = formatter.req.args.get('month','')

        if http_param_year == "":
            # not clicked on a prev or next button
            if len(args) >= 1 and args[0] <> "*":
                # year given in macro parameters
                year = int(args[0])
            else:
                # use current year
                year = self.thistime.year
        else:
            # year in http params (clicked by user) overrides everything
            year = int(http_param_year)

        if http_param_month == "":
            # not clicked on a prev or next button
            if len(args) >= 2 and args[1] <> "*":
                # month given in macro parameters
                month = int(args[1])
            else:
                # use current month
                month = self.thistime.month
        else:
            # month in http params (clicked by user) overrides everything
            month = int(http_param_month)

        showbuttons = True
        if len(args) >= 3 or kwargs.has_key('nav'):
            try:
                showbuttons = kwargs['nav'] in ["True", "true", "yes", "1"]
            except KeyError:
                showbuttons = args[2] in ["True", "true", "yes", "1"]

        wiki_page_format = "%Y-%m-%d"
        if len(args) >= 4 and args[3] != "*" or kwargs.has_key('wiki'):
            try:
                wiki_page_format = str(kwargs['wiki'])
            except KeyError:
                wiki_page_format = str(args[3])

        list_condense = 0
        show_t_open_dates = False
        wiki_page_template = ""
        wiki_subpages = []
        if name == 'WikiTicketCalendar':
            if len(args) >= 5 or kwargs.has_key('cdate'):
                try:
                    show_t_open_dates = kwargs['cdate'] in \
                                               ["True", "true", "yes", "1"]
                except KeyError:
                    show_t_open_dates = args[4] in \
                                               ["True", "true", "yes", "1"]

            # template name tried to create new pages
            # optional, default (empty page) is used, if name is invalid
            if len(args) >= 6 or kwargs.has_key('base'):
                try:
                    wiki_page_template = kwargs['base']
                except KeyError:
                    wiki_page_template = args[5]

            # TracQuery support for ticket selection
            query_args = "id!=0"
            if len(args) >= 7 or kwargs.has_key('query'):
                # prefer query arguments provided by kwargs
                try:
                    query_args = kwargs['query']
                except KeyError:
                    query_args = args[6]
            tickets = WikiCalendarTicketProvider(self.env)
            self.tickets = tickets.harvest(formatter.req, query_args)

            # compress long ticket lists
            if len(args) >= 8 or kwargs.has_key('short'):
                # prefer query arguments provided by kwargs
                try:
                    list_condense = int(kwargs['short'])
                except KeyError:
                    list_condense = int(args[7])

            # control calendar display width
            cal_width = "100%;"
            if len(args) >= 9 or kwargs.has_key('width'):
                # prefer query arguments provided by kwargs
                try:
                    cal_width = kwargs['width']
                except KeyError:
                    cal_width = args[8]

            # multiple wiki (sub)pages per day
            if kwargs.has_key('subpages'):
                wiki_subpages = kwargs['subpages'].split('|')

            # Can use this to change the day the week starts on,
            # but this is a system-wide setting.
            calendar.setfirstweekday(calendar.MONDAY)

        cal = calendar.monthcalendar(year, month)
        curr_day = None
        if year == self.thistime.year and month == self.thistime.month:
            curr_day = self.thistime.day

        # Compile regex pattern before use for better performance
        pattern_del  = '(?:<span .*?>)|(?:</span>)'
        pattern_del += '|(?:<p>)|(?:<p .*?>)|(?:</p>)'
        pattern_del += '|(?:</table>)|(?:<td.*?\n)|(?:<tr.*?</tr>)'
        self.end_RE  = re.compile('(?:</a>)')
        self.del_RE  = re.compile(pattern_del)
        self.item_RE = re.compile('(?:<img .*?>)')
        self.open_RE = re.compile('(?:<a .*?>)')
        self.tab_RE  = re.compile('(?:<table .*?>)')

        # for prev/next navigation links
        prevMonth = month - 1
        nextMonth = month + 1
        nextYear = prevYear = year
        # check for year change (KISS version)
        if prevMonth == 0:
            prevMonth = 12
            prevYear -= 1
        if nextMonth == 13:
            nextMonth = 1
            nextYear += 1

        # for fast-forward/-rewind navigation links
        ffYear = frYear = year
        if month < 4:
            frMonth = month + 9
            frYear -= 1
        else:
            frMonth = month - 3
        if month > 9:
            ffMonth = month - 9
            ffYear += 1
        else:
            ffMonth = month + 3

        last_week_prevMonth = calendar.monthcalendar(prevYear, prevMonth)[-1]
        first_week_nextMonth = calendar.monthcalendar(nextYear, nextMonth)[0]

        # Finally building the output
        # Begin with caption and optional navigation links
        buff = tag.tr()

        if showbuttons is True:
            # calendar navigation buttons
            nx = 'next'
            pv = 'prev'
            nav_pvY = self._mknav('&lt;&lt;', pv, month, year-1)
            nav_frM = self._mknav('&nbsp;&lt;', pv, frMonth, frYear)
            nav_pvM = self._mknav('&nbsp;&laquo;', pv, prevMonth, prevYear)
            nav_nxM = self._mknav('&raquo;&nbsp;', nx, nextMonth, nextYear)
            nav_ffM = self._mknav('&gt;&nbsp;', nx, ffMonth, ffYear)
            nav_nxY = self._mknav('&gt;&gt;', nx, month, year+1)

            # add buttons for going to previous months and year
            buff(nav_pvY, nav_frM, nav_pvM)

        # The caption will always be there.
        heading = tag.td(
             to_unicode(format_date(self._mkdatetime(year, month), '%B %Y')))
        buff = buff(heading(class_='y'))

        if showbuttons is True:
            # add buttons for going to next months and year
            buff(nav_nxM, nav_ffM, nav_nxY)
        buff = tag.caption(tag.table(tag.tbody(buff)))
        buff = tag.table(buff)
        if name == 'WikiTicketCalendar':
            if cal_width.startswith('+') is True:
                width=":".join(['min-width', cal_width]) 
                buff(class_='wikitcalendar', style=width, **{"data-duedatefield": self.due_field_name})
            else:
                buff(class_='wikitcalendar', **{"data-duedatefield": self.due_field_name})
        if name == 'WikiCalendar':
                buff(class_='wiki-calendar')

        heading = tag.tr()
        heading(align='center')

        for day in calendar.weekheader(2).split()[:-2]:
            col = tag.th(to_unicode(day))
            col(class_='workday', scope='col')
            heading(col)
        for day in calendar.weekheader(2).split()[-2:]:
            col = tag.th(to_unicode(day))
            col(class_='weekend', scope='col')
            heading(col)

        heading = buff(tag.thead(heading))

        # Building main calendar table body
        buff = tag.tbody()
        w = -1
        for week in cal:
            w = w + 1
            line = tag.tr()
            line(align='right')
            d = -1
            for day in week:
                d = d + 1
                if day:
                    # check for wikipage with name specified in
                    # 'wiki_page_format'
                    wiki = format_date(self._mkdatetime(year, month, day),
                                                         wiki_page_format)
                    if day == curr_day:
                        a_class = 'day today'
                        td_class = 'today'
                    else:
                        a_class = 'day'
                        td_class = 'day'

                    day_dt = self._mkdatetime(year, month, day)
                    day_ts = to_utimestamp(day_dt)
                    day_ts_eod = day_ts + 86399999999

                    # check for milestone(s) on that day
                    db = self.env.get_db_cnx()
                    cursor = db.cursor()
                    cursor.execute("""
                        SELECT name
                          FROM milestone
                         WHERE due >= %s and due <= %s
                    """, (day_ts, day_ts_eod))
                    milestone = None
                    for row in cursor:
                        if not a_class.endswith('milestone'):
                            a_class += ' milestone'
                        milestone = to_unicode(row[0])
                        url = self.env.href.milestone(milestone)
                        milestone = '* ' + milestone
                        milestone = tag.div(tag.a(milestone, href=url))
                        milestone(class_='milestone')

                    if len(wiki_subpages) > 0:
                        pages = tag(day, Markup('<br />'))
                        for page in wiki_subpages:
                            label = tag(' ', page[0])
                            page = wiki + '/' + page
                            url = self.env.href.wiki(page)
                            pages(self._gen_wiki_links(page, label, 'subpage',
                                                     url, wiki_page_template))
                    else:
                        url = self.env.href.wiki(wiki)
                        pages = self._gen_wiki_links(wiki, day, a_class,
                                                     url, wiki_page_template)
                    hours = 0
                    cell = tag.td(pages)
                    cell(class_=td_class, valign='top', **{"data-date": "%02i/%02i/%i" %(day, month, year)})
                    if name == 'WikiCalendar':
                        line(cell)
                    else:
                        if milestone:
                            cell(milestone)
                        else:
                            cell(tag.br())

                        match = []
                        match_od = []
                        ticket_heap = tag.div('', class_="tickets")
                        ticket_list = tag.div('')
                        ticket_list(align='left', class_='condense')

                        # get tickets with due date set to day
                        for t in self.tickets:
                            due = t.get(self.due_field_name)
                            if due is None or due in ['', '--']:
                                continue
                            else:
                                if self.due_field_fmt == 'ts':
                                    if not isinstance(due, datetime.datetime):
                                        continue
                                    due_ts = to_utimestamp(due)
                                    if due_ts < day_ts or \
                                        due_ts > day_ts_eod:
                                        continue
                                else:
                                    # Beware: Format might even be unicode str
                                    duedate = format_date(day_dt,
                                                      str(self.due_field_fmt))
                                    if not due == duedate:
                                        continue

                            id = t.get('id')
                            hours += float(t.get(self.hours_field_name))
                            ticket, short = self._gen_ticket_entry(t)
                            ticket_heap(ticket)
                            if not id in match:
                                if len(match) == 0:
                                    ticket_list(short)
                                else:
                                    ticket_list(', ', short)
                                match.append(id)

                        # optionally get tickets created on day
                        if show_t_open_dates is True:
                            ticket_od_list = tag.div('')
                            ticket_od_list(align='left',
                                           class_='opendate_condense')

                            for t in self.tickets:
                                ticket_ts = to_utimestamp(t.get('time'))
                                if ticket_ts < day_ts or \
                                        ticket_ts > day_ts_eod:
                                    continue

                                a_class = 'opendate_'
                                id = t.get('id')
                                hours += float(t.get(self.hours_field_name))
                                ticket, short = self._gen_ticket_entry(t,
                                                                  a_class)
                                ticket_heap(ticket)
                                if not id in match:
                                    if len(match_od) == 0:
                                        ticket_od_list(short)
                                    else:
                                        ticket_od_list(', ', short)
                                    match_od.append(id)

                        matches = len(match) + len(match_od)
                        if list_condense > 0 and matches >= list_condense:
                            if len(match_od) > 0:
                                if len(match) > 0:
                                    ticket_list(', ')
                                ticket_list = tag(ticket_list, ticket_od_list)
                            line(cell(ticket_list))
                        else:
                            line(cell(ticket_heap))
                    cell(tag.span("%dh" % hours, class_="totalhours"))
                else:
                    if name == 'WikiCalendar':
                        if w == 0:
                            day = last_week_prevMonth[d]
                            wiki = format_date(self._mkdatetime(
                                prevYear, prevMonth, day), wiki_page_format)
                        else:
                            day = first_week_nextMonth[d]
                            wiki = format_date(self._mkdatetime(
                                nextYear, nextMonth, day), wiki_page_format)
                        url = self.env.href.wiki(wiki)
                        a_class = 'day adjacent_month'
                        pages = self._gen_wiki_links(wiki, day, a_class,
                                                 url, wiki_page_template)

                        cell = tag.td(pages)
                        cell(class_='day adjacent_month')
                        line(cell)
                    else:
                        cell = tag.td('')
                        cell(class_='day adjacent_month')
                        line(cell)
            buff(line)

        buff = tag.div(heading(buff))
        if name == 'WikiTicketCalendar':
            if cal_width.startswith('+') is True:
                width=":".join(['width', cal_width]) 
                buff(class_='wikitcalendar', style=width)
            else:
                buff(class_='wikitcalendar')
        if name == 'WikiCalendar':
                buff(class_='wiki-calendar')
        # Add common CSS stylesheet
        add_stylesheet(self.ref.req, 'wikicalendar/wikicalendar.css')
        
        if self.gridmodify_enabled:
            add_script(self.ref.req, 'datefield/js/jquery-ui.js')
            add_script(self.ref.req, 'wikicalendar/wikicalendar.js')
            add_stylesheet(self.ref.req, 'datefield/css/jquery-ui.css')
            add_stylesheet(self.ref.req, 'datefield/css/ui.datepicker.css')
        
        return buff
    def expand_macro(self, formatter, name, arguments):

        self.ref = formatter
        self.tz_info = formatter.req.tz
        self.thistime = datetime.datetime.now(self.tz_info)

        # Parse arguments from macro invocation
        args, kwargs = parse_args(arguments, strict=False)

        # Find out whether use http param, current or macro param year/month
        http_param_year = formatter.req.args.get('year', '')
        http_param_month = formatter.req.args.get('month', '')

        if http_param_year == "":
            # not clicked on a prev or next button
            if len(args) >= 1 and args[0] <> "*":
                # year given in macro parameters
                year = int(args[0])
            else:
                # use current year
                year = self.thistime.year
        else:
            # year in http params (clicked by user) overrides everything
            year = int(http_param_year)

        if http_param_month == "":
            # not clicked on a prev or next button
            if len(args) >= 2 and args[1] <> "*":
                # month given in macro parameters
                month = int(args[1])
            else:
                # use current month
                month = self.thistime.month
        else:
            # month in http params (clicked by user) overrides everything
            month = int(http_param_month)

        showbuttons = True
        if len(args) >= 3 or kwargs.has_key('nav'):
            try:
                showbuttons = kwargs['nav'] in ["True", "true", "yes", "1"]
            except KeyError:
                showbuttons = args[2] in ["True", "true", "yes", "1"]

        wiki_page_format = "%Y-%m-%d"
        if len(args) >= 4 and args[3] != "*" or kwargs.has_key('wiki'):
            try:
                wiki_page_format = str(kwargs['wiki'])
            except KeyError:
                wiki_page_format = str(args[3])

        show_t_open_dates = True
        if len(args) >= 5 or kwargs.has_key('cdate'):
            try:
                show_t_open_dates = kwargs['cdate'] in \
                                               ["True", "true", "yes", "1"]
            except KeyError:
                show_t_open_dates = args[4] in ["True", "true", "yes", "1"]

        # template name tried to create new pages
        # optional, default (empty page) is used, if name is invalid
        wiki_page_template = ""
        if len(args) >= 6 or kwargs.has_key('base'):
            try:
                wiki_page_template = kwargs['base']
            except KeyError:
                wiki_page_template = args[5]

        # TracQuery support for ticket selection
        query_args = "id!=0"
        if len(args) >= 7 or kwargs.has_key('query'):
            # prefer query arguments provided by kwargs
            try:
                query_args = kwargs['query']
            except KeyError:
                query_args = args[6]
        self.tickets = self._ticket_query(formatter, query_args)

        # compress long ticket lists
        list_condense = 0
        if len(args) >= 8 or kwargs.has_key('short'):
            # prefer query arguments provided by kwargs
            try:
                list_condense = int(kwargs['short'])
            except KeyError:
                list_condense = int(args[7])

        # control calendar display width
        cal_width = "100%;"
        if len(args) >= 9 or kwargs.has_key('width'):
            # prefer query arguments provided by kwargs
            try:
                cal_width = kwargs['width']
            except KeyError:
                cal_width = args[8]

        # Can use this to change the day the week starts on,
        # but this is a system-wide setting.
        calendar.setfirstweekday(calendar.MONDAY)
        cal = calendar.monthcalendar(year, month)

        curr_day = None
        if year == self.thistime.year and month == self.thistime.month:
            curr_day = self.thistime.day

        # Compile regex pattern before use for better performance
        pattern_del = '(?:<span .*?>)|(?:</span>)'
        pattern_del += '|(?:<p>)|(?:<p .*?>)|(?:</p>)'
        pattern_del += '|(?:</table>)|(?:<td.*?\n)|(?:<tr.*?</tr>)'
        self.end_RE = re.compile('(?:</a>)')
        self.del_RE = re.compile(pattern_del)
        self.item_RE = re.compile('(?:<img .*?>)')
        self.open_RE = re.compile('(?:<a .*?>)')
        self.tab_RE = re.compile('(?:<table .*?>)')

        # for prev/next navigation links
        prevMonth = month - 1
        nextMonth = month + 1
        nextYear = prevYear = year
        # check for year change (KISS version)
        if prevMonth == 0:
            prevMonth = 12
            prevYear -= 1
        if nextMonth == 13:
            nextMonth = 1
            nextYear += 1

        # for fast-forward/-rewind navigation links
        ffYear = frYear = year
        if month < 4:
            frMonth = month + 9
            frYear -= 1
        else:
            frMonth = month - 3
        if month > 9:
            ffMonth = month - 9
            ffYear += 1
        else:
            ffMonth = month + 3

        # Finally building the output
        # Prepending inline CSS definitions
        styles = """ \
<!--
table.wikiTicketCalendar th { font-weight: bold; }
table.wikiTicketCalendar th.workday { width: 17%; }
table.wikiTicketCalendar th.weekend { width: 7%; }
table.wikiTicketCalendar caption {
    font-size: 120%; white-space: nowrap;
    }
table.wikiTicketCalendar caption a {
    display: inline; margin: 0; border: 0; padding: 0;
    background-color: transparent; color: #b00; text-decoration: none;
    }
table.wikiTicketCalendar caption a.prev { padding-right: 5px; font: bold; }
table.wikiTicketCalendar caption a.next { padding-left: 5px; font: bold; }
table.wikiTicketCalendar caption a:hover { background-color: #eee; }
table.wikiTicketCalendar td.today {
    background: #fbfbfb; border-color: #444444; color: #444;
    border-style: solid; border-width: 1px;
    }
table.wikiTicketCalendar td.day {
    background: #e5e5e5; border-color: #444444; color: #333;
    border-style: solid; border-width: 1px;
    }
table.wikiTicketCalendar td.fill {
    background: #eee; border-color: #ccc;
    border-style: solid; border-width: 1px;
    }
table.wikiTicketCalendar div.milestone {
    font-size: 9px; background: #f7f7f0; border: 1px solid #d7d7d7;
    border-bottom-color: #999; text-align: left;
    }
table.wikiTicketCalendar a.day {
    width: 2em; height: 100%; margin: 0; border: 0px; padding: 0;
    color: #333; text-decoration: none;
    }
table.wikiTicketCalendar a.day_haspage {
    width: 2em; height: 100%; margin: 0; border: 0px; padding: 0;
    color: #b00 !important; text-decoration: none;
    }
table.wikiTicketCalendar a.day:hover {
    border-color: #eee; background-color: #eee; color: #000;
    }
table.wikiTicketCalendar div.open, span.open   {
    font-size: 9px; color: #000000;
    }
table.wikiTicketCalendar div.closed, span.closed {
    font-size: 9px; color: #777777; text-decoration: line-through;
    }
table.wikiTicketCalendar div.opendate_open, span.opendate_open {
    font-size: 9px; color: #000077;
    }
table.wikiTicketCalendar div.opendate_closed, span.opendate_closed {
    font-size: 9px; color: #000077; text-decoration: line-through;
    }
table.wikiTicketCalendar div.condense { background-color: #e5e5e5; }
table.wikiTicketCalendar div.opendate_condense { background-color: #cdcdfa; }

/* pure CSS style tooltip */
a.tip {
    position: relative; cursor: help;
    }
a.tip span { display: none; }
a.tip:hover span {
    display: block; z-index: 1;
    font-size: 0.75em; text-decoration: none;
    /* big left move because of z-index render bug in IE<8 */
    position: absolute; top: 0.8em; left: 6em;
    border: 1px solid #000; background-color: #fff; padding: 5px;
    }
-->
"""

        # create inline style definition as Genshi fragment
        styles = tag.style(Markup(styles))
        styles(type='text/css')

        # Build caption and optional navigation links
        buff = tag.caption()

        if showbuttons is True:
            # calendar navigation buttons
            nx = 'next'
            pv = 'prev'
            nav_pvY = self._mknav('&nbsp;&lt;&lt;', pv, month, year - 1)
            nav_frM = self._mknav('&nbsp;&lt;&nbsp;', pv, frMonth, frYear)
            nav_pvM = self._mknav('&nbsp;&laquo;&nbsp;', pv, prevMonth,
                                  prevYear)
            nav_nxM = self._mknav('&nbsp;&raquo;&nbsp;', nx, nextMonth,
                                  nextYear)
            nav_ffM = self._mknav('&nbsp;&gt;&nbsp;', nx, ffMonth, ffYear)
            nav_nxY = self._mknav('&nbsp;&gt;&gt;', nx, month, year + 1)

            # add buttons for going to previous months and year
            buff(nav_pvY, nav_frM, nav_pvM)

        # The caption will always be there.
        buff(
            tag.strong(
                to_unicode(format_date(self._mkdatetime(year, month),
                                       '%B %Y'))))

        if showbuttons is True:
            # add buttons for going to next months and year
            buff(nav_nxM, nav_ffM, nav_nxY)

        buff = tag.table(buff)
        width = ":".join(['min-width', cal_width])
        buff(class_='wikiTicketCalendar', style=width)

        heading = tag.tr()
        heading(align='center')

        for day in calendar.weekheader(2).split()[:-2]:
            col = tag.th(day)
            col(class_='workday', scope='col')
            heading(col)
        for day in calendar.weekheader(2).split()[-2:]:
            col = tag.th(day)
            col(class_='weekend', scope='col')
            heading(col)

        heading = buff(tag.thead(heading))

        # Building main calendar table body
        buff = tag.tbody()
        for row in cal:
            line = tag.tr()
            line(align='right')
            for day in row:
                if not day:
                    cell = tag.td('')
                    cell(class_='fill')
                    line(cell)
                else:
                    # check for wikipage with name specified in
                    # 'wiki_page_format'
                    wiki = format_date(self._mkdatetime(year, month, day),
                                       wiki_page_format)
                    url = self.env.href.wiki(wiki)
                    if WikiSystem(self.env).has_page(wiki):
                        a_class = "day_haspage"
                        title = "Go to page %s" % wiki
                    else:
                        a_class = "day"
                        url += "?action=edit"
                        # adding template name, if specified
                        if wiki_page_template != "":
                            url += "&template=" + wiki_page_template
                        title = "Create page %s" % wiki
                    if day == curr_day:
                        td_class = 'today'
                    else:
                        td_class = 'day'

                    cell = tag.a(tag.b(day), href=url)
                    cell(class_=a_class, title_=title)
                    cell = tag.td(cell)
                    cell(class_=td_class, valign='top')

                    day_dt = self._mkdatetime(year, month, day)
                    if uts:
                        day_ts = to_utimestamp(day_dt)
                        day_ts_eod = day_ts + 86399999999
                    else:
                        day_ts = to_timestamp(day_dt)
                        day_ts_eod = day_ts + 86399

                    # check for milestone(s) on that day
                    db = self.env.get_db_cnx()
                    cursor = db.cursor()
                    cursor.execute(
                        """
                        SELECT name
                          FROM milestone
                         WHERE due >= %s and due <= %s
                    """, (day_ts, day_ts_eod))
                    while (1):
                        row = cursor.fetchone()
                        if row is None:
                            cell(tag.br())
                            break
                        else:
                            name = to_unicode(row[0])
                            url = self.env.href.milestone(name)
                            milestone = '* ' + name
                            milestone = tag.div(tag.a(milestone, href=url))
                            milestone(class_='milestone')

                            cell(milestone)

                    match = []
                    match_od = []
                    ticket_heap = tag('')
                    ticket_list = tag.div('')
                    ticket_list(align='left', class_='condense')

                    # get tickets with due date set to day
                    for t in self.tickets:
                        due = t.get(self.due_field_name)
                        if due is None or due in ['', '--']:
                            continue
                        else:
                            if self.due_field_fmt == 'ts':
                                if not isinstance(due, datetime.datetime):
                                    continue
                                else:
                                    if uts:
                                        due_ts = to_utimestamp(due)
                                    else:
                                        due_ts = to_timestamp(due)
                                if due_ts < day_ts or \
                                    due_ts > day_ts_eod:
                                    continue
                            else:
                                duedate = format_date(day_dt,
                                                      self.due_field_fmt)
                                if not due == duedate:
                                    continue

                        id = t.get('id')
                        ticket, short = self._gen_ticket_entry(t)
                        ticket_heap(ticket)
                        if not id in match:
                            if len(match) == 0:
                                ticket_list(short)
                            else:
                                ticket_list(', ', short)
                            match.append(id)

                    # optionally get tickets created on day
                    if show_t_open_dates is True:
                        ticket_od_list = tag.div('')
                        ticket_od_list(align='left',
                                       class_='opendate_condense')

                        for t in self.tickets:
                            if uts:
                                ticket_ts = to_utimestamp(t.get('time'))
                            else:
                                ticket_ts = to_timestamp(t.get('time'))
                            if ticket_ts < day_ts or ticket_ts > day_ts_eod:
                                continue

                            a_class = 'opendate_'
                            id = t.get('id')
                            ticket, short = self._gen_ticket_entry(t, a_class)
                            ticket_heap(ticket)
                            if not id in match:
                                if len(match_od) == 0:
                                    ticket_od_list(short)
                                else:
                                    ticket_od_list(', ', short)
                                match_od.append(id)

                    matches = len(match) + len(match_od)
                    if list_condense > 0 and matches >= list_condense:
                        if len(match_od) > 0:
                            if len(match) > 0:
                                ticket_list(', ')
                            ticket_list = tag(ticket_list, ticket_od_list)
                        line(cell(ticket_list))
                    else:
                        line(cell(ticket_heap))

            buff(line)

        buff = tag.div(heading(buff))
        if cal_width.startswith('+') is True:
            width = ":".join(['width', cal_width])
            buff(class_='wikiTicketCalendar', style=width)
        else:
            buff(class_='wikiTicketCalendar')

        # Finally prepend prepared CSS styles
        buff = tag(styles, buff)

        return buff
Example #32
0
    def filter_stream(self, req, method, filename, stream, data):

        # Tickets will be modified to show the child tickets as a list under the 'Description' section.
        if filename == 'ticket.html':

            # Add our own styles for the ticket lists.
            add_stylesheet(req, 'ct/css/childtickets.css')

            # Get the ticket info.
            ticket = data.get('ticket')

            # Modify ticket.html with sub-ticket table, create button, etc...
            # As follows:
            # - If ticket has no child tickets and child tickets are NOT allowed then skip.
            # - If ticket has child tickets and child tickets are NOT allowed (ie. rules changed or ticket type changed after children were assigned),
            #   print list of tickets but do not allow any tickets to be created.
            # - If child tickets are allowed then print list of child tickets or 'No Child Tickets' if non are currently assigned.
            # 
            if ticket and ticket.exists:

                # The additional section on the ticket is built up of (potentially) three parts: header, ticket table, buttons. These
                # are all 'wrapped up' in a 'div' with the 'attachments' id (we'll just pinch this to make look and feel consistent with any
                # future changes!)
                filter = Transformer('//div[@id="ticket"]')
                snippet = tag.div()

                # Are there any child tickets to display?
                childtickets = [ Ticket(self.env,n) for n in self.childtickets.get(ticket.id,[]) ]

                # (tempish) fix for #8612 : force sorting by ticket id
                childtickets = sorted(childtickets, key=lambda t: t.id)

                # Are child tickets allowed?
                childtickets_allowed = self.config.getbool('childtickets', 'parent.%s.allow_child_tickets' % ticket['type'])

                # If there are no childtickets and the ticket should not have any child tickets, we can simply drop out here.
                if not childtickets_allowed and not childtickets:
                    return stream

                # Our 'main' display consists of two divs.
                buttondiv = tag.div()
                tablediv = tag.div()

                # Test if the ticket has children: If so, then list in pretty table.
                if childtickets:

                    # trac.ini : Which columns to display in child ticket listing?
                    columns = self.config.getlist('childtickets', 'parent.%s.table_headers' % ticket['type'], default=['summary','owner'])

                    tablediv = tag.div(
                                tag.table(
                                    tag.thead(
                                        tag.tr(
                                            tag.th("Ticket",class_="id"),
                                            [ tag.th(s.title(),class_=s) for s in columns ])
                                        ),
                                    tag.tbody([ self._table_row(req,tkt,columns) for tkt in childtickets ]),
                                    class_="listing tickets",
                                    ),
                                tag.br(),
                                )

                # trac.ini : child tickets are allowed - Set up 'create new ticket' buttons.
                if childtickets_allowed:

                    # Can user create a new ticket? If not, just display title (ie. no 'create' button).
                    if 'TICKET_CREATE' in req.perm(ticket.resource):

                        # Always pass these fields
                        default_child_fields = (
                                tag.input(type="hidden", name="parent", value='#'+str(ticket.id)),
                                )

                        #Pass extra fields defined in inherit parameter of parent
                        inherited_child_fields = [
                                tag.input(type="hidden",name="%s"%field,value=ticket[field]) for field in self.config.getlist('childtickets','parent.%s.inherit' % ticket['type'])
                                ]

                        # If child types are restricted then create a set of buttons for the allowed types (This will override 'default_child_type).
                        restrict_child_types = self.config.getlist('childtickets','parent.%s.restrict_child_type' % ticket['type'],default=[])

                        if not restrict_child_types:
                            # trac.ini : Default 'type' of child tickets?
                            default_child_type = self.config.get('childtickets', 'parent.%s.default_child_type' % ticket['type'], default=self.config.get('ticket','default_type'))

                            # ... create a default submit button
                            if ticket['status'] == 'closed':
                                submit_button_fields = (
                                        tag.input(type="submit",disabled="disabled",name="childticket",value="New Child Ticket",title="Create a child ticket"),
                                        tag.input(type="hidden", name="type", value=default_child_type),
                                        )
                            else:
                                submit_button_fields = (
                                        tag.input(type="submit",name="childticket",value="New Child Ticket",title="Create a child ticket"),
                                        tag.input(type="hidden",name="type",value=default_child_type),
                                        )
                        else:
                            if ticket['status'] == 'closed':
                                submit_button_fields = [ tag.input(type="submit",disabled="disabled",name="type",value="%s" % ticket_type,title="Create a %s child ticket" % ticket_type) for ticket_type in restrict_child_types ]
                            else:
                                submit_button_fields = [ tag.input(type="submit",name="type",value="%s" % ticket_type,title="Create a %s child ticket" % ticket_type) for ticket_type in restrict_child_types ]
                        buttondiv = tag.form(
                                    tag.div( default_child_fields, inherited_child_fields, submit_button_fields),
                                    method="get", action=req.href.newticket(),
                                    )

                snippet.append(tag.h2("Child Tickets",class_="foldable"))
                snippet.append(tag.div(tablediv, buttondiv, id="childtickets"))

                return stream | filter.after(snippet)

        return stream
Example #33
0
    def render(self, ticketset):
        # add needed javascript and css files
        self.addJsChartFiles()

        if self.firstsegment == None or self.lastsegment == None:
            return self.divWarning(
                'you have to set the time period via the macro parameters. Example: first=2012-02-03, last=2012-02-19 .'
            )

        tickets = ticketset.getIDList()

        # stop if no tickets available
        if len(tickets) == 0:
            return self.divWarning('No tickets available.')

        changes = {}
        initalvalues = {}
        creationdates = {}

        (firstday, lastday) = self.getBoundaries({})
        alldates = self.getAllRelevantDates(firstday, lastday)

        lastdaySecs = lastday
        firstday = self.normalizeToDay(firstday)
        lastday = self.normalizeToDay(lastday)

        (ticketCount, relevantChanges) = self.computeInformationAboutSegment(
            ticketset, firstday, lastday)

        # count only the tickets that are relevant within the requested time period (firstday,lastday)
        relevantTickets = ticketCount
        closedTickets = {}  # change this
        openTickets = {}  # change this
        changeDateStrings = relevantChanges.keys()
        changeDateStrings.sort()
        # ticketCount = 70 # DEBUG

        for changeDateStr in changeDateStrings:  # for each day
            self.macroenv.tracenv.log.debug(
                "changes %4s: %3s (%s)" %
                (changeDateStr, relevantChanges[changeDateStr], ticketCount))
            self.setKeyIfNotExistsInt(closedTickets, changeDateStr,
                                      -1 * relevantChanges[changeDateStr])
            ticketCount = ticketCount + relevantChanges[
                changeDateStr]  # reduce the number of open tickets
            self.setKeyIfNotExistsInt(openTickets, changeDateStr, ticketCount)

        # generate HTML
        holderid = "%s_%s_%d_%d" % (
            self.getNameOfRenderFrame(), 'holder', int(time.time() * 1000000),
            random.randint(1, 1024))  # compute unique element id
        currentday = firstday
        frame = tag.div(class_='invisible ppConfBurnDown',
                        id=self.getNameOfRenderFrame() + holderid)
        tableData = tag.table(class_="invisible data",
                              border="1",
                              style='width:auto;')
        trDays = tag.tr()
        trDaysAxis = tag.tr()
        trOpenTickets = tag.tr()
        trClosedTickets = tag.tr()
        trReopenedTickets = tag.tr()
        alldates.sort()
        lastOpenTicket = relevantTickets  # fallback: all tickets
        lastClosedTickets = 0
        counter = 0
        todaySecs = self.datetime2seconds(datetime.datetime.today())
        todayStr = self.getDateString(todaySecs)
        todayid = 0
        maxValue = 0
        if lastdaySecs <= todaySecs:  # if today is later then the shown time frame then mark the last column
            todayid = len(alldates)
        for currentday in alldates:
            if currentday == todayStr:  # capture the column with the current date
                todayid = counter
            counter = counter + 1
            trDays(
                tag.th(currentday.replace("\n", " "))
            )  # text for info box, no line breaks here, because it is limited to 3 lines
            trDaysAxis(tag.th(currentday))
            if openTickets.has_key(currentday):
                lastOpenTicket = openTickets[currentday]
            trOpenTickets(tag.td(lastOpenTicket))
            if closedTickets.has_key(currentday):
                lastClosedTickets = closedTickets[currentday]
            else:
                lastClosedTickets = 0
            trClosedTickets(tag.td(lastClosedTickets))
            maxValue = max(len(str(lastClosedTickets)),
                           len(str(lastOpenTicket)), maxValue)
            trReopenedTickets(tag.td('0'))

        tableData(tag.thead(trDays))
        tableData(tag.tfoot(trDaysAxis))
        tableData(tag.tbody(trOpenTickets, trClosedTickets, trReopenedTickets))

        (label1, label2) = self.getLabel()

        # caculate the scale factor for the info box within the chart
        maxGlobal = max(
            len(str(label1)) + maxValue,
            len(str(label2)) + maxValue)
        if self.segment in ['week', 'twoweek'
                            ]:  # they use long descriptions in the info box
            maxGlobal = max(maxGlobal, 27)

        # configuration of renderer
        frame(tag.div(str(relevantTickets), class_='maxTasks'))
        frame(tag.div(self.width, class_='width'))
        frame(tag.div(self.height, class_='height'))
        frame(tag.div(str(maxGlobal), class_='maxlength'))
        frame(tag.div(label1, class_='label1'))
        frame(tag.div(label2, class_='label2'))
        frame(
            tag.div(str(todayid),
                    class_='today'))  # number of column with the current date
        frame(tag.div(holderid, class_='holder'))  # where to put the chart in

        frame(tableData)
        outerframe = tag.div()  # div as global container
        #outerframe(outer) # DEBUG
        outerframe(frame)
        outerframe(tag.div(id=holderid), style="border-width:1px")
        return outerframe
Example #34
0
        def _body_rows():
            for idx, line in enumerate(_group_lines(stream)):
                row = tag.tr()
                if marks and idx + 1 in marks:
                    row(class_='hilite')
                for annotator, data in annotator_datas:
                    if annotator:
                        annotator.annotate_row(context, row, idx+1, line, data)
                    else:
                        row.append(tag.td())
                row.append(tag.td(line))
                yield row

        return tag.table(class_='code')(
            tag.thead(_head_row()),
            tag.tbody(_body_rows())
        )

    def get_max_preview_size(self):
        """:deprecated: use `max_preview_size` attribute directly."""
        return self.max_preview_size

    def get_charset(self, content='', mimetype=None):
        """Infer the character encoding from the `content` or the `mimetype`.

        `content` is either a `str` or an `unicode` object.
        
        The charset will be determined using this order:
         * from the charset information present in the `mimetype` argument
         * auto-detection of the charset from the `content`
Example #35
0
    def expand_macro(self, formatter, name, arguments):

        self.ref = formatter
        self.tz_info = formatter.req.tz
        self.thistime = datetime.datetime.now(self.tz_info)

        # Add CSS stylesheet
        add_stylesheet(self.ref.req,
            'wikiticketcalendar/css/wikiticketcalendar.css')


        # Parse arguments from macro invocation
        args, kwargs = parse_args(arguments, strict=False)

        # Find out whether use http param, current or macro param year/month
        http_param_year = formatter.req.args.get('year','')
        http_param_month = formatter.req.args.get('month','')

        if http_param_year == "":
            # not clicked on a prev or next button
            if len(args) >= 1 and args[0] <> "*":
                # year given in macro parameters
                year = int(args[0])
            else:
                # use current year
                year = self.thistime.year
        else:
            # year in http params (clicked by user) overrides everything
            year = int(http_param_year)

        if http_param_month == "":
            # not clicked on a prev or next button
            if len(args) >= 2 and args[1] <> "*":
                # month given in macro parameters
                month = int(args[1])
            else:
                # use current month
                month = self.thistime.month
        else:
            # month in http params (clicked by user) overrides everything
            month = int(http_param_month)

        showbuttons = True
        if len(args) >= 3 or kwargs.has_key('nav'):
            try:
                showbuttons = kwargs['nav'] in ["True", "true", "yes", "1"]
            except KeyError:
                showbuttons = args[2] in ["True", "true", "yes", "1"]

        wiki_page_format = "%Y-%m-%d"
        if len(args) >= 4 and args[3] != "*" or kwargs.has_key('wiki'):
            try:
                wiki_page_format = str(kwargs['wiki'])
            except KeyError:
                wiki_page_format = str(args[3])

        show_t_open_dates = True
        if len(args) >= 5 or kwargs.has_key('cdate'):
            try:
                show_t_open_dates = kwargs['cdate'] in \
                                               ["True", "true", "yes", "1"]
            except KeyError:
                show_t_open_dates = args[4] in ["True", "true", "yes", "1"]

        # template name tried to create new pages
        # optional, default (empty page) is used, if name is invalid
        wiki_page_template = ""
        if len(args) >= 6 or kwargs.has_key('base'):
            try:
                wiki_page_template = kwargs['base']
            except KeyError:
                wiki_page_template = args[5]

        # TracQuery support for ticket selection
        query_args = "id!=0"
        if len(args) >= 7 or kwargs.has_key('query'):
            # prefer query arguments provided by kwargs
            try:
                query_args = kwargs['query']
            except KeyError:
                query_args = args[6]
        self.tickets = self._ticket_query(formatter, query_args)

        # compress long ticket lists
        list_condense = 0
        if len(args) >= 8 or kwargs.has_key('short'):
            # prefer query arguments provided by kwargs
            try:
                list_condense = int(kwargs['short'])
            except KeyError:
                list_condense = int(args[7])

        # control calendar display width
        cal_width = "100%;"
        if len(args) >= 9 or kwargs.has_key('width'):
            # prefer query arguments provided by kwargs
            try:
                cal_width = kwargs['width']
            except KeyError:
                cal_width = args[8]


        # Can use this to change the day the week starts on,
        # but this is a system-wide setting.
        calendar.setfirstweekday(calendar.MONDAY)
        cal = calendar.monthcalendar(year, month)

        curr_day = None
        if year == self.thistime.year and month == self.thistime.month:
            curr_day = self.thistime.day

        # Compile regex pattern before use for better performance
        pattern_del  = '(?:<span .*?>)|(?:</span>)'
        pattern_del += '|(?:<p>)|(?:<p .*?>)|(?:</p>)'
        pattern_del += '|(?:</table>)|(?:<td.*?\n)|(?:<tr.*?</tr>)'
        self.end_RE  = re.compile('(?:</a>)')
        self.del_RE  = re.compile(pattern_del)
        self.item_RE = re.compile('(?:<img .*?>)')
        self.open_RE = re.compile('(?:<a .*?>)')
        self.tab_RE  = re.compile('(?:<table .*?>)')

        # for prev/next navigation links
        prevMonth = month - 1
        nextMonth = month + 1
        nextYear = prevYear = year
        # check for year change (KISS version)
        if prevMonth == 0:
            prevMonth = 12
            prevYear -= 1
        if nextMonth == 13:
            nextMonth = 1
            nextYear += 1

        # for fast-forward/-rewind navigation links
        ffYear = frYear = year
        if month < 4:
            frMonth = month + 9
            frYear -= 1
        else:
            frMonth = month - 3
        if month > 9:
            ffMonth = month - 9
            ffYear += 1
        else:
            ffMonth = month + 3


        # Finally building the output
        # Begin with caption and optional navigation links
        buff = tag.caption()

        if showbuttons is True:
            # calendar navigation buttons
            nx = 'next'
            pv = 'prev'
            nav_pvY = self._mknav('&nbsp;&lt;&lt;', pv, month, year-1)
            nav_frM = self._mknav('&nbsp;&lt;&nbsp;', pv, frMonth, frYear)
            nav_pvM = self._mknav('&nbsp;&laquo;&nbsp;', pv, prevMonth,
                                                                 prevYear)
            nav_nxM = self._mknav('&nbsp;&raquo;&nbsp;', nx, nextMonth,
                                                                 nextYear)
            nav_ffM = self._mknav('&nbsp;&gt;&nbsp;', nx, ffMonth, ffYear)
            nav_nxY = self._mknav('&nbsp;&gt;&gt;', nx, month, year+1)

            # add buttons for going to previous months and year
            buff(nav_pvY, nav_frM, nav_pvM)

        # The caption will always be there.
        buff(tag.strong(to_unicode(format_date(self._mkdatetime(
                                               year, month), '%B %Y'))))

        if showbuttons is True:
            # add buttons for going to next months and year
            buff(nav_nxM, nav_ffM, nav_nxY)

        buff = tag.table(buff)
        width=":".join(['min-width', cal_width]) 
        buff(class_='wikiTicketCalendar', style=width)

        heading = tag.tr()
        heading(align='center')

        for day in calendar.weekheader(2).split()[:-2]:
            col = tag.th(day)
            col(class_='workday', scope='col')
            heading(col)
        for day in calendar.weekheader(2).split()[-2:]:
            col = tag.th(day)
            col(class_='weekend', scope='col')
            heading(col)

        heading = buff(tag.thead(heading))

        # Building main calendar table body
        buff = tag.tbody()
        for row in cal:
            line = tag.tr()
            line(align='right')
            for day in row:
                if not day:
                    cell = tag.td('')
                    cell(class_='fill')
                    line(cell)
                else:
                    # check for wikipage with name specified in
                    # 'wiki_page_format'
                    wiki = format_date(self._mkdatetime(year, month, day),
                                                         wiki_page_format)
                    url = self.env.href.wiki(wiki)
                    if WikiSystem(self.env).has_page(wiki):
                        a_class = "day_haspage"
                        title = _("Go to page %s") % wiki
                    else:
                        a_class = "day"
                        url += "?action=edit"
                        # adding template name, if specified
                        if wiki_page_template != "":
                            url += "&template=" + wiki_page_template
                        title = _("Create page %s") % wiki
                    if day == curr_day:
                        td_class = 'today'
                    else:
                        td_class = 'day'

                    cell = tag.a(tag.b(day), href=url)
                    cell(class_=a_class, title_=title)
                    cell = tag.td(cell)
                    cell(class_=td_class, valign='top')

                    day_dt = self._mkdatetime(year, month, day)
                    day_ts = to_utimestamp(day_dt)
                    day_ts_eod = day_ts + 86399999999

                    # check for milestone(s) on that day
                    db = self.env.get_db_cnx()
                    cursor = db.cursor()
                    cursor.execute("""
                        SELECT name
                          FROM milestone
                         WHERE due >= %s and due <= %s
                    """, (day_ts, day_ts_eod))
                    while (1):
                        row = cursor.fetchone()
                        if row is None:
                            cell(tag.br())
                            break
                        else:
                            name = to_unicode(row[0])
                            url = self.env.href.milestone(name)
                            milestone = '* ' + name
                            milestone = tag.div(tag.a(milestone, href=url))
                            milestone(class_='milestone')

                            cell(milestone)

                    match = []
                    match_od = []
                    ticket_heap = tag('')
                    ticket_list = tag.div('')
                    ticket_list(align='left', class_='condense')

                    # get tickets with due date set to day
                    for t in self.tickets:
                        due = t.get(self.due_field_name)
                        if due is None or due in ['', '--']:
                            continue
                        else:
                            if self.due_field_fmt == 'ts':
                                if not isinstance(due, datetime.datetime):
                                    continue
                                due_ts = to_utimestamp(due)
                                if due_ts < day_ts or \
                                    due_ts > day_ts_eod:
                                    continue
                            else:
                                duedate = format_date(day_dt,
                                                      self.due_field_fmt)
                                if not due == duedate:
                                    continue

                        id = t.get('id')
                        ticket, short = self._gen_ticket_entry(t)
                        ticket_heap(ticket)
                        if not id in match:
                            if len(match) == 0:
                                ticket_list(short)
                            else:
                                ticket_list(', ', short)
                            match.append(id)

                    # optionally get tickets created on day
                    if show_t_open_dates is True:
                        ticket_od_list = tag.div('')
                        ticket_od_list(align='left',
                                       class_='opendate_condense')

                        for t in self.tickets:
                            ticket_ts = to_utimestamp(t.get('time'))
                            if ticket_ts < day_ts or ticket_ts > day_ts_eod:
                                continue

                            a_class = 'opendate_'
                            id = t.get('id')
                            ticket, short = self._gen_ticket_entry(t, a_class)
                            ticket_heap(ticket)
                            if not id in match:
                                if len(match_od) == 0:
                                    ticket_od_list(short)
                                else:
                                    ticket_od_list(', ', short)
                                match_od.append(id)

                    matches = len(match) + len(match_od)
                    if list_condense > 0 and matches >= list_condense:
                        if len(match_od) > 0:
                            if len(match) > 0:
                                ticket_list(', ')
                            ticket_list = tag(ticket_list, ticket_od_list)
                        line(cell(ticket_list))
                    else:
                        line(cell(ticket_heap))

            buff(line)

        buff = tag.div(heading(buff))
        if cal_width.startswith('+') is True:
            width=":".join(['width', cal_width]) 
            buff(class_='wikiTicketCalendar', style=width)
        else:
            buff(class_='wikiTicketCalendar')

        return buff
Example #36
0
     calendar[segment]['date'] = consideredDate
     subtitle = weekdays[calendar[segment]['isocalendar'][2]] + ', week '+str(calendar[segment]['isocalendar'][1])
     if consideredDate == currentDate:
       myclass = 'today' # overwrite
   except Exception,e:
     self.macroenv.tracenv.log.error(str(e)+' '+segment)
     calendar[segment]['isocalendar'] = (None, None, None)
     calendar[segment]['date'] = None
     subtitle = "--"
     mystyle = 'color:#000;'
     mytitle = 'date could not be resolved'
   tr(tag.th(tag.h4(segment, class_ = myclass ), tag.h5( subtitle, style = mystyle, title = mytitle, class_ = myclass  ))) 
   counttickets[segment] = 0
 if self.showsummarypiechart:
   tr(tag.th(tag.h4('Summary', class_ = myclass_org ), tag.h5( 'of all tickets', style = mystyle_org, title = mytitle_org, class_ = myclass_org ))) 
 table(tag.thead(tr)) # Summary
 
 self.macroenv.tracenv.log.debug('tickets in table: '+repr(orderedtickets))
 
 
 # table body
 tbody = tag.tbody()
 counter=0
 
 for o in self.rows:
   if counter % 2 == 1:
     class_ = 'odd'
   else:
     class_ = 'even'
   counter += 1
   tr = tag.tr(class_ = class_)
Example #37
0
    def ListOfWikiPages(self, formatter, content):
        """
== Description ==

Website: http://trac-hacks.org/wiki/ListOfWikiPagesMacro

`$Id$`

The macro `ListOfWikiPages` prints a table of all (user generated, i.e. 
non-trac-default) wiki pages with last changed date and author as requested in 
Request-a-Hack th:#2427.
Version 0.2 provides also a long format which also includes the newest version 
number and links to the difference and the history as well as the last comment.  
This was requested by th:#4717.

The second macro provided by this package is `LastChangesBy` which prints the 
last changes made by the given user or the logged-in user if no username is 
given. 

== Usage ==

You can use the `ListOfWikiPages` macro like this:
{{{
[[ListOfWikiPages]]                     # default format as configured in the config file
[[ListOfWikiPages(format=short)]]       # short format
[[ListOfWikiPages(format=long)]]        # long format (new v0.2)
}}}
which prints a table of all wiki pages, or with a list of wiki pages:
{{{
[[ListOfWikiPages(ThatWikiPage,ThisWikiPage,AnotherWikiPage,format=...)]]
}}}

Since v0.3 the optional arguments `from` and `to` can be used to specify a 
time/date range as requested by th:#5344.
The values of this arguments are taken as negative offsets to the current time 
(i.e. the time the wiki page is displayed).
Allowed is a number followed by a unit which can be `s`,`m`,`h`,`d`,`w`,`o`,`y` 
for seconds, minutes, hours, days, weeks, month and years.
If the unit is missing seconds are assumed.

{{{
[[ListOfWikiPages(from=3d)]]            # displays all wiki pages changed in the last three days
[[ListOfWikiPages(to=15m)]]             # displays all wiki pages was where changed longer than 15 minutes ago
[[ListOfWikiPages(from=4.5w,to=15h)]]   # displays all wiki pages was where changed between 4 1/2 week and 15 hours ago
}}}

A headline can be given using a `headline` argument:
{{{
[[ListOfWikiPages(headline=Headline text without any comma)]]     # sets a table headline, may not contain '`,`'
}}}

The order can be reversed, i.e. list the oldest wikis first, using:
{{{
[[ListOfWikiPages(order=reverse)]]
}}}

Unwanted wiki ranges (e.g. `Trac*`) can be excluded by the `exclude=pattern` option which can be given multiple times.
The wildcards '`*`' (matches everything) and '`?`' (matches a single character) can be used in the pattern. (Requested by #6074)
{{{
[[ListOfWikiPages(exclude=Trac*,exclude=abc?)]]
}}}

        """
        largs, kwargs = parse_args(content, multi=['exclude'])

        self.href = formatter.req.href

        long_format = self.default_format.lower() == 'long'
        if 'format' in kwargs:
            long_format = kwargs['format'].lower() == 'long'
        self.long_format = long_format

        db = self.env.get_db_cnx()
        cursor = db.cursor()
        #cursor.log = self.env.log

        sql_wikis = ''
        if largs:
            sql_wikis = self._get_sql_include(largs)

        sql_exclude = ''
        if 'exclude' in kwargs:
            sql_exclude = self._get_sql_exclude(kwargs['exclude'])

        self.kwargs = kwargs
        dfrom, fromtext = self.timeval('from', (0, ''))
        dto, totext = self.timeval('to', (int(unixtime()), ''))

        if 'from' in kwargs or 'to' in kwargs:
            sql_time = " time BETWEEN %d AND %d AND " % (dfrom, dto)
        else:
            sql_time = ''

        if kwargs.get('order', 'normal') == 'reverse':
            order = " "
        else:
            order = " DESC "

        sqlcmd = \
            "SELECT name,time,author,version,comment FROM wiki AS w1 WHERE " \
            + sql_time + \
            "author NOT IN ('%s') "  % "','".join( self.ignore_users ) + sql_wikis + sql_exclude + \
            "AND version=(SELECT MAX(version) FROM wiki AS w2 WHERE w1.name=w2.name) ORDER BY time " + \
            order
        cursor.execute(sqlcmd)

        rows = [
            self.formatrow(n, name, time, version, comment, author)
            for n, [name, time, author, version, comment] in enumerate(cursor)
        ]

        if self.long_format:
            cols = ("WikiPage", "Last Changed At", "By", "Version", "Diff",
                    "History", "Comment")
        else:
            cols = ("WikiPage", "Last Changed At", "By")

        if 'headline' in kwargs:
            headlinetag = tag.tr(tag.th(kwargs['headline'], colspan=len(cols)))
        else:
            headlinetag = tag()

        head = tag.thead(
            headlinetag,
            tag.tr(
                map(lambda x: tag.th(x, class_=x.replace(" ", "").lower()),
                    cols)))
        table = tag.table(head, rows, class_='listofwikipages')

        self.href = None
        return table
Example #38
0
    def ListOfWikiPages(self, formatter, content):
        """
== Description ==

Website: http://trac-hacks.org/wiki/ListOfWikiPagesMacro

`$Id$`

The macro `ListOfWikiPages` prints a table of all (user generated, i.e. 
non-trac-default) wiki pages with last changed date and author as requested in 
Request-a-Hack th:#2427.
Version 0.2 provides also a long format which also includes the newest version 
number and links to the difference and the history as well as the last comment.  
This was requested by th:#4717.

The second macro provided by this package is `LastChangesBy` which prints the 
last changes made by the given user or the logged-in user if no username is 
given. 

== Usage ==

You can use the `ListOfWikiPages` macro like this:
{{{
[[ListOfWikiPages]]                     # default format as configured in the config file
[[ListOfWikiPages(format=short)]]       # short format
[[ListOfWikiPages(format=long)]]        # long format (new v0.2)
}}}
which prints a table of all wiki pages, or with a list of wiki pages:
{{{
[[ListOfWikiPages(ThatWikiPage,ThisWikiPage,AnotherWikiPage,format=...)]]
}}}

Since v0.3 the optional arguments `from` and `to` can be used to specify a 
time/date range as requested by th:#5344.
The values of this arguments are taken as negative offsets to the current time 
(i.e. the time the wiki page is displayed).
Allowed is a number followed by a unit which can be `s`,`m`,`h`,`d`,`w`,`o`,`y` 
for seconds, minutes, hours, days, weeks, month and years.
If the unit is missing seconds are assumed.

{{{
[[ListOfWikiPages(from=3d)]]            # displays all wiki pages changed in the last three days
[[ListOfWikiPages(to=15m)]]             # displays all wiki pages was where changed longer than 15 minutes ago
[[ListOfWikiPages(from=4.5w,to=15h)]]   # displays all wiki pages was where changed between 4 1/2 week and 15 hours ago
}}}

A headline can be given using a `headline` argument:
{{{
[[ListOfWikiPages(headline=Headline text without any comma)]]     # sets a table headline, may not contain '`,`'
}}}

The order can be reversed, i.e. list the oldest wikis first, using:
{{{
[[ListOfWikiPages(order=reverse)]]
}}}

Unwanted wiki ranges (e.g. `Trac*`) can be excluded by the `exclude=pattern` option which can be given multiple times.
The wildcards '`*`' (matches everything) and '`?`' (matches a single character) can be used in the pattern. (Requested by #6074)
{{{
[[ListOfWikiPages(exclude=Trac*,exclude=abc?)]]
}}}

        """
        largs, kwargs = parse_args( content, multi = ['exclude'] )

        self.href = formatter.req.href

        long_format = self.default_format.lower() == 'long'
        if 'format' in kwargs:
          long_format = kwargs['format'].lower() == 'long'
        self.long_format = long_format

        db = self.env.get_db_cnx()
        cursor = db.cursor()
        #cursor.log = self.env.log

        sql_wikis = ''
        if largs:
          sql_wikis = self._get_sql_include(largs)

        sql_exclude = ''
        if 'exclude' in kwargs:
          sql_exclude = self._get_sql_exclude(kwargs['exclude'])

        self.kwargs = kwargs
        dfrom, fromtext = self.timeval('from', (0,''))
        dto, totext     = self.timeval('to',   (int(unixtime()),''))

        if 'from' in kwargs or 'to' in kwargs:
          sql_time = " time BETWEEN %d AND %d AND " % (dfrom,dto)
        else:
          sql_time = ''

        if kwargs.get('order','normal') == 'reverse':
          order = " "
        else:
          order = " DESC "

        sqlcmd = \
            "SELECT name,time,author,version,comment FROM wiki AS w1 WHERE " \
            + sql_time + \
            "author NOT IN ('%s') "  % "','".join( self.ignore_users ) + sql_wikis + sql_exclude + \
            "AND version=(SELECT MAX(version) FROM wiki AS w2 WHERE w1.name=w2.name) ORDER BY time " + \
            order
        cursor.execute(sqlcmd)

        rows = [ self.formatrow(n,name,time,version,comment,author)
              for n,[name,time,author,version,comment] in enumerate(cursor) ]

        if self.long_format:
          cols = ( "WikiPage", "Last Changed At", "By",
                   "Version", "Diff", "History", "Comment" )
        else:
          cols = ( "WikiPage", "Last Changed At", "By" )

        if 'headline' in kwargs:
          headlinetag = tag.tr( tag.th( kwargs['headline'],
            colspan = len(cols) ) )
        else:
          headlinetag = tag()

        head  = tag.thead ( headlinetag, tag.tr(
          map(lambda x: tag.th(x, class_=x.replace(" ", "").lower() ), cols) ) )
        table = tag.table ( head, rows, class_ = 'listofwikipages' )

        self.href = None
        return table
Example #39
0
        def _body_rows():
            for idx, line in enumerate(_group_lines(stream)):
                row = tag.tr()
                if marks and idx + 1 in marks:
                    row(class_='hilite')
                for annotator, data in annotator_datas:
                    if annotator:
                        annotator.annotate_row(context, row, idx + 1, line,
                                               data)
                    else:
                        row.append(tag.td())
                row.append(tag.td(line))
                yield row

        return tag.table(class_='code')(tag.thead(_head_row()),
                                        tag.tbody(_body_rows()))

    def get_max_preview_size(self):
        """:deprecated: use `max_preview_size` attribute directly."""
        return self.max_preview_size

    def get_charset(self, content='', mimetype=None):
        """Infer the character encoding from the `content` or the `mimetype`.

        `content` is either a `str` or an `unicode` object.
        
        The charset will be determined using this order:
         * from the charset information present in the `mimetype` argument
         * auto-detection of the charset from the `content`
         * the configured `default_charset` 
Example #40
0
  def render(self, ticketset):
    # add needed javascript and css files
    self.addJsChartFiles()
    
    if self.firstsegment == None or self.lastsegment == None:
      return self.divWarning('you have to set the time period via the macro parameters. Example: first=2012-02-03, last=2012-02-19 .')
    
    tickets = ticketset.getIDList()
    
    # stop if no tickets available
    if len(tickets) == 0:
      return self.divWarning('No tickets available.')
    
    changes = {}    
    initalvalues = {}
    creationdates = {}
    
    (firstday,lastday) = self.getBoundaries({})
    alldates = self.getAllRelevantDates(firstday, lastday)

    lastdaySecs = lastday
    firstday = self.normalizeToDay(firstday)
    lastday = self.normalizeToDay(lastday)

    (ticketCount, relevantChanges) = self.computeInformationAboutSegment( ticketset, firstday, lastday )


    # count only the tickets that are relevant within the requested time period (firstday,lastday)
    relevantTickets = ticketCount
    closedTickets = {} # change this
    openTickets = {} # change this
    changeDateStrings = relevantChanges.keys()
    changeDateStrings.sort()
    # ticketCount = 70 # DEBUG
    
    for changeDateStr in changeDateStrings: # for each day
      self.macroenv.tracenv.log.debug("changes %4s: %3s (%s)" % (changeDateStr,relevantChanges[changeDateStr], ticketCount))
      self.setKeyIfNotExistsInt( closedTickets, changeDateStr, -1*relevantChanges[changeDateStr] )
      ticketCount = ticketCount + relevantChanges[changeDateStr]  # reduce the number of open tickets
      self.setKeyIfNotExistsInt( openTickets  , changeDateStr, ticketCount)

    # generate HTML 
    holderid = "%s_%s_%d_%d" % (self.getNameOfRenderFrame(),'holder',int(time.time()*1000000),random.randint(1,1024) ) # compute unique element id
    currentday = firstday
    frame = tag.div( class_= 'invisible ppConfBurnDown', id=self.getNameOfRenderFrame()+holderid ) 
    tableData = tag.table( class_="invisible data" , border = "1", style = 'width:auto;')
    trDays = tag.tr()
    trDaysAxis = tag.tr()
    trOpenTickets = tag.tr()
    trClosedTickets = tag.tr()
    trReopenedTickets = tag.tr()
    alldates.sort()
    lastOpenTicket = relevantTickets # fallback: all tickets
    lastClosedTickets = 0
    counter = 0
    todaySecs = self.datetime2seconds( datetime.datetime.today() )
    todayStr = self.getDateString(todaySecs)
    todayid = 0
    maxValue = 0
    if lastdaySecs <= todaySecs: # if today is later then the shown time frame then mark the last column
      todayid = len(alldates)
    for currentday in alldates:
      if currentday == todayStr: # capture the column with the current date
        todayid = counter 
      counter = counter + 1
      trDays(tag.th(currentday.replace("\n"," "))) # text for info box, no line breaks here, because it is limited to 3 lines
      trDaysAxis(tag.th(currentday))
      if openTickets.has_key(currentday) :
        lastOpenTicket = openTickets[currentday]
      trOpenTickets(tag.td(lastOpenTicket))
      if closedTickets.has_key(currentday) :
        lastClosedTickets = closedTickets[currentday]
      else:
        lastClosedTickets = 0
      trClosedTickets(tag.td(lastClosedTickets))
      maxValue = max(len(str(lastClosedTickets)),len(str(lastOpenTicket)),maxValue)
      trReopenedTickets(tag.td('0'))
    
    tableData(tag.thead(trDays))
    tableData(tag.tfoot(trDaysAxis))
    tableData(tag.tbody(trOpenTickets, trClosedTickets, trReopenedTickets ))
    
    
    (label1,label2) = self.getLabel()
    
    # caculate the scale factor for the info box within the chart
    maxGlobal = max( len(str(label1))+maxValue, len(str(label2))+maxValue )
    if self.segment in ['week','twoweek']: # they use long descriptions in the info box
      maxGlobal = max(maxGlobal, 27)
    
    # configuration of renderer
    frame(tag.div( str(relevantTickets), class_ = 'maxTasks' ))
    frame(tag.div( self.width, class_ = 'width' ))
    frame(tag.div( self.height, class_ = 'height' ))
    frame(tag.div( str(maxGlobal), class_ = 'maxlength' ))
    frame(tag.div( label1, class_ = 'label1' ))
    frame(tag.div( label2, class_ = 'label2' ))
    frame(tag.div( str(todayid), class_ = 'today' )) # number of column with the current date
    frame(tag.div( holderid, class_ = 'holder' )) # where to put the chart in
    
    frame(tableData)
    outerframe = tag.div() # div as global container
    #outerframe(outer) # DEBUG
    outerframe(frame)
    outerframe(tag.div( id = holderid ), style="border-width:1px" )
    outerframe(tag.script("$.getScript('%s'); $.getScript('%s'); $.getScript('%s');  " % ('projectplan/js/jquery-burndown/raphael.js', 'projectplan/js/jquery-burndown/raphael_002.js','projectplan/js/jquery-burndown/burndown.js' ) ) )
    return outerframe
Example #41
0
    def filter_stream(self, req, method, filename, stream, data):

        # Tickets will be modified to show the child tickets as a list under the 'Description' section.
        if filename == 'ticket.html':

            # Get the ticket info.
            ticket = data.get('ticket')

            # Modify ticket.html with sub-ticket table, create button, etc...
            # As follows:
            # - If ticket has no child tickets and child tickets are NOT allowed then skip.
            # - If ticket has child tickets and child tickets are NOT allowed (ie. rules changed or ticket type changed after children were assigned),
            #   print list of tickets but do not allow any tickets to be created.
            # - If child tickets are allowed then print list of child tickets or 'No Child Tickets' if non are currently assigned.
            #
            if ticket and ticket.exists:

                filter = Transformer('//div[@class="description"]')
                snippet = tag()

                # Are there any child tickets to display?
                childtickets = [
                    Ticket(self.env, n)
                    for n in self.env.childtickets.get(ticket.id, [])
                ]

                # (tempish) fix for #8612 : force sorting by ticket id
                childtickets = sorted(childtickets, key=lambda t: t.id)

                # trac.ini : Which columns to display in child ticket listing?
                columns = self.config.getlist('childtickets',
                                              'parent.%s.table_headers' %
                                              ticket['type'],
                                              default=['summary', 'owner'])

                # trac.ini : child tickets are allowed.
                if self.config.getbool(
                        'childtickets',
                        'parent.%s.allow_child_tickets' % ticket['type']):

                    # trac.ini : Default 'type' of child tickets?
                    default_child_type = self.config.get(
                        'childtickets',
                        'parent.%s.default_child_type' % ticket['type'],
                        default=self.config.get('ticket', 'default_type'))

                    self.env.log.debug(
                        "TracchildticketsModule : default_child_type: %s" %
                        default_child_type)

                    # Can user create a new ticket? If not, just display title (ie. no 'create' button).
                    if 'TICKET_CREATE' in req.perm(ticket.resource):

                        # Always pass these fields
                        default_child_fields = (tag.input(type="hidden",
                                                          name="parent",
                                                          value='#' +
                                                          str(ticket.id)), )

                        #Pass extra fields defined in inherit parameter of parent
                        inherited_child_fields = [
                            tag.input(type="hidden",
                                      name="%s" % field,
                                      value=ticket[field])
                            for field in self.config.getlist(
                                'childtickets', 'parent.%s.inherit' %
                                ticket['type'])
                        ]

                        # If child types are restricted then create a set of buttons for the allowed types (This will override 'default_child_type).
                        restrict_child_types = self.config.getlist(
                            'childtickets',
                            'parent.%s.restrict_child_type' % ticket['type'],
                            default=[])
                        if not restrict_child_types:
                            # ... create a default submit button
                            submit_button_fields = (
                                tag.input(type="submit",
                                          name="childticket",
                                          value="New Child Ticket",
                                          title="Create a child ticket"),
                                tag.input(type="hidden",
                                          name="type",
                                          value=default_child_type),
                            )
                        else:
                            submit_button_fields = [
                                tag.input(type="submit",
                                          name="type",
                                          value="%s" % ticket_type,
                                          title="Create a %s child ticket" %
                                          ticket_type)
                                for ticket_type in restrict_child_types
                            ]

                        snippet.append(
                            tag.div(
                                tag.form(
                                    tag.div(default_child_fields,
                                            inherited_child_fields,
                                            submit_button_fields,
                                            class_="inlinebuttons"),
                                    method="get",
                                    action=req.href.newticket(),
                                ),
                                tag.h3("Child Tickets",
                                       id="comment:child_tickets"),
                            ))
                    else:
                        snippet.append(
                            tag.div(
                                tag.h3("Child Tickets",
                                       id="comment:child_tickets")))

                # trac.ini : child tickets are NOT allowed but (somehow?!) this parent ticket has children assigned.
                elif childtickets:
                    snippet.append(
                        tag.div(
                            tag.h3("Child Tickets",
                                   id="comment:child_tickets")))

                # Test if the ticket has children: If so, then list in pretty table.
                if childtickets:
                    snippet.append(
                        tag.div(
                            tag.table(
                                tag.thead(
                                    tag.tr(tag.th("Ticket", class_="id"), [
                                        tag.th(s.title(), class_=s)
                                        for s in columns
                                    ])),
                                tag.tbody([
                                    self._table_row(req, tkt, columns)
                                    for tkt in childtickets
                                ]),
                                class_="listing tickets",
                            ), ))
                elif self.config.getbool(
                        'childtickets',
                        'parent.%s.allow_child_tickets' % ticket['type']):
                    snippet.append(tag.div(tag.p("NO SUB-TICKETS.")))

                return stream | filter.append(snippet)

        return stream
Example #42
0
    def expand_macro(self, formatter, name, arguments):

        self.ref = formatter
        self.tz_info = formatter.req.tz
        self.thistime = datetime.datetime.now(self.tz_info)

        # Parse arguments from macro invocation
        args, kwargs = parse_args(arguments, strict=False)

        # Find out whether use http param, current or macro param year/month
        http_param_year = formatter.req.args.get('year','')
        http_param_month = formatter.req.args.get('month','')

        if http_param_year == "":
            # not clicked on a prev or next button
            if len(args) >= 1 and args[0] <> "*":
                # year given in macro parameters
                year = int(args[0])
            else:
                # use current year
                year = self.thistime.year
        else:
            # year in http params (clicked by user) overrides everything
            year = int(http_param_year)

        if http_param_month == "":
            # not clicked on a prev or next button
            if len(args) >= 2 and args[1] <> "*":
                # month given in macro parameters
                month = int(args[1])
            else:
                # use current month
                month = self.thistime.month
        else:
            # month in http params (clicked by user) overrides everything
            month = int(http_param_month)

        showbuttons = True
        if len(args) >= 3 or kwargs.has_key('nav'):
            try:
                showbuttons = kwargs['nav'] in ["True", "true", "yes", "1"]
            except KeyError:
                showbuttons = args[2] in ["True", "true", "yes", "1"]

        wiki_page_format = "%Y-%m-%d"
        if len(args) >= 4 and args[3] != "*" or kwargs.has_key('wiki'):
            try:
                wiki_page_format = str(kwargs['wiki'])
            except KeyError:
                wiki_page_format = str(args[3])
        # Support relative paths in macro arguments for wiki page links.
        wiki_page_format = self._resolve_relative_name(wiki_page_format,
                                                       formatter.resource.id)

        list_condense = 0
        show_t_open_dates = True
        wiki_page_template = ""
        wiki_subpages = []

        # Read optional check plan.
        check = []
        if kwargs.has_key('check'):
            check = kwargs['check'].split('.')

        if name == 'WikiTicketCalendar':
            if len(args) >= 5 or kwargs.has_key('cdate'):
                try:
                    show_t_open_dates = kwargs['cdate'] in \
                                               ["True", "true", "yes", "1"]
                except KeyError:
                    show_t_open_dates = args[4] in \
                                               ["True", "true", "yes", "1"]

        # Optional page template to create new wiki pages.
        # The default (empty page) is used, if the template name is invalid.
        if len(args) >= 6 or kwargs.has_key('base'):
            try:
                wiki_page_template = kwargs['base']
            except KeyError:
                wiki_page_template = args[5]

        if name == 'WikiTicketCalendar':
            # TracQuery support for ticket selection
            query_args = "id!=0"
            if len(args) >= 7 or kwargs.has_key('query'):
                # prefer query arguments provided by kwargs
                try:
                    query_args = kwargs['query']
                except KeyError:
                    query_args = args[6]
            tickets = WikiCalendarTicketProvider(self.env)
            self.tickets = tickets.harvest(formatter.req, query_args)

            # compress long ticket lists
            if len(args) >= 8 or kwargs.has_key('short'):
                # prefer query arguments provided by kwargs
                try:
                    list_condense = int(kwargs['short'])
                except KeyError:
                    list_condense = int(args[7])

            # control calendar display width
            cal_width = "100%;"
            if len(args) >= 9 or kwargs.has_key('width'):
                # prefer query arguments provided by kwargs
                try:
                    cal_width = kwargs['width']
                except KeyError:
                    cal_width = args[8]

            # multiple wiki (sub)pages per day
            if kwargs.has_key('subpages'):
                wiki_subpages = kwargs['subpages'].split('|')

            # Can use this to change the day the week starts on,
            # but this is a system-wide setting.
            calendar.setfirstweekday(calendar.MONDAY)

        cal = calendar.monthcalendar(year, month)
        curr_day = None
        if year == self.thistime.year and month == self.thistime.month:
            curr_day = self.thistime.day

        # for prev/next navigation links
        prevMonth = month - 1
        nextMonth = month + 1
        nextYear = prevYear = year
        # check for year change (KISS version)
        if prevMonth == 0:
            prevMonth = 12
            prevYear -= 1
        if nextMonth == 13:
            nextMonth = 1
            nextYear += 1

        # for fast-forward/-rewind navigation links
        ffYear = frYear = year
        if month < 4:
            frMonth = month + 9
            frYear -= 1
        else:
            frMonth = month - 3
        if month > 9:
            ffMonth = month - 9
            ffYear += 1
        else:
            ffMonth = month + 3

        last_week_prevMonth = calendar.monthcalendar(prevYear, prevMonth)[-1]
        first_week_nextMonth = calendar.monthcalendar(nextYear, nextMonth)[0]

        # Switch to user's locale, if available.
        try:
            loc_req = str(formatter.req.locale)
        except AttributeError:
            # Available since in Trac 0.12 .
            loc_req = None
        if loc_req:
            loc = locale.getlocale()
            loc_prop = locale.normalize(loc_req)
            try:
                locale.setlocale(locale.LC_TIME, loc_prop)
            except locale.Error:
                try:
                    # Re-try with UTF-8 as last resort.
                    loc_prop = '.'.join([loc_prop.split('.')[0],'utf8'])
                    locale.setlocale(locale.LC_TIME, loc_prop)
                except locale.Error:
                    loc_prop = None
            self.env.log.debug('Locale setting for calendar: ' + str(loc_prop))

        # Finally building the output
        # Begin with caption and optional navigation links
        buff = tag.tr()

        if showbuttons is True:
            # calendar navigation buttons
            nx = 'next'
            pv = 'prev'
            nav_pvY = self._mknav('&lt;&lt;', pv, month, year-1)
            nav_frM = self._mknav('&nbsp;&lt;', pv, frMonth, frYear)
            nav_pvM = self._mknav('&nbsp;&laquo;', pv, prevMonth, prevYear)
            nav_nxM = self._mknav('&raquo;&nbsp;', nx, nextMonth, nextYear)
            nav_ffM = self._mknav('&gt;&nbsp;', nx, ffMonth, ffYear)
            nav_nxY = self._mknav('&gt;&gt;', nx, month, year+1)

            # add buttons for going to previous months and year
            buff(nav_pvY, nav_frM, nav_pvM)

        # The caption will always be there.
        heading = tag.td(
             to_unicode(format_date(self._mkdatetime(year, month), '%B %Y')))
        buff = buff(heading(class_='y'))

        if showbuttons is True:
            # add buttons for going to next months and year
            buff(nav_nxM, nav_ffM, nav_nxY)
        buff = tag.caption(tag.table(tag.tbody(buff)))
        buff = tag.table(buff)
        if name == 'WikiTicketCalendar':
            if cal_width.startswith('+') is True:
                width=":".join(['min-width', cal_width]) 
                buff(class_='wikitcalendar', style=width)
            else:
                buff(class_='wikitcalendar')
        if name == 'WikiCalendar':
                buff(class_='wiki-calendar')

        heading = tag.tr()
        heading(align='center')

        for day in calendar.weekheader(2).split()[:-2]:
            col = tag.th(to_unicode(day))
            col(class_='workday', scope='col')
            heading(col)
        for day in calendar.weekheader(2).split()[-2:]:
            col = tag.th(to_unicode(day))
            col(class_='weekend', scope='col')
            heading(col)

        heading = buff(tag.thead(heading))

        # Building main calendar table body
        buff = tag.tbody()
        w = -1
        for week in cal:
            w = w + 1
            line = tag.tr()
            line(align='right')
            d = -1
            for day in week:
                d = d + 1
                if day:
                    # check for wikipage with name specified in
                    # 'wiki_page_format'
                    wiki = format_date(self._mkdatetime(year, month, day),
                                                         wiki_page_format)
                    if day == curr_day:
                        a_class = 'day today'
                        td_class = 'today'
                    else:
                        a_class = 'day'
                        td_class = 'day'

                    day_dt = self._mkdatetime(year, month, day)
                    if uts:
                        day_ts = to_utimestamp(day_dt)
                        day_ts_eod = day_ts + 86399999999
                    else:
                        day_ts = to_timestamp(day_dt)
                        day_ts_eod = day_ts + 86399

                    # check for milestone(s) on that day
                    db = self.env.get_db_cnx()
                    cursor = db.cursor()
                    cursor.execute("""
                        SELECT name
                          FROM milestone
                         WHERE due >= %s and due <= %s
                    """, (day_ts, day_ts_eod))
                    milestones = tag()
                    for row in cursor:
                        if not a_class.endswith('milestone'):
                            a_class += ' milestone'
                        milestone = to_unicode(row[0])
                        url = self.env.href.milestone(milestone)
                        milestone = '* ' + milestone
                        milestones = tag(milestones,
                                         tag.div(tag.a(milestone, href=url),
                                                 class_='milestone'))
                    day = tag.span(day)
                    day(class_='day')
                    if len(wiki_subpages) > 0:
                        pages = tag(day, Markup('<br />'))
                        for page in wiki_subpages:
                            label = tag(' ', page[0])
                            page = '/'.join([wiki, page])
                            url = self.env.href.wiki(page)
                            pages(self._gen_wiki_links(page, label, 'subpage',
                                                     url, wiki_page_template,
                                                     check))
                    else:
                        url = self.env.href.wiki(wiki)
                        pages = self._gen_wiki_links(wiki, day, a_class,
                                                     url, wiki_page_template,
                                                     check)
                    cell = tag.td(pages)
                    cell(class_=td_class, valign='top')
                    if name == 'WikiCalendar':
                        line(cell)
                    else:
                        if milestones:
                            cell(milestones)
                        else:
                            cell(tag.br())

                        match = []
                        match_od = []
                        ticket_heap = tag('')
                        ticket_list = tag.div('')
                        ticket_list(align='left', class_='condense')

                        # get tickets with due date set to day
                        for t in self.tickets:
                            due = t.get(self.tkt_due_field)
                            if due is None or due in ['', '--']:
                                continue
                            else:
                                if self.tkt_due_format == 'ts':
                                    if not isinstance(due, datetime.datetime):
                                        continue
                                    if uts:
                                        due_ts = to_utimestamp(due)
                                    else:
                                        due_ts = to_timestamp(due)
                                    if due_ts < day_ts or due_ts > day_ts_eod:
                                        continue
                                else:
                                    # Beware: Format might even be unicode str
                                    duedate = format_date(day_dt,
                                                      str(self.tkt_due_format))
                                    if not due == duedate:
                                        continue

                            id = t.get('id')
                            ticket, short = self._gen_ticket_entry(t)
                            ticket_heap(ticket)
                            if not id in match:
                                if len(match) == 0:
                                    ticket_list(short)
                                else:
                                    ticket_list(', ', short)
                                match.append(id)

                        # optionally get tickets created on day
                        if show_t_open_dates is True:
                            ticket_od_list = tag.div('')
                            ticket_od_list(align='left',
                                           class_='opendate_condense')

                            for t in self.tickets:
                                if uts:
                                    ticket_ts = to_utimestamp(t.get('time'))
                                else:
                                    ticket_ts = to_timestamp(t.get('time'))
                                if ticket_ts < day_ts or \
                                        ticket_ts > day_ts_eod:
                                    continue

                                a_class = 'opendate_'
                                id = t.get('id')
                                ticket, short = self._gen_ticket_entry(t,
                                                                  a_class)
                                ticket_heap(ticket)
                                if not id in match:
                                    if len(match_od) == 0:
                                        ticket_od_list(short)
                                    else:
                                        ticket_od_list(', ', short)
                                    match_od.append(id)

                        matches = len(match) + len(match_od)
                        if list_condense > 0 and matches >= list_condense:
                            if len(match_od) > 0:
                                if len(match) > 0:
                                    ticket_list(', ')
                                ticket_list = tag(ticket_list, ticket_od_list)
                            line(cell(ticket_list))
                        else:
                            line(cell(ticket_heap))
                else:
                    if name == 'WikiCalendar':
                        if w == 0:
                            day = last_week_prevMonth[d]
                            wiki = format_date(self._mkdatetime(
                                prevYear, prevMonth, day), wiki_page_format)
                        else:
                            day = first_week_nextMonth[d]
                            wiki = format_date(self._mkdatetime(
                                nextYear, nextMonth, day), wiki_page_format)
                        url = self.env.href.wiki(wiki)
                        a_class = 'day adjacent_month'
                        pages = self._gen_wiki_links(wiki, day, a_class,
                                                 url, wiki_page_template)

                        cell = tag.td(pages)
                        cell(class_='day adjacent_month')
                        line(cell)
                    else:
                        cell = tag.td('')
                        cell(class_='day adjacent_month')
                        line(cell)
            buff(line)

        if loc_req and loc_prop:
            # We may have switched to users locale, resetting now.
            try:
                locale.setlocale(locale.LC_ALL, loc)
                self.env.log.debug('Locale setting restored: ' + str(loc))
            except locale.Error:
                pass

        buff = tag.div(heading(buff))
        if name == 'WikiTicketCalendar':
            if cal_width.startswith('+') is True:
                width=":".join(['width', cal_width]) 
                buff(class_='wikitcalendar', style=width)
            else:
                buff(class_='wikitcalendar')
        if name == 'WikiCalendar':
                buff(class_='wiki-calendar')
        # Add common CSS stylesheet
        if self.internal_css and not self.ref.req.args.get('wikicalendar'):
            # Put definitions directly into the output.
            f = open('/'.join([self.htdocs_path, 'wikicalendar.css']), 'Ur')
            css = tag.style(Markup('<!--\n'), '\n'.join(f.readlines()),
                            Markup('-->\n'))(type="text/css")
            f.close()
            # Add hint to prevent multiple inclusions.
            self.ref.req.args['wikicalendar'] = True
            return tag(css, buff)
        elif not self.ref.req.args.get('wikicalendar'):
            add_stylesheet(self.ref.req, 'wikicalendar/wikicalendar.css')
        return buff
Example #43
0
 def render(self, ticketset):
   return_div = tag.div(class_=self.cssclass+' projectplanrender' )
   
   # check for missing parameters 
   missingparameter = False
   if self.rows == [] or self.rows == None:
     return_div(tag.div('Missing parameter "rows": use a semicolon-separated list to input the "'+self.rowtype+'".', class_='ppwarning')) 
     missingparameter = True
   if self.rowtype == None or  str(self.rowtype).strip() == '':
     return_div(tag.div('Missing parameter "rowtype": specifies the ticket attribute that should be showed at the rows.', class_='ppwarning')) 
     missingparameter = True
   if self.cols == [] or self.cols == None:
     return_div(tag.div('Missing parameter: use a semicolon-separated list to input the "cols".', class_='ppwarning'))
     missingparameter = True
   if self.coltype == None or  str(self.coltype).strip() == '':
     return_div(tag.div('Missing parameter "coltype": specifies the ticket attribute that should be showed in the columns.', class_='ppwarning')) 
     missingparameter = True
   if missingparameter:
     return return_div
   
   
   #ul = tag.ul()
   #for tid in ticketset.getIDSortedList():
     #ticket = ticketset.getTicket(tid)
     #ul( tag.li(tid, " ",ticket.getfield('component') , " ", ticket.getfield('owner') ))
   #return_div(ul)
   def getstatistictitle( statusdict ):
     mytitle = ''
     mysum = 0
     for status in statusdict:
       mytitle += "%s: %s\n" % (status, str(statusdict[status]) )
       mysum += int(statusdict[status])
     mytitle += "%s: %s" % ('number', mysum)
     return mytitle
   
   def setKV( myStruct, myKey, newValue ):
     '''
       shortcut to set the values correctly
       used to reduce the code needed while using a list as key of a dict
     '''
     myStruct[str(myKey)] = newValue
   
   def tableKeyPrettyPrint( mylist ) :
     '''
       transform a list of keys to a user readable string
       in: ['a','b'] --> out: 'a|b'
     '''
     return '|'.join(mylist)
   
   def tableKeyQueryParameter( parameter, mylist ) :
     '''
       transform a list of keys to a Trac query string parameter  (OR)
       in: x, ['a','b'] --> out: 'x=a&x=b'
     '''
     return '&'.join([ "%s=%s" % (parameter, s) for s in mylist ])
   
   
   chartheight=80
   chartwidth=170
   
   data = {}
   statistics = {}
   
   # init table data 
   for row in self.rows :
     colstatistics = {}
     colkeys = {}
     for col in self.cols :
       # colkeys[col] = []
       setKV( colkeys, col, [] )
       # colstatistics[col] = {}
       setKV( colstatistics, col, {} )
     # data[row] = colkeys
     setKV( data, row, colkeys )
     # statistics[row] = colstatistics
     setKV( statistics, row, colstatistics )
   
   for tid in ticketset.getIDSortedList():
     ticket = ticketset.getTicket(tid)
     ticket_rowtype = ticket.getfield(self.rowtype)
     ticket_coltype =  ticket.getfield(self.coltype)
     
     # determine the data cell where the ticket has to be added, keep in mind that rows and cols are list of lists
     for row in self.rows :
       for col in self.cols :
         if ticket_rowtype in row and ticket_coltype in col :
           data[str(row)][str(col)].append(ticket) # save tickets at precise values of row and col
           self.log_debug('row:%s col:%s append:%s' % (row,col,tid))
     
     # if ticket_rowtype in self.rows and ticket_coltype in self.cols :
   
   # create HTML table
   table = tag.table( class_="data pptableticketperday" , border = "1", style = 'width:auto;')
   
   # create HTML table head
   thead = tag.thead()
   tr = tag.tr()
   tr( tag.th("%s vs %s" % (self.rowtype,self.coltype) ) )
   for colkey in self.cols :
     tr( tag.th(tag.h4(tag.a( tableKeyPrettyPrint(colkey), href=self.macroenv.tracenv.href()+('/query?%s&order=%s' % ( tableKeyQueryParameter(self.coltype, colkey),self.rowtype)) )),title="%s is %s" % (self.coltype, tableKeyPrettyPrint(colkey) ) ) ) # first line with all colkeys
   if self.showsummarypiechart:
     tr( tag.th(tag.h4( "Ticket Overview" ) ) )  
   thead(tr)
   table(thead)
   
   # create HTML table body
   tbody = tag.tbody()
   counter=0
   
   for rowkey in self.rows :
     # switch line color
     if counter % 2 == 1:
       class_ = 'odd'
     else:
       class_ = 'even'
     counter += 1
     tr = tag.tr( class_=class_ ) # new line
     
     td = tag.td() # new cell
     td(tag.h5(tag.a( tableKeyPrettyPrint(rowkey), href=self.macroenv.tracenv.href()+('/query?%s&order=%s' % ( tableKeyQueryParameter( self.rowtype,rowkey),self.coltype)) )),title="%s is %s" % (self.rowtype, tableKeyPrettyPrint(rowkey) ) ) # first cell contains row key
     tr(td)
     for colkey in self.cols :
       td = tag.td()
       for ticket in data[str(rowkey)][str(colkey)] :
         td( tag.span(self.createTicketLink(ticket), class_ = 'ticket_inner' ), " " , mytitle="%s is %s and %s is %s" % (self.rowtype,rowkey,self.coltype,colkey) ) # mytitle might be used later by javascript
         if not statistics[str(rowkey)][str(colkey)].has_key( ticket.getstatus() ) :
           statistics[str(rowkey)][str(colkey)][ticket.getstatus()] = 0
         statistics[str(rowkey)][str(colkey)][ticket.getstatus()] += 1
       tr(td)
     
     # compute statistics
     rowstatistics = {}
     count = 0
     for colkey in statistics[str(rowkey)] :
       for status in statistics[str(rowkey)][str(colkey)] :
         if not rowstatistics.has_key(status) : 
           rowstatistics[status] = 0
         try:
           rowstatistics[status] += statistics[str(rowkey)][str(colkey)][status]
           count += statistics[str(rowkey)][str(colkey)][status]
         except:
           pass
       
     if self.showsummarypiechart:
       tr(tag.td(tag.img(src=self.createGoogleChartFromDict('ColorForStatus', rowstatistics, '%s tickets' % (count,), height=chartheight )), class_='ppstatistics' , title=getstatistictitle(rowstatistics)) ) # Summary
     
     tbody(tr)
   table(tbody)
   
   # create HTML table foot
   if self.showsummarypiechart :
     fullstatistics = {}
     tfoot = tag.tfoot()
     tr = tag.tr()
     
     tr( tag.td(tag.h5('Ticket Overview') ) )
     
     # create statistics for col
     fullcount = 0
     for colkey in self.cols :
       colstatistics = {}
       colcount = 0
       for rowkey in self.rows :
         for status in statistics[str(rowkey)][str(colkey)] :
           if not fullstatistics.has_key(status) : 
             fullstatistics[status] = 0
           if not colstatistics.has_key(status) : 
             colstatistics[status] = 0
           try:
             colstatistics[status] += statistics[str(rowkey)][str(colkey)][status]
             colcount += statistics[str(rowkey)][str(colkey)][status]
             fullstatistics[status] += statistics[str(rowkey)][str(colkey)][status]
             fullcount += statistics[str(rowkey)][str(colkey)][status]
           except:
             pass
       tr(tag.td(tag.img(src=self.createGoogleChartFromDict('ColorForStatus', colstatistics, '%s tickets' % (colcount,), height=chartheight)), title=getstatistictitle(colstatistics) )) # Col Summary
     tr(tag.td(tag.img(src=self.createGoogleChartFromDict('ColorForStatus', fullstatistics, '%s tickets' % (fullcount,), height=chartheight)), class_='ppstatistics', title=getstatistictitle(fullstatistics))) # Full Summary
     tfoot(tr)
     table(tfoot)
   
   return_div(table)
   
   return return_div 
Example #44
0
    def filter_stream(self, req, method, filename, stream, data):

        # Tickets will be modified to show the child tickets as a list under the 'Description' section.
        if filename == 'ticket.html':

            # Get the ticket info.
            ticket = data.get('ticket')

            # Modify ticket.html with sub-ticket table, create button, etc...
            # As follows:
            # - If ticket has no child tickets and child tickets are NOT allowed then skip.
            # - If ticket has child tickets and child tickets are NOT allowed (ie. rules changed or ticket type changed after children were assigned),
            #   print list of tickets but do not allow any tickets to be created.
            # - If child tickets are allowed then print list of child tickets or 'No Child Tickets' if non are currently assigned.
            # 
            if ticket and ticket.exists:

                filter = Transformer('//div[@class="description"]')
                snippet = tag()
                
                # Are there any child tickets to display?
                childtickets = [ Ticket(self.env,n) for n in self.env.childtickets.get(ticket.id,[]) ]

                # (tempish) fix for #8612 : force sorting by ticket id
                childtickets = sorted(childtickets, key=lambda t: t.id)


                # trac.ini : Which columns to display in child ticket listing?
                columns = self.config.getlist('childtickets', 'parent.%s.table_headers' % ticket['type'], default=['summary','owner'])

                # trac.ini : child tickets are allowed.
                if self.config.getbool('childtickets', 'parent.%s.allow_child_tickets' % ticket['type']):

                    # trac.ini : Default 'type' of child tickets?
                    default_child_type = self.config.get('childtickets', 'parent.%s.default_child_type' % ticket['type'], default=self.config.get('ticket','default_type'))

                    self.env.log.debug("TracchildticketsModule : default_child_type: %s" % default_child_type)

                    # Can user create a new ticket? If not, just display title (ie. no 'create' button).
                    if 'TICKET_CREATE' in req.perm(ticket.resource):

                        # Always pass these fields
                        default_child_fields = (
                                tag.input(type="hidden", name="parent", value='#'+str(ticket.id)),
                                )

                        #Pass extra fields defined in inherit parameter of parent
                        inherited_child_fields = [
                                tag.input(type="hidden",name="%s"%field,value=ticket[field]) for field in self.config.getlist('childtickets','parent.%s.inherit' % ticket['type'])
                                ]

                        # If child types are restricted then create a set of buttons for the allowed types (This will override 'default_child_type).
                        restrict_child_types = self.config.getlist('childtickets','parent.%s.restrict_child_type' % ticket['type'],default=[])
                        if not restrict_child_types:
                            # ... create a default submit button
                            submit_button_fields = (
                                    tag.input(type="submit",name="childticket",value="New Child Ticket",title="Create a child ticket"),
                                    tag.input(type="hidden", name="type", value=default_child_type),
                                    )
                        else:
                            submit_button_fields = [ tag.input(type="submit",name="type",value="%s" % ticket_type,title="Create a %s child ticket" % ticket_type) for ticket_type in restrict_child_types ]
        
                        snippet.append(tag.div(
                            tag.form(
                                tag.div( default_child_fields, inherited_child_fields, submit_button_fields, class_="inlinebuttons"),                            
                                method="get", action=req.href.newticket(),
                                ),
                            tag.h3("Child Tickets",id="comment:child_tickets"),
                            ))
                    else:
                        snippet.append(tag.div(tag.h3("Child Tickets",id="comment:child_tickets")))

                # trac.ini : child tickets are NOT allowed but (somehow?!) this parent ticket has children assigned.
                elif childtickets:
                    snippet.append(tag.div(tag.h3("Child Tickets",id="comment:child_tickets")))

                # Test if the ticket has children: If so, then list in pretty table.
                if childtickets:
                    snippet.append(
                            tag.div(
                                tag.table(
                                    tag.thead(
                                        tag.tr(
                                            tag.th("Ticket",class_="id"),
                                            [ tag.th(s.title(),class_=s) for s in columns ])
                                        ),
                                    tag.tbody([ self._table_row(req,tkt,columns) for tkt in childtickets ]),
                                    class_="listing tickets",
                                    ),
                                )
                            )
                elif self.config.getbool('childtickets', 'parent.%s.allow_child_tickets' % ticket['type']):
                    snippet.append(tag.div(tag.p("NO SUB-TICKETS.")))

                return stream | filter.append(snippet)

        return stream
Example #45
0
    def LastChangesBy(self, formatter, content):
        """
This macro prints a table similar to the `[[ListOfWikiPages]]` only with the 
''By'' column missing and the author name in the table head.
{{{
[[LastChangesBy(martin_s)]]          # the last 5 changes by user `martin_s`
[[LastChangesBy(martin_s,10)]]       # the last 10 changes by user `martin_s`

[[LastChangesBy]]                    # or
[[LastChangesBy()]]                  # the last 5 changes by the current user (i.e. every user sees it's own changes, if logged-on)
[[LastChangesBy(,12)]]               # the last 12 changes by the current user

[[LastChangesBy(...,format=...]]     # Selects `long` or `short` table format
[[LastChangesBy(...,from=..,to=..]]  # Selects `from` and `to` time/date range

[[LastChangesBy(...,headline=...]]   # Overwrites headline, may not contain `','`

[[LastChangesBy(...,order=reverse]]  # Lists the wikis in reverse order. Only really useful with few wikis or with `to`/`from`.

[[LastChangesBy(..,exclude=pattern]] # Excludes wikis matching `pattern`. Wildcards `*` and `?` are supported.
}}}
        """

        largs, kwargs = parse_args( content )

        #self.base_path = formatter.req.base_path
        self.href = formatter.req.href
        section = 'listofwikipages'

        long_format = self.env.config.get(section, 'default_format', 
            'short').lower() == 'long'
        if 'format' in kwargs:
          long_format = kwargs['format'].lower() == 'long'
        self.long_format = long_format

        self.kwargs = kwargs
        dfrom, fromtext = self.timeval('from', (0,''))
        dto, totext     = self.timeval('to',   (int(unixtime()),''))

        if 'from' in kwargs or 'to' in kwargs:
          sql_time = " AND time BETWEEN %d AND %d " % (dfrom,dto)
        else:
          sql_time = ''

        sql_exclude = ''
        if 'exclude' in kwargs:
          sql_exclude = self._get_sql_exclude(kwargs['exclude'])

        author = len(largs) > 0 and largs[0] or formatter.req.authname
        count  = len(largs) > 1 and largs[1] or 5
        try:
            count = int(count)
            if count < 1:
                raise
        except:
            raise TracError("Second list argument must be a positive integer!")

        db = self.env.get_db_cnx()
        cursor = db.cursor()
        #cursor.log = self.env.log

        if kwargs.get('order','normal') == 'reverse':
          order = " "
        else:
          order = " DESC "

        cursor.execute ( """
              SELECT name,time,version,comment
              FROM wiki AS w1 WHERE author = %s """ + sql_time + sql_exclude + """
              AND version=(SELECT MAX(version) FROM wiki AS w2 WHERE w1.name=w2.name)
              ORDER BY time
          """ + order + " LIMIT 0,%d " % count, (author,) )

        rows = [ self.formatrow(n,name,time,version,comment) for
              n,[name,time,version,comment] in enumerate(cursor) if n < count ]
        if count == 1:
            count = ''
            s = ''
        else:
            s = 's'

        if self.long_format:
          cols = ( "WikiPage", "Last Changed At",
                   "Version", "Diff", "History", "Comment" )
        else:
          cols = ( "WikiPage", "Last Changed At" )

        headline = "Last %s change%s by  " % (count,s)
        if sql_time:
          if fromtext:
            if totext:
              timetag = " between %s and %s ago" % (fromtext,totext)
            else:
              timetag = " in the last %s" % fromtext
          else:
            if totext:
              timetag = " before the last %s" % totext
            else:
              timetag = ""
        else:
          timetag = ''

        if 'headline' in kwargs:
          headlinetag = tag.tr(
              tag.th(kwargs['headline'],
              colspan = len(cols) ))
        else:
          headlinetag = tag.tr(
              tag.th(headline, tag.strong(author), timetag,
              colspan = len(cols) ))

        head = tag.thead ( headlinetag,
                tag.tr(
          map(lambda x: tag.th(x, class_=x.replace(" ", "").lower() ), cols)
        ) )
        table = tag.table( head, rows, class_ = 'lastchangesby' )

        self.href = None
        return table
Example #46
0
    def expand_macro(self, formatter, name, content):
        req = formatter.req
        if not hasattr(req, '_querychart'):
            add_script(req, 'querychart/js/flot/excanvas.pack.js')
            add_script(req, 'querychart/js/flot/jquery.flot.pack.js')
            add_script(req, 'querychart/js/querychart.js')
            req._querychart = 0
        else:
            req._querychart = req._querychart+1

        #context = formatter.context
        opts = {
               'width':'536',
               'height':'300',
               'end':None,
               'start':None,
               'query':'',
               'col':[],
               'per':'week',
               'upper':False
               }
        collabel={}
        ticket_fields = TicketSystem(self.env).get_ticket_fields()

        for arg in content.split(','):
            colon_split = arg.split(':')
            key = colon_split[0]
            value = ''
            if len(colon_split)>1:
                value = ':'.join(colon_split[1:])
            else:
                value = True
            if key=='col':
                if value=='time':
                    opts[key].append('time')
                    collabel['time'] = _('Created')
                elif value=='changetime':
                    opts[key].append('changetime')
                    collabel['changetime'] = _('Modified')
                else:
                    for f in ticket_fields:
                        if f['name'] == value or f['label'] == value:
                            opts[key].append(f['name'])
                            collabel[f['name']] = f['label']
                            break

            elif key in ['start','end']:
                opts[key]= parse_date(value)
            else:
                opts[key] = value


        
        data = self._make_data(req,opts)
        if data==None:
            raise TracError('No data matched')
        fieldlist = data['fieldlist']
        x_axis = data['x_axis']
        counts = data['counts']
        linenum = data['linenum']
        result_len = data['result_len']


        table = tag.table(class_="listing reports",
                          id="querycharttable_%d"%(req._querychart),
                          style="display:none")
        tr = tag.tr(tag.th('Field'),
                    tag.th('Date'),
                    tag.th('Count'))
        #for field in fieldlist:
        #    tr.append(tag.th(field))
        table.append(tag.thead(tr))

        for i in range(0,linenum):
            for x in x_axis:
                tr = tag.tr(tag.td(collabel[fieldlist[i]]),
                            tag.td(format_date(x)),
                            tag.td(counts[(x,i)])
                            )
                table.append(tr)

        opttag = tag.div(id="querychartopt_%d"%(req._querychart),
                         style="display:none")

        for opt in opts:
            opttag.append(tag.span(opts[opt],class_=opt))

        div = tag.div(
                      tag.div(' ',
                              id="placeholder_%d"%(req._querychart),
                              style="width:%spx;height:%spx;"%
                              (opts["width"],opts["height"])),
                      opttag,
                      table,
                      class_="querychart",
                      id="querychart_%d"%(req._querychart)
                      )
        return div
Example #47
0
        def _body_rows():
            for idx, line in enumerate(_group_lines(stream)):
                row = tag.tr()
                if marks and idx + 1 in marks:
                    row(class_='hilite')
                for annotator, data in annotator_datas:
                    if annotator:
                        annotator.annotate_row(context, row, idx+1, line, data)
                    else:
                        row.append(tag.td())
                row.append(tag.td(line))
                yield row

        return tag.table(class_='code')(
            tag.thead(_head_row()),
            tag.tbody(_body_rows())
        )

    def get_max_preview_size(self):
        """:deprecated: use `max_preview_size` attribute directly."""
        return self.max_preview_size

    def get_charset(self, content='', mimetype=None):
        """Infer the character encoding from the `content` or the `mimetype`.

        `content` is either a `str` or an `unicode` object.

        The charset will be determined using this order:
         * from the charset information present in the `mimetype` argument
         * auto-detection of the charset from the `content`
Example #48
0
    def expand_macro(self, formatter, name, arguments):
        """Returns macro content."""
        env = self.env
        req = formatter.req
        tz = req.tz

        # Parse arguments from macro invocation.
        args, kwargs = parse_args(arguments, strict=False)

        # Enable week number display regardless of argument position.
        week_pref = 'w' in args and args.pop(args.index('w'))

        week_pref = week_pref and week_pref or kwargs.get('w')
        week_start = None
        week_num_start = None
        # Parse per-instance week calculation rules, if available.
        if week_pref:
            if ':' not in week_pref:
                # Treat undelimitted setting as week start.
                week_pref += ':'
            w_start, wn_start = week_pref.split(':')
            try:
                week_start = int(w_start)
            except ValueError:
                week_start = None
            else:
                week_start = week_start > -1 and week_start < 7 and \
                             week_start or None
            try:
                week_num_start = int(wn_start)
            except ValueError:
                week_num_start = None
            else:
                week_num_start = week_num_start in (1, 4, 7) and \
                                 week_num_start or None

        # Respect user's locale, if available.
        try:
            locale = Locale.parse(str(req.locale))
        except (AttributeError, UnknownLocaleError):
            # Attribute 'req.locale' vailable since Trac 0.12.
            locale = None
        if has_babel:
            if locale:
                if not locale.territory:
                    # Search first locale, which has the same `language` and
                    # territory in preferred languages.
                    for l in req.languages:
                        l = l.replace('-', '_').lower()
                        if l.startswith(locale.language.lower() + '_'):
                            try:
                                l = Locale.parse(l)
                                if l.territory:
                                    locale = l
                                    break  # first one rules
                            except UnknownLocaleError:
                                pass
                if not locale.territory and locale.language in LOCALE_ALIASES:
                    locale = Locale.parse(LOCALE_ALIASES[locale.language])
            else:
                # Default fallback.
                locale = Locale('en', 'US')
            env.log.debug('Locale setting for wiki calendar: %s' %
                          locale.get_display_name('en'))
        if not week_start:
            if week_pref and week_pref.lower().startswith('iso'):
                week_start = 0
                week_num_start = 4
            elif has_babel:
                week_start = locale.first_week_day
            else:
                import calendar
                week_start = calendar.firstweekday()
        # ISO calendar will remain as default.
        if not week_num_start:
            if week_start == 6:
                week_num_start = 1
            else:
                week_num_start = 4
        env.log.debug('Effective settings: first_week_day=%s, '
                      '1st_week_of_year_rule=%s' %
                      (week_start, week_num_start))

        # Find year and month of interest.
        year = req.args.get('year')
        # Not clicked on any previous/next button, next look for macro args.
        if not year and len(args) >= 1 and args[0] != "*":
            year = args[0]
        year = year and year.isnumeric() and int(year) or None

        month = req.args.get('month')
        # Not clicked on any previous/next button, next look for macro args.
        if not month and len(args) >= 2 and args[1] != "*":
            month = args[1]
        month = month and month.isnumeric() and int(month) or None

        now = datetime.now(tz)
        # Force offset from start-of-day to avoid a false 'today' marker,
        # but use it only on request of different month/year.
        now.replace(second=1)
        today = None
        if (month and month != now.month) or (year and year != now.year):
            today = now.replace(year=year, month=month, day=1)
        # Use current month and year, if nothing else has been requested.
        if not today:
            today = now.replace(hour=0, minute=0, second=0, microsecond=0)

        showbuttons = True
        if len(args) >= 3 or kwargs.has_key('nav'):
            try:
                showbuttons = kwargs['nav'] in _TRUE_VALUES
            except KeyError:
                showbuttons = args[2] in _TRUE_VALUES

        wiki_page_format = "%Y-%m-%d"
        if len(args) >= 4 and args[3] != "*" or kwargs.has_key('wiki'):
            try:
                wiki_page_format = str(kwargs['wiki'])
            except KeyError:
                wiki_page_format = str(args[3])
        # Support relative paths in macro arguments for wiki page links.
        wiki_page_format = resolve_relative_name(wiki_page_format,
                                                 formatter.resource.id)

        list_condense = 0
        show_t_open_dates = True
        wiki_subpages = []

        # Read optional check plan.
        check = []
        if kwargs.has_key('check'):
            check = kwargs['check'].split('.')

        if name == 'WikiTicketCalendar':
            if len(args) >= 5 or kwargs.has_key('cdate'):
                try:
                    show_t_open_dates = kwargs['cdate'] in _TRUE_VALUES
                except KeyError:
                    show_t_open_dates = args[4] in _TRUE_VALUES

            # TracQuery support for ticket selection
            query_args = "id!=0"
            if len(args) >= 7 or kwargs.has_key('query'):
                # prefer query arguments provided by kwargs
                try:
                    query_args = kwargs['query']
                except KeyError:
                    query_args = args[6]

            # compress long ticket lists
            if len(args) >= 8 or kwargs.has_key('short'):
                # prefer query arguments provided by kwargs
                try:
                    list_condense = int(kwargs['short'])
                except KeyError:
                    list_condense = int(args[7])

            # control calendar display width
            cal_width = "100%;"
            if len(args) >= 9 or kwargs.has_key('width'):
                # prefer query arguments provided by kwargs
                try:
                    cal_width = kwargs['width']
                except KeyError:
                    cal_width = args[8]

            # multiple wiki (sub)pages per day
            if kwargs.has_key('subpages'):
                wiki_subpages = kwargs['subpages'].split('|')

        # Prepare datetime objects for previous/next navigation link creation.
        prev_year = month_offset(today, -12)
        prev_quarter = month_offset(today, -3)
        prev_month = month_offset(today, -1)
        next_month = month_offset(today, 1)
        next_quarter = month_offset(today, 3)
        next_year = month_offset(today, 12)

        # Find first and last calendar day, probably in last/next month,
        # using datetime objects exactly at start-of-day here.
        # Note: Calendar days are numbered 0 (Mo) - 6 (Su).
        first_day_month = today.replace(day=1, second=0)
        first_day = first_day_month - timedelta(
            week_index(first_day_month, week_start))
        last_day_month = next_month.replace(day=1) - timedelta(1)
        if ((last_day_month - first_day).days + 1) % 7 > 0:
            last_day = last_day_month + timedelta(7 - (
                (last_day_month - first_day).days + 1) % 7)
        else:
            last_day = last_day_month

        # Find relevant tickets.
        if name == 'WikiTicketCalendar':
            daystr = (uts and '..' or ':').join([
                format_datetime(first_day, locale=locale),
                format_datetime(last_day, locale=locale)
            ])
            provider = WikiCalendarTicketProvider(env)
            query_args = query_args and query_args + '&' or ''
            tkt_due = provider.harvest(
                req, query_args + '='.join([self.tkt_due_field, daystr]))
            if show_t_open_dates:
                tkt_new = provider.harvest(
                    req, query_args + '='.join(['created', daystr]))

        # Finally building the output now.
        # Begin with caption and optional navigation links.
        buff = tag.tr()

        if showbuttons is True:
            # Create calendar navigation buttons.
            nx = 'next'
            pv = 'prev'
            nav_pv_y = _nav_link(req, '&lt;&lt;', pv, prev_year, locale)
            nav_pv_q = _nav_link(req, '&nbsp;&laquo;', pv, prev_quarter,
                                 locale)
            nav_pv_m = _nav_link(req, '&nbsp;&lt;', pv, prev_month, locale)
            nav_nx_m = _nav_link(req, '&gt;&nbsp;', nx, next_month, locale)
            nav_nx_q = _nav_link(req, '&raquo;&nbsp;', nx, next_quarter,
                                 locale)
            nav_nx_y = _nav_link(req, '&gt;&gt;', nx, next_year, locale)

            # Add buttons for going to previous months and year.
            buff(nav_pv_y, nav_pv_q, nav_pv_m)

        # The caption will always be there.
        if has_babel:
            heading = tag.td(format_datetime(today, 'MMMM y', locale=locale))
        else:
            heading = tag.td(format_date(today, '%B %Y'))
        buff = buff(heading(class_='y'))

        if showbuttons is True:
            # Add buttons for going to next months and year.
            buff(nav_nx_m, nav_nx_q, nav_nx_y)
        buff = tag.caption(tag.table(tag.tbody(buff)))
        buff = tag.table(buff)
        if name == 'WikiTicketCalendar':
            if cal_width.startswith('+') is True:
                width = ":".join(['min-width', cal_width])
                buff(class_='wikitcalendar', style=width)
            else:
                buff(class_='wikitcalendar')
        if name == 'WikiCalendar':
            buff(class_='wiki-calendar')

        heading = tag.tr()
        heading(align='center')
        if week_pref:
            # Add an empty cell matching the week number column below.
            heading(tag.th())

        day_names = [(idx, day_name) for idx, day_name in get_day_names(
            'abbreviated', 'format', locale).iteritems()]
        # Read day names after shifting into correct position.
        for idx, name_ in day_names[week_start:7] + day_names[0:week_start]:
            col = tag.th(name_)
            if has_babel:
                weekend = idx >= locale.weekend_start and \
                          idx <= locale.weekend_end
            else:
                weekend = idx > 4
            col(class_=('workday', 'weekend')[weekend], scope='col')
            heading(col)
        heading = buff(tag.thead(heading))

        # Building main calendar table body
        buff = tag.tbody()
        day = first_day
        while day.date() <= last_day.date():
            # Insert a new row for every week.
            if (day - first_day).days % 7 == 0:
                line = tag.tr()
                line(align='right')
                if week_pref:
                    cell = tag.td(
                        week_num(env, day, week_start, week_num_start))
                    line(cell(class_='week'))
            if not (day < first_day_month or day > last_day_month):
                wiki = format_date(day, wiki_page_format)
                if day == today:
                    a_class = 'day today'
                    td_class = 'today'
                else:
                    a_class = 'day'
                    td_class = 'day'

                if uts:
                    day_ts = to_utimestamp(day)
                    day_ts_eod = day_ts + 86399999999
                else:
                    day_ts = to_timestamp(day)
                    day_ts_eod = day_ts + 86399

                # Check for milestone(s) on that day.
                #db = env.get_read_db()
                #cursor = db.cursor()
                #cursor.execute("""
                #    SELECT name
                #      FROM milestone
                #     WHERE due >= %s and due <= %s
                #""", (day_ts, day_ts_eod))
                cursor = self.env.db_query(
                    """
                    SELECT name
                      FROM milestone
                     WHERE due >= %s and due <= %s
                """, (day_ts, day_ts_eod))
                milestones = tag()
                for row in cursor:
                    if not a_class.endswith('milestone'):
                        a_class += ' milestone'
                    milestone = to_unicode(row[0])
                    url = env.href.milestone(milestone)
                    milestone = '* ' + milestone
                    milestones = tag(
                        milestones,
                        tag.div(tag.a(milestone, href=url),
                                class_='milestone'))
                label = tag.span(day.day)
                label(class_='day')
                # Generate wiki page links with name specified in
                # 'wiki_page_format', and check their existence.
                if len(wiki_subpages) > 0:
                    pages = tag(label, Markup('<br />'))
                    for page in wiki_subpages:
                        label = tag(' ', page[0])
                        page = '/'.join([wiki, page])
                        pages(
                            self._wiki_link(req, args, kwargs, page, label,
                                            'subpage', check))
                else:
                    pages = self._wiki_link(req, args, kwargs, wiki, label,
                                            a_class, check)
                cell = tag.td(pages)
                cell(class_=td_class, valign='top')
                if name == 'WikiCalendar':
                    line(cell)
                else:
                    if milestones:
                        cell(milestones)
                    else:
                        cell(tag.br())

                    match = []
                    match_od = []
                    ticket_heap = tag('')
                    ticket_list = tag.div('')
                    ticket_list(align='left', class_='condense')

                    # Get tickets with due date set to day.
                    for t in tkt_due:
                        due = t.get(self.tkt_due_field)
                        if due is None or due in ('', '--'):
                            continue
                        else:
                            if self.tkt_due_format == 'ts':
                                if not isinstance(due, datetime):
                                    continue
                                if uts:
                                    due_ts = to_utimestamp(due)
                                else:
                                    due_ts = to_timestamp(due)
                                if due_ts < day_ts or due_ts > day_ts_eod:
                                    continue
                            else:
                                # Beware: Format might even be unicode string,
                                # but str is required by the function.
                                duedate = format_date(day,
                                                      str(self.tkt_due_format))
                                if not due == duedate:
                                    continue

                        tkt_id = t.get('id')
                        ticket, short = _ticket_links(env, formatter, t)
                        ticket_heap(ticket)
                        if not tkt_id in match:
                            if len(match) == 0:
                                ticket_list(short)
                            else:
                                ticket_list(', ', short)
                            match.append(tkt_id)

                    # Optionally, get tickets created on day too.
                    if show_t_open_dates:
                        ticket_od_list = tag.div('')
                        ticket_od_list(align='left',
                                       class_='opendate_condense')

                        for t in tkt_new:
                            if uts:
                                ticket_ts = to_utimestamp(t.get('time'))
                            else:
                                ticket_ts = to_timestamp(t.get('time'))
                            if ticket_ts < day_ts or ticket_ts > day_ts_eod:
                                continue

                            a_class = 'opendate_'
                            tkt_id = t.get('id')
                            ticket, short = _ticket_links(
                                env, formatter, t, a_class)
                            ticket_heap(ticket)
                            if not tkt_id in match:
                                if len(match_od) == 0:
                                    ticket_od_list(short)
                                else:
                                    ticket_od_list(', ', short)
                                match_od.append(tkt_id)

                    matches = len(match) + len(match_od)
                    if list_condense > 0 and matches >= list_condense:
                        if len(match_od) > 0:
                            if len(match) > 0:
                                ticket_list(', ')
                            ticket_list = tag(ticket_list, ticket_od_list)
                        line(cell(ticket_list))
                    else:
                        line(cell(ticket_heap))
            else:
                if name == 'WikiCalendar':
                    wiki = format_date(day, wiki_page_format)
                    a_class = 'day adjacent_month'
                    pages = self._wiki_link(req, args, kwargs, wiki, day.day,
                                            a_class)
                    cell = tag.td(pages, class_='day adjacent_month')
                    line(cell)
                else:
                    cell = tag.td('', class_='day adjacent_month')
                    line(cell)
            # Append completed week rows.
            if (day - first_day).days % 7 == 6:
                buff(line)
            day += timedelta(1)

        buff = tag.div(heading(buff))
        if name == 'WikiTicketCalendar':
            if cal_width.startswith('+') is True:
                width = ":".join(['width', cal_width])
                buff(class_='wikitcalendar', style=width)
            else:
                buff(class_='wikitcalendar')
        if name == 'WikiCalendar':
            buff(class_='wiki-calendar')
        # Add common CSS stylesheet.
        if self.internal_css and not req.args.get('wikicalendar'):
            # Put definitions directly into the output.
            f = open('/'.join([self.htdocs_path, 'wikicalendar.css']), 'Ur')
            css = tag.style(Markup('<!--\n'), '\n'.join(f.readlines()),
                            Markup('-->\n'))(type="text/css")
            f.close()
            # Add hint to prevent multiple inclusions.
            req.args['wikicalendar'] = True
            return tag(css, buff)
        elif not req.args.get('wikicalendar'):
            add_stylesheet(req, 'wikicalendar/wikicalendar.css')
        return buff
    def gen_calendar(self, tickets, query, month, width=None, nav=True):
        milestones = self._get_milestones()

        req = self.req
        locale = self._get_locale()
        first_week_day = self._get_first_week_day(locale)
        start_date_format = self.mod.start_date_format
        due_date_format = self.mod.due_date_format

        if not month:
            month = get_today(req.tz).replace(day=1)

        # init data
        today = get_today(req.tz)

        # generate calendar data
        weeks = self._get_month_calendar(month.year, month.month,
                                         first_week_day, locale)
        days = sorted(sum(weeks, []))
        tickets = self._filter_tickets(days, tickets, req.tz)
        milestones = self._filter_milestones(days, milestones, req.tz)
        cal = [[{'date': day,
                 'tickets': tickets[day], 'milestones': milestones[day]}
                for day in week]
               for week in weeks]

        def genli(t):
            if isinstance(t, Milestone):
                return self._create_milestone_item(t)
            else:
                return self._create_ticket_item(t)

        def gentd(week_idx, day_info):
            day = day_info['date']
            tt = day_info['milestones'] + day_info['tickets']
            if len(tt) < 6:
                ttshow = tt
                ttall = []
            else:
                ttshow = tt[:4]
                ttall = tt

            tdclass = []
            if day == today:
                tdclass.append('today')
            if is_weekend(day, locale):
                tdclass.append('weekend')

            formatted_day = format_date(day, format='long', locale=locale)

            td = tag.td(
                class_=' '.join(tdclass),
                data_for_start_date=day.strftime(start_date_format),
                data_for_due_date=day.strftime(due_date_format),
                data_fdate=formatted_day)

            label = []
            if day == today:
                label.append(tag.span(_("Today"), class_='today'))
            label.append(tag.span(unicode(day.day),
                                  class_=('day normal', 'day')[day == today]))
            td(tag.div(label))
            if ttshow:
                td(tag.ul([genli(t) for t in ttshow]))

            if ttall:
                id = 'calendar-more-%s' % str(day)
                td(tag.a(_("%d more tickets...") % (len(ttall) - 4),
                         href='#' + id,
                         class_='show-all-list'),
                   tag.div(tag.h4(formatted_day),
                           tag.ul([genli(t) for t in ttall]),
                           class_='ticketcalendar-popup-list',
                           id=id,
                           data_title=format_date(day, locale=locale,
                                                  format='full')))

            return td

        day_names = get_day_names(locale=locale, width='abbreviated')
        day_names = [day_names[(idx + first_week_day) % 7]
                     for idx in xrange(7)]

        header = tag.div(class_='ticketcalendar-header')
        if nav:
            def nav_href(d):
                return self.get_box_href(query, d)

            def nav_pager(d):
                return tag.span(
                    tag.a(u'\u25c4', href=nav_href(d - timedelta(days=1))),
                    tag.a(_("Current month"),
                          href=nav_href(get_today(req.tz))),
                    tag.a(u'\u25ba', href=nav_href(d + timedelta(days=31))),
                    class_='ticketcalendar-pager')

            def nav_macro():
                macro = (
                    '[[TicketCalendar(type=box,month=%(month)s,'
                    'query=%(query)s,order=%(order)s%(extra)s)]]' %
                    (dict(month=month.strftime('%Y-%m'),
                          query=self.build_query_string(query.constraints),
                          order=query.order,
                          extra=query.desc and ',desc=1' or '')))
                text = tag.input(type='text', readonly='readonly', size='80',
                                 value=macro, style='width:0;display:none')
                return tag.span(_("Macro"), text,
                                class_='ticketcalendar-macro')

            header(tag.div(nav_macro(), nav_pager(month),
                           class_='ticketcalendar-nav'))

        header(tag.h4(_("%(month_name)s, %(year)s",
                        month_name=_get_month_name(month, locale),
                        year=month.year)))

        calendar = tag.table(
             tag.thead(tag.tr(tag.th(name) for name in day_names)),
             tag.tbody([tag.tr([gentd(idx, d) for d in w])
                               for idx, w in enumerate(cal)]),
             class_='calendar')

        can_create = 'TICKET_CREATE' in req.perm

        ticket_box = tag.div(
            tag.h4(tag.span('', class_='tc-today-date')),
            tag.ul(
                tag.li(tag.a(
                    tag_("New ticket with \"%(date)s\" as the start date",
                         date=tag.span('', data='start-date')),
                    data_href=req.href('newticket',
                                       [(self.mod.start_date_name, '')]),
                    class_='newticket-start-date')),
                tag.li(tag.a(
                    tag_("New ticket with \"%(date)s\" as the due date",
                         date=tag.span('', data='due-date')),
                    data_href=req.href('newticket',
                                       [(self.mod.due_date_name, '')]),
                    class_='newticket-due-date'))),
            title=_("Create new ticket"),
            class_='ticketcalendar-newticket-box',
            style='display:none',
            data_writable=(None, 'writable')[can_create])

        class_ = ('ticketcalendar',
                  'ticketcalendar ticketcalendar-can-create')[can_create]
        return tag.div(header, calendar, ticket_box, class_=class_,
                       style=width and ('width: %s' % width) or None)
Example #50
0
    def gen_calendar(self, tickets, query, month, width=None, nav=True):
        milestones = self._get_milestones()

        req = self.req
        locale = self._get_locale()
        first_week_day = self._get_first_week_day(locale)
        start_date_format = self.mod.start_date_format
        due_date_format = self.mod.due_date_format

        if not month:
            month = datetime.now(req.tz)
            month = datetime(month.year, month.month, 1).date()

        # init data
        today = datetime.now(req.tz).date()

        # generate calendar data
        weeks = self._get_month_calendar(month.year, month.month,
                                         first_week_day, locale)
        days = sorted(sum(weeks, []))
        tickets = self._filter_tickets(days, tickets, req.tz)
        milestones = self._filter_milestones(days, milestones, req.tz)
        cal = [[{
            'date': day,
            'tickets': tickets[day],
            'milestones': milestones[day]
        } for day in week] for week in weeks]

        def genli(t):
            if isinstance(t, Milestone):
                return self._create_milestone_item(t)
            else:
                return self._create_ticket_item(t)

        def gentd(week_idx, day_info):
            day = day_info['date']
            tt = day_info['milestones'] + day_info['tickets']
            if len(tt) < 6:
                ttshow = tt
                ttall = []
            else:
                ttshow = tt[:4]
                ttall = tt

            tdclass = []
            if day == today:
                tdclass.append('today')
            if day.weekday() in (5, 6):
                tdclass.append('weekend')

            formatted_day = format_date(day, format='long', locale=locale)

            td = tag.td(class_=' '.join(tdclass),
                        data_for_start_date=day.strftime(start_date_format),
                        data_for_due_date=day.strftime(due_date_format),
                        data_fdate=formatted_day)

            label = []
            if day == today:
                label.append(tag.span(_("Today"), class_='today'))
            label.append(
                tag.span(unicode(day.day),
                         class_=('day normal', 'day')[day == today]))
            td(tag.div(label))
            if ttshow:
                td(tag.ul([genli(t) for t in ttshow]))

            if ttall:
                id = 'calendar-more-%s' % str(day)
                td(
                    tag.a(_("%d more tickets...") % (len(ttall) - 4),
                          href='#' + id,
                          class_='show-all-list'),
                    tag.div(tag.h4(formatted_day),
                            tag.ul([genli(t) for t in ttall]),
                            class_='ticketcalendar-popup-list',
                            id=id,
                            data_title=format_date(day,
                                                   locale=locale,
                                                   format='full')))

            return td

        day_names = get_day_names(locale=locale, width='abbreviated')
        day_names = [
            day_names[(idx + first_week_day) % 7] for idx in xrange(7)
        ]

        header = tag.div(class_='ticketcalendar-header')
        if nav:

            def nav_href(d):
                return self.get_box_href(query, d)

            def nav_pager(d):
                return tag.span(tag.a(u'\u25c4',
                                      href=nav_href(d - timedelta(days=1))),
                                tag.a(_("Current month"),
                                      href=nav_href(date.today())),
                                tag.a(u'\u25ba',
                                      href=nav_href(d + timedelta(days=31))),
                                class_='ticketcalendar-pager')

            def nav_macro():
                macro = (
                    '[[TicketCalendar(type=box,month=%(month)s,'
                    'query=%(query)s,order=%(order)s%(extra)s)]]' %
                    (dict(month=month.strftime('%Y-%m'),
                          query=self.build_query_string(query.constraints),
                          order=query.order,
                          extra=query.desc and ',desc=1' or '')))
                text = tag.input(type='text',
                                 readonly='readonly',
                                 size='80',
                                 value=macro,
                                 style='width:0;display:none')
                return tag.span(_("Macro"),
                                text,
                                class_='ticketcalendar-macro')

            header(
                tag.div(nav_macro(),
                        nav_pager(month),
                        class_='ticketcalendar-nav'))

        header(
            tag.h4(
                _("%(month_name)s, %(year)s",
                  month_name=_get_month_name(month, locale),
                  year=month.year)))

        calendar = tag.table(
            tag.thead(tag.tr(tag.th(name) for name in day_names)),
            tag.tbody([
                tag.tr([gentd(idx, d) for d in w]) for idx, w in enumerate(cal)
            ]),
            class_='calendar')

        can_create = 'TICKET_CREATE' in req.perm

        ticket_box = tag.div(
            tag.h4(tag.span('', class_='tc-today-date')),
            tag.ul(
                tag.li(
                    tag.a(tag_(
                        "New ticket with \"%(date)s\" as the start date",
                        date=tag.span('', data='start-date')),
                          data_href=req.href('newticket',
                                             [(self.mod.start_date_name, '')]),
                          class_='newticket-start-date')),
                tag.li(
                    tag.a(tag_("New ticket with \"%(date)s\" as the due date",
                               date=tag.span('', data='due-date')),
                          data_href=req.href('newticket',
                                             [(self.mod.due_date_name, '')]),
                          class_='newticket-due-date'))),
            title=_("Create new ticket"),
            class_='ticketcalendar-newticket-box',
            style='display:none',
            data_writable=(None, 'writable')[can_create])

        class_ = ('ticketcalendar',
                  'ticketcalendar ticketcalendar-can-create')[can_create]
        return tag.div(header,
                       calendar,
                       ticket_box,
                       class_=class_,
                       style=width and ('width: %s' % width) or None)