def render_voter(self, req): resource = self.normalise_resource(req.path_info) vote = self.get_vote(req, resource) up = tag.img(src=req.href.chrome('vote/' + self.image_map[vote][0]), alt='Up-vote') down = tag.img(src=req.href.chrome('vote/' + self.image_map[vote][1]), alt='Down-vote') if 'VOTE_MODIFY' in req.perm and get_reporter_id(req) != 'anonymous': down = tag.a(down, id='downvote', href=req.href.vote('down', resource), title='Down-vote') up = tag.a(up, id='upvote', href=req.href.vote('up', resource), title='Up-vote') add_script(req, 'vote/js/tracvote.js') shown = req.session.get('shown_vote_message') if not shown: add_notice(req, 'You can vote for resources on this Trac ' 'install by clicking the up-vote/down-vote arrows ' 'in the context navigation bar.') req.session['shown_vote_message'] = '1' body, title = self.format_votes(resource) votes = tag.span(body, id='votes') add_stylesheet(req, 'vote/css/tracvote.css') elm = tag.span(up, votes, down, id='vote', title=title) req.chrome.setdefault('ctxtnav', []).insert(0, elm)
def f(stream): # Update the closed value n = closure_state[0] closure_state[0] += 1 # Extract the user information author = data['events'][n]['author'].strip() user_info = cache.get(author) if user_info is not None: author, name, email = user_info else: db = self.env.get_db_cnx() user_info = self._get_info(author, db) cache[author] = user_info author, name, email = user_info # Try to find a provider for provider in self.providers: href = provider.get_hackergotchi(req.href, author, name, email) if href is not None: break else: href = req.href.chrome('hackergotchi', 'default.png') # Build our element elm = tag.img(src=href, alt='Hackergotchi for %s' % author, class_='hackergotchi') # Output the combined stream return itertools.chain(elm.generate(), stream)
def f(stream): # Update the closed value n = closure_state[0] closure_state[0] += 1 # Extract the user information author = data["events"][n]["author"].strip() user_info = cache.get(author) if user_info is not None: author, name, email = user_info else: db = self.env.get_db_cnx() user_info = self._get_info(author, db) cache[author] = user_info author, name, email = user_info # Try to find a provider for provider in self.providers: href = provider.get_hackergotchi(req.href, author, name, email) if href is not None: break else: href = req.href.chrome("hackergotchi", "default.png") # Build our element elm = tag.img(src=href, alt="Hackergotchi for %s" % author, class_="hackergotchi") # Output the combined stream return itertools.chain(elm.generate(), stream)
def render_timeline_event(self, context, field, event): """Display the title of the event in the given context. Full description here http://trac.edgewall.org/browser/trunk/trac/timeline/api.py """ if field == 'url': return event[3]['url'] elif field == 'title': return "Build %s #%s was %s" % (event[3]['builder'], event[3]['num'], event[0]) elif field == 'description': data = event[3] msg = tag.span() if data['source'] and data["rev"]: rev_msg = tag.div("rev: ", tag.a(data['rev'][:7], href=context.href("/browser/%s" % data['source'], rev=data['rev'])), " ", tag.a(tag.img(src=context.href("/chrome/common/changeset.png")), href=context.href("/changeset/%s/%s" % (data['rev'], data['source']))) ) msg.append(rev_msg) if 'error' in event[3] and event[3]['error']: error_msg = tag.div(event[3]['error'], " ") if 'error_log' in event[3] and event[3]['error_log']: error_msg.append(tag.a("Log", href=event[3]['error_log'])) msg.append(error_msg) return msg
def get_html(self, total, horas_semanas): valor_hora = self.data['valor_hora'] text = ['Horas trabajadas: %.2f' % total, 'Precio en dolares (U$S%s): %.2f' % (valor_hora, total * valor_hora)] text.extend(['Horas semana %s: %.2f' % (nro+1, horas) for nro, horas in horas_semanas.items()]) div = tag.div() ul = tag.ul() for li in text: ul.append(tag.li(li)) if 'date' in self.data: link = tag.a('@netlandish: Grinch report', href=self._get_grinch_report_url()) ul.append(link) div.append(ul) img = tag.img(src=self._get_google_chart(horas_semanas)) div.append(img) ul = tag.ul() for project, hours in self.hours.iteritems(): ul.append(tag.li('{0}: {1}'.format(project.title(), hours))) div.append(ul) return div
def expand_macro(self, formatter, name, content, args = None): if args is None: args = {} if name[-4:] in ('_svg', '_png'): name, type = name.split('_') else: type = (args.get('type') or self._default_type).lower() if type not in ('svg', 'png'): return system_message("Invalid type(%s). Type must be 'svg' or 'png'" % type) font = self._font # nonascii unicode can't be passed to hashlib. id = make_hash('%s,%s,%s,%r' % (name, type, font, content)).hexdigest() ## Create img tag. params = { "src": formatter.req.href("%s/%s.%s" % (name, id, type)) } for key, value in args.iteritems(): if key != "type": params[key] = value output = tag.img(**params) ## Generate image and cache it. def generate_image(): infile = mktemp(prefix='%s-' % name) outfile = mktemp(prefix='%s-' % name) try: try: f = codecs.open(infile, 'w', 'utf8') try: f.write(content) finally: f.close() cmd = [name, '-a', '-T', type, '-o', outfile, infile] if font: cmd.extend(['-f', font]) self.env.log.debug('(%s) command: %r' % (name, cmd)) try: proc = Popen(cmd, stderr=PIPE) stderr_value = proc.communicate()[1] except Exception, e: self.env.log.error('(%s) %r' % (name, e)) raise ImageGenerationError("Failed to generate diagram. (%s is not found.)" % name) if proc.returncode != 0 or not os.path.isfile(outfile): self.env.log.error('(%s) %s' % (name, stderr_value)) raise ImageGenerationError("Failed to generate diagram. (rc=%d)" % proc.returncode) f = open(outfile, 'rb') try: data = f.read() finally: f.close() return data except ImageGenerationError: raise except Exception, e: self.env.log.error('(%s) %r' % (name, e)) raise ImageGenerationError("Failed to generate diagram.")
def filter_stream(self, req, method, filename, stream, data): """ Reformat the ``branch`` field of a ticket to show the history of the linked branch. """ ticket = data.get('ticket') if filename in self._templates and ticket: add_stylesheet(req, 'sage_trac/sage-ticket.css') else: return stream filters = [ # Add additional color coding to the ticket ID FILTER_ID.attr('class', 'trac-id-{0}'.format(ticket['status'])), ] if self.patchbot_url: # Add the patchbot status icons if a patchbot URL was given nonce = hex(random.randint(0, 1 << 60)) ticket_url = '{0}/ticket/{1}'.format( self.patchbot_url.rstrip('/'), ticket.id) base_url = '{0}/base.svg?nonce={1}'.format(ticket_url, nonce) status_url = '{0}/status.svg?nonce={1}'.format(ticket_url, nonce) elem = tag.div( tag.a( tag.img(src=base_url, border=0, height=32), tag.img(src=status_url, border=0, height=32), href=ticket_url), class_='date') filters.append(FILTER_DATE.after(elem)) filters.extend(self._get_branch_filters(req, ticket)) def apply_filters(filters): s = stream for filter in filters: s |= filter return s return apply_filters(filters)
def expand_macro(self, formatter, name, content): if not self.plantuml_jar: return system_message( _("Installation error: plantuml_jar option not defined in trac.ini" )) if not os.path.exists(self.plantuml_jar): return system_message( _("Installation error: plantuml.jar not found at '%s'") % self.plantuml_jar) # Trac 0.12 supports expand_macro(self, formatter, name, content, args) # which allows us to readily differentiate between a WikiProcess and WikiMacro # call. To support Trac 0.11, some additional work is required. try: args = formatter.code_processor.args except AttributeError: args = None path = None if not 'path' in args: #Could be WikiProcessor or WikiMacro call if content.strip().startswith("@startuml"): markup = content path = None else: path = content if not path: return system_message(_("Path not specified")) elif args: #WikiProcessor with args path = args.get('path') if not path: return system_message(_("Path not specified")) if path: markup, exists = self._read_source_from_repos(formatter, path) if not exists: return system_message( _("File not found in repository: " + path)) else: if not content: return system_message(_("No UML text defined")) markup = content.encode('utf-8').strip() img_id = hashlib.sha1(markup).hexdigest() if not self._is_img_existing(img_id): cmd = '%s -jar -Djava.awt.headless=true "%s" -charset UTF-8 -pipe' % ( self.java_bin, self.plantuml_jar) p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE) (img_data, stderr) = p.communicate(input=markup) if p.returncode != 0: return system_message( _("Error running plantuml: '%s'") % stderr) self._write_img_to_file(img_id, img_data) link = formatter.href('plantuml', id=img_id) return tag.img(src=link)
def annotate_row(self, context, row, lineno, line, data): htmlImageString = '<img src="' + self.imagePath + '">' #make line number light gray if(lineno <= self.lineEnd and lineno >= self.lineStart): #if there is a comment on this line if(self.comments.has_key(lineno)): #if there is more than 0 comments if(self.comments[lineno] > 0): return row.append(tag.th(id='L%s' % lineno)(tag.a(tag.img(src='%s' % self.imagePath) + ' ' + str(lineno), href='javascript:getComments(%s, %s)' % (lineno, self.fileID)))) return row.append(tag.th(id='L%s' % lineno)(tag.a(lineno, href='javascript:addComment(%s, %s, -1)' % (lineno, self.fileID)))) return row.append(tag.th(id='L%s' % lineno)(tag.font(lineno, color='#CCCCCC')))
def _format_emoji(self, formatter, emoji): emoji_image = self.EMOJIS.get(emoji) if emoji_image is None: return emoji else: return tag.img( src=formatter.href.chrome('/%s%s/%s' %( self.HTDOCS_PREFIX, self.EMOJI_DIR, emoji_image)), alt=emoji, title=emoji, style=self.STYLE)
def _format_emoji(self, formatter, emoji): emoji_image = self.EMOJIS.get(emoji) if emoji_image is None: return emoji else: return tag.img(src=formatter.href.chrome( '/%s%s/%s' % (self.HTDOCS_PREFIX, self.EMOJI_DIR, emoji_image)), alt=emoji, title=emoji, style=self.STYLE)
def filter_stream(self, req, method, filename, stream, data): """Return a filtered Genshi event stream, or the original unfiltered stream if no match. `req` is the current request object, `method` is the Genshi render method (xml, xhtml or text), `filename` is the filename of the template to be rendered, `stream` is the event stream and `data` is the data for the current template. See the Genshi documentation for more information. """ # only show CAPTCHAs for anonymous users if req.authname != 'anonymous': return stream # only put CAPTCHAs in the realms specified realm = self.realm(req) if realm not in self.realms: return stream # add the CAPTCHA to the stream if filename in self.xpath: # store CAPTCHA in DB and session word = random_word(self.dict_file) insert_update(self.env, 'captcha', 'id', req.session.sid, dict(word=word)) req.session['captcha'] = word req.session.save() # render the template chrome = Chrome(self.env) template = chrome.load_template('captcha.html') _data = {} # CAPTCHA type if self.captcha_type == 'png': captcha = tag.img(None, src=req.href('captcha.png')) else: captcha = Markup(skimpyAPI.Pre(word).data()) _data['captcha'] = captcha _data['email'] = req.session.get('email', '') _data['name'] = req.session.get('name', '') _data['captchaid'] = req.session.sid xpath = self.xpath[filename] stream |= Transformer(xpath).before(template.generate(**_data)) if filename in self.delete: stream |= Transformer(self.delete[filename]).remove() return stream
def _render_icon(self, formatter, name, size): if not name: return size = size.upper()[0] if size else 'S' name = name.lower() if any(x in name for x in ['*', '?']): #noinspection PyArgumentList return ShowIcons(self.env)._render( formatter, 2, name, size, True, self.icon_limit) else: loc = self.icon_location(size) return tag.img(src=formatter.href.chrome(loc[0], name + '.png'), alt=name, style="vertical-align: text-bottom")
def _render_icon(self, formatter, name, size): if not name: return size = size.upper()[0] if size else 'S' name = name.lower() if any(x in name for x in ['*', '?']): #noinspection PyArgumentList return ShowIcons(self.env)._render( formatter, 2, name, size, True, self.icon_limit) else: loc = self.icon_location(size) return tag.img(src=formatter.href.chrome(loc[0], '%s.png' % name), alt=name, style="vertical-align: text-bottom")
def _create_hatena_bookmark_button(self, url, locale): href = '//b.hatena.ne.jp/entry/' if url: href += url.replace('#', '%23') return [ tag.a(tag.img(src='//b.st-hatena.com/images/entry-button/button-only.gif', alt=u'このエントリーをはてなブックマークに追加', width='20', height='20', style='border:none'), href=href, class_='hatena-bookmark-button', data_hatena_bookmark_layout=self._hatena_bookmark_layout, title=u'このエントリーをはてなブックマークに追加'), tag.script(type='text/javascript', charset='utf-8', async='async', src='//b.st-hatena.com/js/bookmark_button_wo_al.js'), ]
def expand_macro(self, formatter, name, content): website = urllib2.urlopen("http://icanhascheezburger.com/") website_html = website.read() beg_pos = -1 beg_pos = website_html.find('<img src="', beg_pos + 1) end_pos = website_html.find('"', beg_pos + 10) raw_url = website_html[beg_pos + 10:end_pos] attr = {} out = tag.img(src=raw_url, **attr) return out
def expand_macro(self, formatter, name, content): if not self.plantuml_jar: return system_message(_("Installation error: plantuml_jar option not defined in trac.ini")) if not os.path.exists(self.plantuml_jar): return system_message(_("Installation error: plantuml.jar not found at '%s'") % self.plantuml_jar) # Trac 0.12 supports expand_macro(self, formatter, name, content, args) # which allows us to readily differentiate between a WikiProcess and WikiMacro # call. To support Trac 0.11, some additional work is required. try: args = formatter.code_processor.args except AttributeError: args = None path = None if not args: #Could be WikiProcessor or WikiMacro call if content.strip().startswith("@startuml"): markup = content path = None else: path = content if not path: return system_message(_("Path not specified")) elif args: #WikiProcessor with args path = args.get('path') if not path: return system_message(_("Path not specified")) if path: markup, exists = self._read_source_from_repos(formatter, path) if not exists: return markup else: if not content: return system_message(_("No UML text defined")) markup = content.encode('utf-8').strip() img_id = hashlib.sha1(markup).hexdigest() if not self._is_img_existing(img_id): cmd = '%s -jar -Djava.awt.headless=true "%s" -charset UTF-8 -pipe' % (self.java_bin, self.plantuml_jar) p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE) (img_data, stderr) = p.communicate(input=markup) if p.returncode != 0: stderr = stderr.decode(sys.getfilesystemencoding()) return system_message(_("Error running plantuml: '%s'") % stderr) self._write_img_to_file(img_id, img_data) link = formatter.href('plantuml', id=img_id) return tag.img(src=link)
def expand_macro(self, formatter, name, content): self.log.info('expand_macro') sha_key = sha.new(content).hexdigest() img_name = "%s.png" % (sha_key) img_path = os.path.join(self.cache_dir, img_name) cmd = [self.proc_path, '-T', 'png', '-o', img_path] self.log.info("cmd=%s" % (' '.join(cmd))) out, err = self.launch(cmd, content) if out or err: msg = 'The command\n %s\nfailed with the the following output:\n%s\n%s' % (cmd, out, err) return err img_url = formatter.href.mscgen(img_name) return tag.img(src=img_url, alt=_("mscgen image"))
def user_scattered(hist, avg): #adding two entries for the velocity line: hist += [ (0,0), (15, 15*avg) ] est = ",".join(map(lambda t: str( int( (t[0]/25.0) * 100 ) ), hist)) act = ",".join(map(lambda t: str( int( (t[1]/25.0) * 100 ) ), hist)) return tag.img( src="http://chart.apis.google.com/chart?%s&%s&%s&%s&%s&%s&%s" % ( "cht=s", "chs=350x350", "chxr=0,0,25,5|1,0,25,5", "chxt=x,y,x,y", "chxl=2:||expected|3:||actual|", "chd=t:%s|%s" % (est, act), "chm=o,0000FF,0,-1,6|D,000000,1,-2:,1,-1|o,FF0000,0,0:%d:,5" % (len(hist)-3), ), alt="estemated to actual chart")
def expand_macro(self, formatter, name, content): self.log.info('expand_macro') sha_key = sha.new(content).hexdigest() img_name = "%s.png" % (sha_key) img_path = os.path.join(self.cache_dir, img_name) cmd = [self.proc_path, '-T', 'png', '-o', img_path] self.log.info("cmd=%s" % (' '.join(cmd))) out, err = self.launch(cmd, content) if out or err: msg = 'The command\n %s\nfailed with the the following output:\n%s\n%s' % ( cmd, out, err) return err img_url = formatter.href.mscgen(img_name) return tag.img(src=img_url, alt=_("mscgen image"))
def get_ajax(self, macroenv, req, content): macroenv.tracenv.log.debug("AJAX: %s" % (content,) ) myhash = hashlib.md5(content).hexdigest() ajax_url = "/projectplan_service/%s" % (urllib.quote_plus(content),) return tag.div( tag.div( tag.div( tag.a(tag.img( src="%s/%s" % (macroenv.tracreq.href.chrome( 'projectplan', macroenv.PPConstant.RelDocPath ), 'loading.gif' ), style='display:none;margin-right:2ex;margin-top:3ex;', title='computing projectplan report' ), tag.span("project report is loading"), href=ajax_url, style='padding:3ex;text-align:center;' ), id="%s_inner" % myhash, style="height:8ex;" ), id=myhash, style="height:8ex" ), tag.script(''' $(document).ready(function(){ $.ajax({ url: "%s", cache: false, beforeSend: function(){ $("#%s img").show(); }, success: function(data){ $("#%s").hide().after(data); ppAddTooltipWrapper("#%s"); }, error: function(jqXHR, textStatus, errorThrown){ $("#%s a").first().html("Error: report (of ProjectPlan) could not be rendered.").css({padding:"0",margin:"auto"}); $("#%s").addClass("system-message").css({height:"auto"}); $("#%s_inner").css({height:"auto"}); } }); }); ''' % (ajax_url, myhash, myhash, myhash, myhash, myhash, myhash )) )
def img(macro, environ, data, *args, **kwargs): """Displays an image, HTML <img>. This macro allows you to display a custom image, HTML <img> element and contrib various attributes such as style, class, id, etc. **Arguments:** * id=None (//the id attribute//) * alt=None (//the alt attribute//) * class=None (//the class attribute//) * style=None (//the style attribute//) **Example(s):** {{{ <<img "/img/python.png">> }}} <<img "/img/python.png">> """ if not args: return None src = args[0] id = kwargs.get("id", None) alt = kwargs.get("alt", None) cls = kwargs.get("class", None) style = kwargs.get("style", None) if style: style = ";".join(sanitizer.sanitize_css(style)) attrs = {} if id: attrs["id"] = id if alt: attrs["alt"] = alt if cls: attrs["class_"] = cls if style: attrs["style"] = style return tag.img(src=src, **attrs)
def _add_title(self, data, tagname, attr_name, prefix, after_stream, depth): """ In case of data parameter as element has same tagname attribute for the parameter and attribute named the attr_name starts with the prefix, add description in title attribute and rel attribute to the element and store div element generated to after_stream[depth] for later use. (In Japanese/KANJI) data で与えられた要素が、引数で指定された tagname であり、attr_name 属性の値が prefix で始まる場合、 説明文をtitle属性およびrel属性としてその要素に設定します。 またそのとき、after_stream[depth] に DIV 要素を格納します。 """ element, attrs = data attr_value = attrs.get(attr_name) if element.localname == tagname and attr_value and attr_value.startswith( prefix): attr_value = attr_value[len(prefix):] attr_value_locale = "%s.%s" % (attr_value, self.locale) text = self.parent.pages.get( attr_value_locale, self.parent.pages.get( attr_value, FieldTooltip._default_pages.get( attr_value_locale, FieldTooltip._default_pages.get(attr_value)))) if text: attrs |= [(QName('title'), attr_value + ' | ' + text)] attrs |= [(QName('rel'), '#tooltip-' + attr_value)] img = tag.img(src='%s/chrome/common/wiki.png' \ % self.context.req.base_url, alt='?', align='right') a = tag.a(img, href='%s/wiki/%s%s' \ % (self.context.req.base_url, FieldTooltip._wiki_prefix, attr_value)) after_stream[str(depth)] = \ tag.div(a, '%s:\n' % attr_value, format_to_html(self.parent.env, self.context, text, False), id='tooltip-' + attr_value, class_='tooltip', style='display: none') data = element, attrs return data
def expand_macro(self, formatter, name, content): content = content or '' args = content.split(',') # HTML arguments used in Pledgie URL (future maybe...) hargs = {'key': self.env.config.get('pledgie', 'campaign_id', None)} if not content: raise TracError("No campaign id given! The campaign id can " \ "be found in the pledgie url, e.g. " \ "http://pledgie.com/campaigns/ID\n") return tag.a(tag.img(src = "http://www.pledgie.com/campaigns/" \ + args[0] + ".png" # title = Markup.escape(title, quotes=True), # alt = Markup.escape(alt, quotes=True), ), class_ = "pledgiemacro", href = "http://www.pledgie.com/campaigns/" + args[0] )
def expand_macro(self, formatter, name, content): content = content or '' args = content.split(',') # HTML arguments used in Pledgie URL (future maybe...) hargs = { 'key': self.env.config.get('pledgie', 'campaign_id', None)} if not content: raise TracError("No campaign id given! The campaign id can " \ "be found in the pledgie url, e.g. " \ "http://pledgie.com/campaigns/ID\n") return tag.a(tag.img(src = "http://www.pledgie.com/campaigns/" \ + args[0] + ".png" # title = Markup.escape(title, quotes=True), # alt = Markup.escape(alt, quotes=True), ), class_ = "pledgiemacro", href = "http://www.pledgie.com/campaigns/" + args[0] )
def _create_hatena_bookmark_button(self, url, locale): href = '//b.hatena.ne.jp/entry/' if url: href += url.replace('#', '%23') return [ tag.a(tag.img( src='//b.st-hatena.com/images/entry-button/button-only.gif', alt=u'このエントリーをはてなブックマークに追加', width='20', height='20', style='border:none'), href=href, class_='hatena-bookmark-button', data_hatena_bookmark_layout=self._hatena_bookmark_layout, title=u'このエントリーをはてなブックマークに追加'), tag.script(type='text/javascript', charset='utf-8', async='async', src='//b.st-hatena.com/js/bookmark_button_wo_al.js'), ]
def view(self): if self.name not in self.storage: data = {"name": self.name} self.storage.reopen() self.search.update(self.environ) name, _ = os.path.splitext(self.name) data["results"] = sorted(self.search.find((name,)), key=itemgetter(0), reverse=True)[:5] return self.render("notfound.html", **data) data = { "title": self.name, "name": self.name, "html": tag.img( alt=self.name, src=self.uri("/+download/%s" % self.name) ), "ctxnav": list(self.environ._ctxnav("view", self.name)), } return self.render("view.html", **data)
def annotate_row(self, context, row, lineno, line, data): htmlImageString = '<img src="' + self.imagePath + '">' #make line number light gray if (lineno <= self.lineEnd and lineno >= self.lineStart): #if there is a comment on this line if (self.comments.has_key(lineno)): #if there is more than 0 comments if (self.comments[lineno] > 0): return row.append( tag.th(id='L%s' % lineno)( tag.a(tag.img(src='%s' % self.imagePath) + ' ' + str(lineno), href='javascript:getComments(%s, %s)' % (lineno, self.fileID)))) return row.append( tag.th(id='L%s' % lineno)( tag.a(lineno, href='javascript:addComment(%s, %s, -1)' % (lineno, self.fileID)))) return row.append( tag.th(id='L%s' % lineno)(tag.font(lineno, color='#CCCCCC')))
def get_ajax(self, macroenv, req, content): macroenv.tracenv.log.debug("AJAX: %s" % (content, )) myhash = hashlib.md5(content).hexdigest() ajax_url = "/projectplan_service/%s" % (urllib.quote_plus(content), ) return tag.div( tag.div(tag.div(tag.a(tag.img( src="%s/%s" % (macroenv.tracreq.href.chrome( 'projectplan', macroenv.PPConstant.RelDocPath), 'loading.gif'), style='display:none;margin-right:2ex;margin-top:3ex;', title='computing projectplan report'), tag.span("project report is loading"), href=ajax_url, style='padding:3ex;text-align:center;'), id="%s_inner" % myhash, style="height:8ex;"), id=myhash, style="height:8ex"), tag.script(''' $(document).ready(function(){ $.ajax({ url: "%s", cache: false, beforeSend: function(){ $("#%s img").show(); }, success: function(data){ $("#%s").hide().after(data); ppAddTooltipWrapper("#%s"); }, error: function(jqXHR, textStatus, errorThrown){ $("#%s a").first().html("Error: report (of ProjectPlan) could not be rendered.").css({padding:"0",margin:"auto"}); $("#%s").addClass("system-message").css({height:"auto"}); $("#%s_inner").css({height:"auto"}); } }); }); ''' % (ajax_url, myhash, myhash, myhash, myhash, myhash, myhash)))
def _format_link(self, formatter, ns, target, label): link, params, fragment = formatter.split_link(target) ids = link.split(':', 2) attachment = None if len(ids) == 3: known_realms = ResourceSystem(self.env).get_known_realms() # new-style attachment: TracLinks (filename:realm:id) if ids[1] in known_realms: attachment = Resource(ids[1], ids[2]).child('attachment', ids[0]) else: # try old-style attachment: TracLinks (realm:id:filename) if ids[0] in known_realms: attachment = Resource(ids[0], ids[1]).child('attachment', ids[2]) else: # local attachment: TracLinks (filename) attachment = formatter.resource.child('attachment', link) if attachment and 'ATTACHMENT_VIEW' in formatter.perm(attachment): try: model = Attachment(self.env, attachment) raw_href = get_resource_url(self.env, attachment, formatter.href, format='raw') if ns.startswith('raw'): return tag.a(label, class_='attachment', href=raw_href + params, title=get_resource_name(self.env, attachment)) href = get_resource_url(self.env, attachment, formatter.href) title = get_resource_name(self.env, attachment) img = tag.img(src=formatter.href.chrome('common/download.png'), alt=_("Download")) return tag(tag.a(label, class_='attachment', title=title, href=href + params), tag.span(" ", tag.a(img, class_='trac-rawlink', href=raw_href + params, title=_("Download")), class_="noprint")) except ResourceNotFound, e: pass
def macro_side_bar_file(macro, environ, *args, **kwargs): image = args[0] width = args[1] caption = args[2] return tag.div( tag.div( tag.a( tag.img( #width=width, class_='thumbimage', src='http://upload.wikimedia.org/wikipedia/commons/thumb/c/c7/Herz-Heart.jpg/350px-Herz-Heart.jpg' width=width, class_='thumbimage', src=reverse('media_preview', args=[image]) ), #href='http://upload.wikimedia.org/wikipedia/commons/thumb/c/c7/Herz-Heart.jpg/350px-Herz-Heart.jpg', class_='image' #href=reverse('media_display', args=[image]), class_='image fancybox-iframe' href=reverse('media_display', args=[image]), class_='image' ), tag.div( caption, class_='thumbcaption' ), style='width:%spx;' % width, class_='thumbinner', ), class_='thumb tright' )
def _add_title(self, data, tagname, attr_name, prefix, after_stream, depth): """ In case of data parameter as element has same tagname attribute for the parameter and attribute named the attr_name starts with the prefix, add description in title attribute and rel attribute to the element and store div element generated to after_stream[depth] for later use. (In Japanese/KANJI) data で与えられた要素が、引数で指定された tagname であり、attr_name 属性の値が prefix で始まる場合、 説明文をtitle属性およびrel属性としてその要素に設定します。 またそのとき、after_stream[depth] に DIV 要素を格納します。 """ element, attrs = data attr_value = attrs.get(attr_name) if element.localname == tagname and attr_value and attr_value.startswith(prefix): attr_value = attr_value[len(prefix):] attr_value_locale = "%s.%s" % (attr_value, self.locale) text = self.parent.pages.get(attr_value_locale, self.parent.pages.get(attr_value, FieldTooltip._default_pages.get(attr_value_locale, FieldTooltip._default_pages.get(attr_value)))) if text: attrs |= [(QName('title'), attr_value + ' | ' + text)] attrs |= [(QName('rel'), '#tooltip-' + attr_value)] img = tag.img(src='%s/chrome/common/wiki.png' \ % self.context.req.base_url, alt='?', align='right') a = tag.a(img, href='%s/wiki/%s%s' \ % (self.context.req.base_url, FieldTooltip._wiki_prefix, attr_value)) after_stream[str(depth)] = \ tag.div(a, '%s:\n' % attr_value, format_to_html(self.parent.env, self.context, text, False), id='tooltip-' + attr_value, class_='tooltip', style='display: none') data = element, attrs return data
def convert(self, data, dataSettings): if data is not None: if 'format' in dataSettings: format = dataSettings['format'] else: format = 'png' color = dataSettings.get('color', True) imageSrc = '../moldb/showMol?margin=0&molId=%s&uid=%s&format=%s&color=%s' % (data['molId'],data['uid'], format, color) style = None if 'size' in dataSettings: style = "width:%spx;" % dataSettings['size'] if format == 'svg': return tag.object(data=imageSrc,type="image/svg+xml", style=style) elif format == 'emf': # For IE copy/paste reasons, we will pass a width query parameter # rather than using a style setting. That way the copy from IE to # MS Office products will faithfully preserve the image size in the # table. if 'size' in dataSettings: dim=dataSettings['size'] imageSrc='%s&width=%s&height=%s' % (imageSrc, str(int(2*dim)), dim) return tag.img(src=imageSrc) else: return ""
def expand_macro(self, formatter, name, content): # args will be null if the macro is called without parenthesis. if not content: return '' # parse arguments # we expect the 1st argument to be a filename (filespec) args = content.split(',') if len(args) == 0: raise Exception("No argument.") # strip unicode white-spaces and ZWSPs are copied from attachments # section (#10668) filespec = stripws(args.pop(0)) # style information size_re = re.compile('[0-9]+(%|px)?$') attr_re = re.compile('(align|valign|border|width|height|alt' '|margin(?:-(?:left|right|top|bottom))?' '|title|longdesc|class|id|usemap)=(.+)') quoted_re = re.compile("(?:[\"'])(.*)(?:[\"'])$") attr = {} style = {} link = '' # helper for the special case `source:` # from trac.versioncontrol.web_ui import BrowserModule # FIXME: somehow use ResourceSystem.get_known_realms() # ... or directly trac.wiki.extract_link try: browser_links = [ res[0] for res in BrowserModule(self.env).get_link_resolvers() ] except Exception: browser_links = [] while args: arg = stripws(args.pop(0)) if size_re.match(arg): # 'width' keyword attr['width'] = arg elif arg == 'nolink': link = None elif arg.startswith('link='): val = arg.split('=', 1)[1] elt = extract_link(self.env, formatter.context, val.strip()) elt = find_element(elt, 'href') link = None if elt is not None: link = elt.attrib.get('href') elif arg in ('left', 'right'): style['float'] = arg elif arg == 'center': style['margin-left'] = style['margin-right'] = 'auto' style['display'] = 'block' style.pop('margin', '') elif arg in ('top', 'bottom', 'middle'): style['vertical-align'] = arg else: match = attr_re.match(arg) if match: key, val = match.groups() if (key == 'align' and val in ('left', 'right', 'center')) or \ (key == 'valign' and \ val in ('top', 'middle', 'bottom')): args.append(val) elif key in ('margin-top', 'margin-bottom'): style[key] = ' %dpx' % int(val) elif key in ('margin', 'margin-left', 'margin-right') \ and 'display' not in style: style[key] = ' %dpx' % int(val) elif key == 'border': style['border'] = ' %dpx solid' % int(val) else: m = quoted_re.search(val) # unquote "..." and '...' if m: val = m.group(1) attr[str(key)] = val # will be used as a __call__ kwd # parse filespec argument to get realm and id if contained. parts = [ i.strip('''['"]''') for i in self._split_filespec_re.split(filespec) ] url = raw_url = desc = None attachment = None if (parts and parts[0] in ('http', 'https', 'ftp')): # absolute raw_url = url = filespec desc = url.rsplit('?')[0] elif filespec.startswith('//'): # server-relative raw_url = url = filespec[1:] desc = url.rsplit('?')[0] elif filespec.startswith('/'): # project-relative params = '' if '?' in filespec: filespec, params = filespec.rsplit('?', 1) url = formatter.href(filespec) if params: url += '?' + params raw_url, desc = url, filespec elif len(parts) == 3: # realm:id:attachment-filename # # or intertrac:realm:id realm, id, filename = parts intertrac_target = "%s:%s" % (id, filename) it = formatter.get_intertrac_url(realm, intertrac_target) if it: url, desc = it raw_url = url + unicode_quote('?format=raw') else: attachment = Resource(realm, id).child('attachment', filename) elif len(parts) == 2: realm, filename = parts if realm in browser_links: # source:path # TODO: use context here as well rev = None if '@' in filename: filename, rev = filename.rsplit('@', 1) url = formatter.href.browser(filename, rev=rev) raw_url = formatter.href.browser(filename, rev=rev, format='raw') desc = filespec else: # #ticket:attachment or WikiPage:attachment # FIXME: do something generic about shorthand forms... realm = None id, filename = parts if id and id[0] == '#': realm = 'ticket' id = id[1:] elif id == 'htdocs': raw_url = url = formatter.href.chrome('site', filename) desc = os.path.basename(filename) elif id == 'shared': raw_url = url = formatter.href.chrome('shared', filename) desc = os.path.basename(filename) else: realm = 'wiki' if realm: attachment = Resource(realm, id).child('attachment', filename) elif len(parts) == 1: # it's an attachment of the current resource attachment = formatter.resource.child('attachment', filespec) else: raise TracError('No filespec given') if attachment and 'ATTACHMENT_VIEW' in formatter.perm(attachment): url = get_resource_url(self.env, attachment, formatter.href) raw_url = get_resource_url(self.env, attachment, formatter.href, format='raw') try: desc = get_resource_summary(self.env, attachment) except ResourceNotFound as e: raw_url = formatter.href.chrome('common/attachment.png') desc = _('No image "%(id)s" attached to %(parent)s', id=attachment.id, parent=get_resource_name(self.env, attachment.parent)) for key in ('title', 'alt'): if desc and not key in attr: attr[key] = desc if style: attr['style'] = '; '.join('%s:%s' % (k, escape(v)) for k, v in style.iteritems()) result = tag.img(src=raw_url, **attr) if link is not None: result = tag.a(result, href=link or url, style='padding:0; border:none') return result
class ImageMacro(WikiMacroBase): """Embed an image in wiki-formatted text. The first argument is the file specification. The file specification may reference attachments in three ways: * `module:id:file`, where module can be either '''wiki''' or '''ticket''', to refer to the attachment named ''file'' of the specified wiki page or ticket. * `id:file`: same as above, but id is either a ticket shorthand or a Wiki page name. * `file` to refer to a local attachment named 'file'. This only works from within that wiki page or a ticket. Also, the file specification may refer to repository files, using the `source:file` syntax (`source:file@rev` works also). Files can also be accessed with a direct URLs; `/file` for a project-relative, `//file` for a server-relative, or `http://server/file` for absolute location of the file. The remaining arguments are optional and allow configuring the attributes and style of the rendered `<img>` element: * digits and unit are interpreted as the size (ex. 120, 25%) for the image * `right`, `left`, `center`, `top`, `bottom` and `middle` are interpreted as the alignment for the image (alternatively, the first three can be specified using `align=...` and the last three using `valign=...`) * `link=some TracLinks...` replaces the link to the image source by the one specified using a TracLinks. If no value is specified, the link is simply removed. * `nolink` means without link to image source (deprecated, use `link=`) * `key=value` style are interpreted as HTML attributes or CSS style indications for the image. Valid keys are: * align, valign, border, width, height, alt, title, longdesc, class, margin, margin-(left,right,top,bottom), id and usemap * `border`, `margin`, and `margin-`* can only be a single number * `margin` is superseded by `center` which uses auto margins Examples: {{{ [[Image(photo.jpg)]] # simplest [[Image(photo.jpg, 120px)]] # with image width size [[Image(photo.jpg, right)]] # aligned by keyword [[Image(photo.jpg, nolink)]] # without link to source [[Image(photo.jpg, align=right)]] # aligned by attribute }}} You can use image from other page, other ticket or other module. {{{ [[Image(OtherPage:foo.bmp)]] # if current module is wiki [[Image(base/sub:bar.bmp)]] # from hierarchical wiki page [[Image(#3:baz.bmp)]] # if in a ticket, point to #3 [[Image(ticket:36:boo.jpg)]] [[Image(source:/images/bee.jpg)]] # straight from the repository! [[Image(htdocs:foo/bar.png)]] # image file in project htdocs dir. }}} ''Adapted from the Image.py macro created by Shun-ichi Goto <*****@*****.**>'' """ def expand_macro(self, formatter, name, content): # args will be null if the macro is called without parenthesis. if not content: return '' # parse arguments # we expect the 1st argument to be a filename (filespec) args = content.split(',') if len(args) == 0: raise Exception("No argument.") filespec = args.pop(0) # style information size_re = re.compile('[0-9]+(%|px)?$') attr_re = re.compile('(align|valign|border|width|height|alt' '|margin(?:-(?:left|right|top|bottom))?' '|title|longdesc|class|id|usemap)=(.+)') quoted_re = re.compile("(?:[\"'])(.*)(?:[\"'])$") attr = {} style = {} link = '' while args: arg = args.pop(0).strip() if size_re.match(arg): # 'width' keyword attr['width'] = arg elif arg == 'nolink': link = None elif arg.startswith('link='): val = arg.split('=', 1)[1] elt = extract_link(self.env, formatter.context, val.strip()) link = None if isinstance(elt, Element): link = elt.attrib.get('href') elif arg in ('left', 'right'): style['float'] = arg elif arg == 'center': style['margin-left'] = style['margin-right'] = 'auto' style['display'] = 'block' style.pop('margin', '') elif arg in ('top', 'bottom', 'middle'): style['vertical-align'] = arg else: match = attr_re.match(arg) if match: key, val = match.groups() if (key == 'align' and val in ('left', 'right', 'center')) or \ (key == 'valign' and \ val in ('top', 'middle', 'bottom')): args.append(val) elif key in ('margin-top', 'margin-bottom'): style[key] = ' %dpx' % int(val) elif key in ('margin', 'margin-left', 'margin-right') \ and 'display' not in style: style[key] = ' %dpx' % int(val) elif key == 'border': style['border'] = ' %dpx solid' % int(val) else: m = quoted_re.search(val) # unquote "..." and '...' if m: val = m.group(1) attr[str(key)] = val # will be used as a __call__ kwd # parse filespec argument to get realm and id if contained. parts = filespec.split(':') url = raw_url = desc = None attachment = None if (parts and parts[0] in ('http', 'https', 'ftp')): # absolute raw_url = url = desc = filespec elif filespec.startswith('//'): # server-relative raw_url = url = desc = filespec[1:] elif filespec.startswith('/'): # project-relative # use href, but unquote to allow args (use default html escaping) raw_url = url = desc = unquote(formatter.href(filespec)) elif len(parts) == 3: # realm:id:attachment-filename realm, id, filename = parts attachment = Resource(realm, id).child('attachment', filename) elif len(parts) == 2: # FIXME: somehow use ResourceSystem.get_known_realms() # ... or directly trac.wiki.extract_link from trac.versioncontrol.web_ui import BrowserModule try: browser_links = [res[0] for res in BrowserModule(self.env).get_link_resolvers()] except Exception: browser_links = [] if parts[0] in browser_links: # source:path # TODO: use context here as well realm, filename = parts rev = None if '@' in filename: filename, rev = filename.split('@') url = formatter.href.browser(filename, rev=rev) raw_url = formatter.href.browser(filename, rev=rev, format='raw') desc = filespec else: # #ticket:attachment or WikiPage:attachment # FIXME: do something generic about shorthand forms... realm = None id, filename = parts if id and id[0] == '#': realm = 'ticket' id = id[1:] elif id == 'htdocs': raw_url = url = formatter.href.chrome('site', filename) desc = os.path.basename(filename) else: realm = 'wiki' if realm: attachment = Resource(realm, id).child('attachment', filename) elif len(parts) == 1: # it's an attachment of the current resource attachment = formatter.resource.child('attachment', filespec) else: raise TracError('No filespec given') if attachment and 'ATTACHMENT_VIEW' in formatter.perm(attachment): url = get_resource_url(self.env, attachment, formatter.href) raw_url = get_resource_url(self.env, attachment, formatter.href, format='raw') try: desc = get_resource_summary(self.env, attachment) except ResourceNotFound, e: raw_url = formatter.href.chrome('common/attachment.png') desc = _('No image "%(id)s" attached to %(parent)s', id=attachment.id, parent=get_resource_name(self.env, attachment.parent)) for key in ('title', 'alt'): if desc and not key in attr: attr[key] = desc if style: attr['style'] = '; '.join('%s:%s' % (k, escape(v)) for k, v in style.iteritems()) result = tag.img(src=raw_url, **attr) if link is not None: result = tag.a(result, href=link or url, style='padding:0; border:none') return result
def expand_macro(self, formatter_or_context, name, content): """Return the HTML output of the macro. :param formatter_or_context: a Formatter when called as a macro, a Context when called by `MetapostPlugin.render` :param name: Wiki macro command that resulted in this method being called. In this case, it should be 'metapost' by an output format, as following: metapost/<format> Valid output formats are: jpg, png, gif, svg and svgz. The default is the value specified in the out_format configuration parameter. If out_format is not specified in the configuration, then the default is png. examples: metapost/png -> png metapost/jpeg -> jpeg metapost/jpg -> jpg metapost -> png metapost/svg -> svg :param content: The text the user entered for the macro to process. """ # check and load the configuration errmsg = self._load_config() if errmsg: return self._error_div(errmsg) out_format = self.out_format # first try with the RegExp engine try: m = re.match('metapost\/?([a-z]*)', name) (out_format) = m.group(1, 2) # or use the string.split method except: (s_sp) = (name.split('/')) if len(s_sp) > 1: out_format = s_sp[1] # assign default values, if instance ones are empty if not out_format: out_format = self.out_format if out_format not in Metapost.Formats: self.log.error('render_macro: requested format (%s) not found.' % out_format) return self._error_div( tag.p( _("Metapost macro processor error: requested format (%(fmt)s) not valid.", fmt=out_format))) encoded_content = content.encode(self.encoding) sha_key = sha.new(encoded_content).hexdigest() mpost_name = '%s.%s' % (sha_key, 'mp') mpost_path = os.path.join(self.cache_dir, mpost_name) img_name = '%s.%s' % (sha_key, out_format) img_path = os.path.join(self.cache_dir, img_name) # Create image if not in cache if not os.path.exists(img_path): self._clean_cache() f = open(mpost_path, 'w+') f.write(encoded_content) f.close() os.system('cd %s ; mpost %s' % (self.cache_dir, mpost_name)) os.system('cd %s ; mptopdf %s.%s' % (self.cache_dir, sha_key, '1')) if errmsg: # there was a warning. Ideally we should be able to use # `add_warning` here, but that's not possible as the warnings # are already emitted at this point in the template processing return self._error_div(errmsg) # Generate HTML output img_url = formatter_or_context.href.metapost(img_name) # for SVG(z) if out_format in Metapost.Vector_Formats: os.system('cd %s ; pdf2svg %s-1.%s %s' % (self.cache_dir, sha_key, 'pdf', img_path)) try: # try to get SVG dimensions f = open(img_path, 'r') svg = f.readlines(1024) # don't read all f.close() svg = "".join(svg).replace('\n', '') w = re.search('width="([0-9]+)(.*?)" ', svg) h = re.search('height="([0-9]+)(.*?)"', svg) (w_val, w_unit) = w.group(1, 2) (h_val, h_unit) = h.group(1, 2) # Graphviz seems to underestimate height/width for SVG images, # so we have to adjust them. # The correction factor seems to be constant. w_val, h_val = [1.35 * float(x) for x in (w_val, h_val)] width = unicode(w_val) + w_unit height = unicode(h_val) + h_unit except ValueError: width = height = '100%' # insert SVG, IE compatibility return tag.object(tag.embed(src=img_url, type="image/svg+xml", width=width, height=height), data=img_url, type="image/svg+xml", width=width, height=height) else: os.system('cd %s ; pdftoppm %s-1.%s %s' % (self.cache_dir, sha_key, 'pdf', sha_key)) os.system('cd %s ; convert %s-1.%s %s' % (self.cache_dir, sha_key, 'ppm', img_name)) return tag.img(src=img_url, alt=_("MetaPost image"))
def get_timeline_markup(self, req, call, maxrows=10): """ Generates the markup needed when this component is called both explicitly inside wiki pages and implicitly by the ISideBarBoxProvider. Note this code uses methods from the trac TimelineModule module. """ chrome = Chrome(self.env) # last 14 days should be enough stop = datetime.now(req.tz) start = stop - timedelta(days=50) # use code from trac/timeline to generate event data timeline = TimelineModule(self.env) available_filters, filters = timeline.get_filters(req) include_authors, exclude_authors = timeline.authors() events = timeline.get_events(req, start, stop, filters, available_filters, include_authors, exclude_authors, maxrows) show_gravatar = self.config.get('avatar','mode').lower() != 'off' # create the mark up context = Context.from_request(req) event_list = tag.ul(class_="timeline-list no-style") for event in events: event_title = event['render']('title', context) event_url = event['render']('url', context) event_list.append(tag.li( show_gravatar and tag.img( src=req.href.avatar(event['author'] if event['author'] else 'anonymous'), class_="avatar", ) or "", tag.span( chrome.authorinfo(req, event['author']), class_="author" ), tag.span( pretty_age(event['date']), class_="date", ), tag.div( tag.i(class_="event-type fa fa-" + event['kind']), tag.a( event_title, href=event_url, ), class_="event-summary" ), class_="cf" )) # if the markup is being generated via ISideBarBoxProvider we don't # need to add a span3 class div_classes = "box-sidebar" if call == "macro": div_classes += " span3 right" return tag.div( tag.h3( tag.i( class_="fa fa-calendar" ), " Recent Project Activity" ), event_list, class_=div_classes, )
def _generate_avatar(self, req, author, class_, size): href = self.pictures_provider.get_src(req, author, size) return tag.img(src=href, class_='userpictures_avatar %s' % class_, width=size, height=size).generate()
def _render_needslock(self, context): return tag.img(src=context.href.chrome('common/lock-locked.png'), alt="needs lock", title="needs lock")
def _render_needslock(self, context): url = chrome_resource_path(context.req, 'common/lock-locked.png') return tag.img(src=url, alt=_("needs lock"), title=_("needs lock"))
def render(self, context, mimetype, content, filename=None, url=None): if url: return tag.div(tag.img(src=url, alt=filename), class_='image-file')
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
def expand_macro(self, formatter, name, content): args, kwargs = parse_args(content, strict=False) if len(args) == 1: hat = args[0].lower() title = TITLES.get(hat, '') elif len(args) == 2: hat = args[0].lower() title = args[1] # An simple Exception would probabl;y be better, see http://../ for examples. if len(args) == 0 or hat not in ('black', 'blue', 'green', 'red', 'white', 'yellow', 'intro', 'cite'): raise TracError( 'Invalid parameters, see http://trac-hacks.org/wiki/SixhatsMacro#Examples for example uses.' ) #tags = [tag.strong()('Error: Invalid parameters, see the following examples:')] #tags.extend([tag.pre()(i) for i in HELP.splitlines()]) #return tag.div(class_='system-message')(*tags) if hat == 'cite': if not title: title = "The best way to learn the Six Hats method is to read Edward de Bono's " url = get_absolute_url( formatter.href.base, 'htdocs://sixhats/pdf/six_thinking_hats.pdf') return tag.p()(title, tag.a(href=url)('Six Thinking Hats'), '.') # Not too sure if a plugin should be self-documenting. if hat == 'intro': hide = kwargs.get('hide') tags = [] tags.append( tag.h1(id='SixHatsIntroduction')('Six Hats Introduction')) tags.append( tag.blockquote( tag. p("There is nothing more sad and wasteful than a roomful of intelligent and highly paid people waiting for a chance to attack something the speaker has said. With the Six Hats method the fullest use is made of everyone's intelligence, experience and information. The Six Hats also removes all 'ego' from the discussion process." ))) tags.append( tag.p( 'The Six Thinking Hats represent directions of thought. They are used to request thinking in a paticular direction, ', tag.strong('not'), ' as a description or label to classify your thinking afterwards. They are ', tag.strong('not'), ' used to characterize people. A person is not a black hat, but he or she might prefer to think with the black hat on. It is desirable for everyone to become skilled in the use of all the hats.' )) tags.append(self.expand_macro(formatter, name, 'cite')) tags.append(tag.h1(id='Summary')('Summary')) tags.append(self.expand_macro(formatter, name, 'white,size=m')) li = [ tag.li('The white hat is neutral and objective.'), tag.li('It focusses on facts and figures.'), ] sub_li = [ tag.li('What information do we have?'), tag.li('What information do we need?'), tag.li('What information is missing?'), tag.li('What questions do we need to ask?'), tag.li('How are we going to get the information we need?') ] li.append( tag.li('Questions to ask with the white hat on:', tag.ul(*sub_li))) li.extend([ tag. li('The information can range from hard verifiable facts and figures to soft information such as 3rd party opinions and feelings. Your own opinions and feelings are placed under the red hat.' ), tag.li('Whose fact is it?'), tag.li('Is the information a fact, a likelyhood or a believe?') ]) sub_li = [ tag.li('Always true'), tag.li('Usually true'), tag.li('Generally true'), tag.li('By and large'), tag.li('More often than not'), tag.li('About half the time'), tag.li('Often'), tag.li('Sometimes true'), tag.li('Occastionally true'), tag.li('Been known to happen'), tag.li('Never true'), tag.li('Cannot be true (contradictory)') ] li.append( tag. li('How true is the fact? Frame the information appropriatly:', tag.ul(*sub_li))) li.append( tag. li('Split the facts into two groups: checked facts and believed facts.' )) tags.append(tag.ul(*li)) tags.append(self.expand_macro(formatter, name, 'red,size=m')) li = [ tag.li( 'The red hat is subjective and generally non-rational.'), tag.li('It exposes and legitimizes emotions and feelings.'), tag. li('It allows people to express their opinions, hunches, intuitions and impressions. (a function of their experience)' ), tag. li("Resist the temptation to justify your emotions. You don't need to give a reason or a logical basis." ), tag. li('If emotions and feelings are not permitted as inputs in the thinking process, they will lurk in the background and affect all the thinking in a hidden way.' ), tag. li('The red hat makes feelings visible so that they can become part of the thinking map and also part of the value system that chooses the route on the map.' ) ] sub_li = [ tag. li('Ordinary emotions such as fear and dislike to more subtle ones such as suspicion.' ), tag. li('Complex judgements that go into such type of feelings as a hunch, intuition, sense, taste, aesthetic feeling and other not visibly justified types of feeling.' ) ] li.append( tag.li('The red hat covers two broad types of feelings:', tag.ol(*sub_li))) tags.append(tag.ul(*li)) tags.append(self.expand_macro(formatter, name, 'black,size=m')) li = [ tag. li('The black hat is critical and logical (negative judgements).' ), tag. li("It's perhaps the most important hat, the hat of survival, of caution and of being careful." ), tag. li('It points out how something does not fit our experience, our resources, our policy, our stragegy, our ethics, our values, etc.' ), tag. li('It protects us from wasting energy and money, it seeks to avoid dangers, problems, obstacles and difficulties.' ), tag. li('There must be a logical basis for the criticism and reasons must be capable of standing on their own.' ), tag. li('It focuses on why something may not work or may not be the right thing to do.' ), ] sub_li = [ tag.li('Be as causious and as fiercely critical as possible.'), tag.li( 'Point out errors or deficiencies in the thinking process.' ), tag.li('Question the strength of the evidence.'), tag.li('What are the risks?'), ] li.append( tag.li( 'In order to get the full value from any suggestion or idea, it is important that the black hat be done thoroughly:', tag.ul(*sub_li))) li.extend([ tag. li('Black hat thinking is not argument and must not be allowed to degenerate into argument.' ), tag.li( tag.strong('Caution:'), ' There are people who overuse the black hat and who spend all their time trying to find fault. The fault is not in the black hat but in the abuse, overuse or misuse of the black hat.' ) ]) tags.append(tag.ul(*li)) tags.append(self.expand_macro(formatter, name, 'yellow,size=m')) li = [ tag. li('The yellow hat is optimistic and logical (positive judgements).' ) ] sub_li = [ tag.li('The generation of proposals.'), tag.li('The positive assessment of proposals.'), tag.li("Developing or 'building up' of proposals.") ] li.append( tag.li('The yellow hat is concerned with:', tag.ol(*sub_li))) li.extend([ tag. li('Under the yellow hat a thinker deliberatly sets out to find whatever benefit there may be in a suggestion.' ), tag. li('It is a waste of time setting out to be creative if you are not going to recognize a good idea.' ), tag.li('Value and benefit are by no means always obvious.'), tag. li('Since the yellow hat is logical you should give a reason for the value you put forward.' ), tag. li('The emphasis of yellow hat thinking is on exploration and positive speculation, oppertunity seeking.' ), tag. li("Yellow hat thinking is concerned with the positive attitude of getting the job done, let's make it happen." ) ]) tags.append(tag.ul(*li)) tags.append(self.expand_macro(formatter, name, 'green,size=m')) li = [ tag.li('The green hat is creative, sometimes illogical.'), tag. li('The green hat is concerned with new ideas and new ways of looking at things, new perceptions.' ), tag. li("Under the green hat we lay out options, alternatives and 'possibilities'." ), tag. li('It corrects the faults found under the black hat and find noval ways the exploit the opportunities identified under the yellow hat.' ), tag. li('You use the green hat to deliberately go after new ideas instead of waiting for them to come to you.' ), tag. li('Sometimes you may be required to put forward provocations, illogical ideas, in order to provoke new concepts.' ), tag. li('Under the green hat we use ideas as stepping stones, for their movement value, moving us to new ideas.' ), tag.li('Use random words and ', tag.em('Po'), '.') ] tags.append(tag.ul(*li)) tags.append(self.expand_macro(formatter, name, 'blue,size=m')) li = [ tag. li('The blue hat is for meta-thinking, thinking about thinking.' ), tag. li('Wearing the blue hat we are no longer thinking about the subject; instead, we are thinking about the thinking needed to explore the subject.' ), tag. li('The blue hat thinker is like the conductor of an orchestra.' ), tag. li("Generally the blue hat is worn by the facilitator, chairperson or leader of the session, it's a permanent role." ), tag. li('The blue hat is for the organization and management of thinking, it also controls the process of thinking.' ), tag. li('The initial blue hat defines the problem, list constraints and sets the agenda, the sequence of the other hats to be used.' ), tag. li('Blue hat thinking stops arguments, enforces the discipline and keep people focussed on map making.' ), tag. li('The final blue hat is responsible for summaries, overviews and conclusions.' ) ] tags.append(tag.ul(*li)) fedoras = tag.a('fedoras', href=get_absolute_url( formatter.href.base, 'htdocs://sixhats/img/source/fedoras.svg')) hardhats = tag.a('hardhats', href=get_absolute_url( formatter.href.base, 'htdocs://sixhats/img/source/hardhats.svg')) tophats = tag.a('tophats', href=get_absolute_url( formatter.href.base, 'htdocs://sixhats/img/source/tophats.svg')) tags.append( tag.p( 'PS. If you wish to use any of these images in your own documents rather use the high quality vectors: ', fedoras, ', ', hardhats, ' and ', tophats, '.')) if hide: add_script(formatter.req, 'sixhats/js/hide.js') if hide.lower() == 'hide': return ''.join([ str(i) for i in ('- ', tag.a(id='hide', href='#', style='font-size: 8pt;')( 'show six hats introduction'), ' -', tag.div( id='introduction', style='display: none;', *tags)) ]) else: return ''.join([ str(i) for i in ( '- ', tag.a(id='hide', href='#', style='font-size: 8pt;') ('hide six hats introduction'), ' -', tag.div(id='introduction', *tags)) ]) else: return tag.div(id='introduction', *tags) id = kwargs.get('id', squish_string(title)) size = kwargs.get('size', 'large') type = kwargs.get('type', 'hardhat').lower() h = kwargs.get('h') if type in ('fedora', 'hardhat', 'tophat'): if size.endswith('%'): percentage = float(size.strip('%')) / 100.0 width, height = SIZES[type]['l'] else: percentage = 1 width, height = SIZES[type][size[0]] width = int(width * percentage) height = int(height * percentage) if h: if h == '1': root = tag.h1 elif h == '2': root = tag.h2 elif h == '3': root = tag.h3 elif h == '4': root = tag.h4 else: root = tag.h5 else: s0 = size[0] if s0 == 'l': root = tag.h1 elif s0 == 'm': root = tag.h2 elif s0 == 's': root = tag.h3 else: root = tag.h1 url = get_absolute_url( formatter.href.base, 'htdocs://sixhats/img/%(type)s/%(hat)s.jpg' % { 'type': type, 'hat': hat }) if id: return root(id=id)(tag.img(src=url, width=width, height=height), title) else: return root()(tag.img(src=url, width=width, height=height), title)
def _format_smiley(self, formatter, match, fullmatch=None): #noinspection PyArgumentList loc = Icons(self.env).icon_location() return tag.img(src=formatter.href.chrome(loc[0], self.smileys[match]), alt=match, style="vertical-align: text-bottom")
def expand_macro(self, formatter, name, content): """Return the HTML output of the macro.""" req = formatter.req # check and load the configuration errmsg = self._load_config() if errmsg: return self._error_div(errmsg) ## Extract processor and format from name processor = out_format = None # first try with the RegExp engine try: m = re.match('graphviz\.?([a-z]*)\/?([a-z]*)', name) (processor, out_format) = m.group(1, 2) # or use the string.split method except: (d_sp, s_sp) = (name.split('.'), name.split('/')) if len(d_sp) > 1: s_sp = d_sp[1].split('/') if len(s_sp) > 1: out_format = s_sp[1] processor = s_sp[0] elif len(s_sp) > 1: out_format = s_sp[1] # assign default values, if instance ones are empty if not out_format: out_format = self.out_format if not processor: processor = self.processor if processor in Graphviz.Processors: proc_cmd = self.cmds[processor] else: self.log.error('render_macro: requested processor (%s) not found.' % processor) return self._error_div('requested processor (%s) not found.' % processor) if out_format not in Graphviz.Formats: self.log.error('render_macro: requested format (%s) not found.' % out_format) return self._error_div( tag.p(_("Graphviz macro processor error: " "requested format (%(fmt)s) not valid.", fmt=out_format))) encoded_cmd = (processor + unicode(self.processor_options)) \ .encode(self.encoding) encoded_content = content.encode(self.encoding) sha_key = sha.new(encoded_cmd + encoded_content).hexdigest() img_name = '%s.%s.%s' % (sha_key, processor, out_format) # cache: hash.<dot>.<png> img_path = os.path.join(self.cache_dir, img_name) map_name = '%s.%s.map' % (sha_key, processor) # cache: hash.<dot>.map map_path = os.path.join(self.cache_dir, map_name) # Check for URL="" presence in graph code URL_in_graph = 'URL=' in content # Create image if not in cache if not os.path.exists(img_path): self._clean_cache() if URL_in_graph: # translate wiki TracLinks in URL content = self._expand_wiki_links(formatter, out_format, content) encoded_content = content.encode(self.encoding) # Antialias PNGs with rsvg, if requested if out_format == 'png' and self.png_anti_alias == True: # 1. SVG output errmsg = self._launch(encoded_content, proc_cmd, '-Tsvg', '-o%s.svg' % img_path, *self.processor_options) if errmsg: return self._error_div(errmsg) # 2. SVG to PNG rasterization errmsg = self._launch(None, self.rsvg_path, '--dpi-x=%d' % self.dpi, '--dpi-y=%d' % self.dpi, '%s.svg' % img_path, img_path) if errmsg: return self._error_div(errmsg) else: # Render other image formats errmsg = self._launch(encoded_content, proc_cmd, '-T%s' % out_format, '-o%s' % img_path, *self.processor_options) if errmsg: return self._error_div(errmsg) # Generate a map file for binary formats if URL_in_graph and out_format in Graphviz.Bitmap_Formats: # Create the map if not in cache if not os.path.exists(map_path): errmsg = self._launch(encoded_content, proc_cmd, '-Tcmap', '-o%s' % map_path, *self.processor_options) if errmsg: return self._error_div(errmsg) # Generate HTML output img_url = formatter.href.graphviz(img_name) # for SVG(z) if out_format in Graphviz.Vector_Formats: try: # try to get SVG dimensions f = open(img_path, 'r') svg = f.readlines(1024) # don't read all f.close() svg = "".join(svg).replace('\n', '') w = re.search('width="([0-9]+)(.*?)" ', svg) h = re.search('height="([0-9]+)(.*?)"', svg) (w_val, w_unit) = w.group(1,2) (h_val, h_unit) = h.group(1,2) # Graphviz seems to underestimate height/width for SVG images, # so we have to adjust them. # The correction factor seems to be constant. w_val, h_val = [1.35 * float(x) for x in (w_val, h_val)] width = unicode(w_val) + w_unit height = unicode(h_val) + h_unit except ValueError: width = height = '100%' # insert SVG, IE compatibility return tag.object( tag.embed(src=img_url, type="image/svg+xml", width=width, height=height), data=img_url, type="image/svg+xml", width=width, height=height) # for binary formats, add map elif URL_in_graph and os.path.exists(map_path): f = open(map_path, 'r') map = f.readlines() f.close() map = "".join(map).replace('\n', '') return tag(tag.map(Markup(map), id='G'+sha_key, name='G'+sha_key), tag.img(src=img_url, usemap="#G"+sha_key, alt=_("GraphViz image"))) else: return tag.img(src=img_url, alt=_("GraphViz image"))
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
def expand_macro(self, formatter_or_context, name, content): """Return the HTML output of the macro. :param formatter_or_context: a Formatter when called as a macro, a Context when called by `GraphvizPlugin.render` :param name: Wiki macro command that resulted in this method being called. In this case, it should be 'graphviz', followed (or not) by the processor name, then by an output format, as following: graphviz.<processor>/<format> Valid processor names are: dot, neato, twopi, circo, and fdp. The default is dot. Valid output formats are: jpg, png, gif, svg and svgz. The default is the value specified in the out_format configuration parameter. If out_format is not specified in the configuration, then the default is png. examples: graphviz.dot/png -> dot png graphviz.neato/jpg -> neato jpg graphviz.circo -> circo png graphviz/svg -> dot svg :param content: The text the user entered for the macro to process. """ # check and load the configuration errmsg = self._load_config() if errmsg: return self._error_div(errmsg) ## Extract processor and format from name processor = out_format = None # first try with the RegExp engine try: m = re.match('graphviz\.?([a-z]*)\/?([a-z]*)', name) (processor, out_format) = m.group(1, 2) # or use the string.split method except: (d_sp, s_sp) = (name.split('.'), name.split('/')) if len(d_sp) > 1: s_sp = d_sp[1].split('/') if len(s_sp) > 1: out_format = s_sp[1] processor = s_sp[0] elif len(s_sp) > 1: out_format = s_sp[1] # assign default values, if instance ones are empty if not out_format: out_format = self.out_format if not processor: processor = self.processor if processor in Graphviz.Processors: proc_cmd = self.cmds[processor] else: self.log.error('render_macro: requested processor (%s) not found.' % processor) return self._error_div('requested processor (%s) not found.' % processor) if out_format not in Graphviz.Formats: self.log.error('render_macro: requested format (%s) not found.' % out_format) return self._error_div( tag.p(_("Graphviz macro processor error: " "requested format (%(fmt)s) not valid.", fmt=out_format))) encoded_cmd = (processor + unicode(self.processor_options)) \ .encode(self.encoding) encoded_content = content.encode(self.encoding) sha_key = sha1(encoded_cmd + encoded_content).hexdigest() img_name = '%s.%s.%s' % (sha_key, processor, out_format) # cache: hash.<dot>.<png> img_path = os.path.join(self.cache_dir, img_name) map_name = '%s.%s.map' % (sha_key, processor) # cache: hash.<dot>.map map_path = os.path.join(self.cache_dir, map_name) # Check for URL="" presence in graph code URL_in_graph = 'URL=' in content # Create image if not in cache if not os.path.exists(img_path): self._clean_cache() if URL_in_graph: # translate wiki TracLinks in URL if isinstance(formatter_or_context, Context): context = formatter_or_context else: context = formatter_or_context.context content = self._expand_wiki_links(context, out_format, content) encoded_content = content.encode(self.encoding) # Antialias PNGs with rsvg, if requested if out_format == 'png' and self.png_anti_alias == True: # 1. SVG output failure, errmsg = self._launch( encoded_content, proc_cmd, '-Tsvg', '-o%s.svg' % img_path, *self.processor_options) if failure: return self._error_div(errmsg) # 2. SVG to PNG rasterization failure, errmsg = self._launch( None, self.rsvg_path, '--dpi-x=%d' % self.dpi, '--dpi-y=%d' % self.dpi, '%s.svg' % img_path, img_path) if failure: return self._error_div(errmsg) else: # Render other image formats failure, errmsg = self._launch( encoded_content, proc_cmd, '-T%s' % out_format, '-o%s' % img_path, *self.processor_options) if failure: return self._error_div(errmsg) # Generate a map file for binary formats if URL_in_graph and out_format in Graphviz.Bitmap_Formats: # Create the map if not in cache if not os.path.exists(map_path): failure, errmsg = self._launch( encoded_content, proc_cmd, '-Tcmap', '-o%s' % map_path, *self.processor_options) if failure: return self._error_div(errmsg) if errmsg: # there was a warning. Ideally we should be able to use # `add_warning` here, but that's not possible as the warnings # are already emitted at this point in the template processing return self._error_div(errmsg) # Generate HTML output img_url = formatter_or_context.href.graphviz(img_name) # for SVG(z) if out_format in Graphviz.Vector_Formats: try: # try to get SVG dimensions f = open(img_path, 'r') svg = f.readlines(1024) # don't read all f.close() svg = "".join(svg).replace('\n', '') w = re.search('width="([0-9]+)(.*?)" ', svg) h = re.search('height="([0-9]+)(.*?)"', svg) (w_val, w_unit) = w.group(1,2) (h_val, h_unit) = h.group(1,2) # Graphviz seems to underestimate height/width for SVG images, # so we have to adjust them. # The correction factor seems to be constant. w_val, h_val = [1.35 * float(x) for x in (w_val, h_val)] width = unicode(w_val) + w_unit height = unicode(h_val) + h_unit except ValueError: width = height = '100%' # insert SVG, IE compatibility return tag.object( tag.embed(src=img_url, type="image/svg+xml", width=width, height=height), data=img_url, type="image/svg+xml", width=width, height=height) # for binary formats, add map elif URL_in_graph and os.path.exists(map_path): f = open(map_path, 'r') map = f.readlines() f.close() map = "".join(map).replace('\n', '') return tag(tag.map(Markup(map), id='G'+sha_key, name='G'+sha_key), tag.img(src=img_url, usemap="#G"+sha_key, alt=_("GraphViz image"))) else: return tag.img(src=img_url, alt=_("GraphViz image"))
def expand_macro(self, formatter, name, content): args = None if content: content = stripws(content) # parse arguments # we expect the 1st argument to be a filename (filespec) args = [stripws(arg) for arg in self._split_args_re.split(content)[1::2]] if not args: return '' # strip unicode white-spaces and ZWSPs are copied from attachments # section (#10668) filespec = args.pop(0) # style information attr = {} style = {} link = '' # helper for the special case `source:` # from trac.versioncontrol.web_ui import BrowserModule # FIXME: somehow use ResourceSystem.get_known_realms() # ... or directly trac.wiki.extract_link try: browser_links = [res[0] for res in BrowserModule(self.env).get_link_resolvers()] except Exception: browser_links = [] while args: arg = args.pop(0) if self._size_re.match(arg): # 'width' keyword attr['width'] = arg elif arg == 'nolink': link = None elif arg.startswith('link='): val = arg.split('=', 1)[1] elt = extract_link(self.env, formatter.context, val.strip()) elt = find_element(elt, 'href') link = None if elt is not None: link = elt.attrib.get('href') elif arg in ('left', 'right'): style['float'] = arg elif arg == 'center': style['margin-left'] = style['margin-right'] = 'auto' style['display'] = 'block' style.pop('margin', '') elif arg in ('top', 'bottom', 'middle'): style['vertical-align'] = arg else: match = self._attr_re.match(arg) if match: key, val = match.groups() if (key == 'align' and val in ('left', 'right', 'center')) or \ (key == 'valign' and val in ('top', 'middle', 'bottom')): args.append(val) elif key in ('margin-top', 'margin-bottom'): style[key] = ' %dpx' % _arg_as_int(val, key, min=1) elif key in ('margin', 'margin-left', 'margin-right') \ and 'display' not in style: style[key] = ' %dpx' % _arg_as_int(val, key, min=1) elif key == 'border': style['border'] = ' %dpx solid' % _arg_as_int(val, key) else: m = self._quoted_re.search(val) # unquote "..." and '...' if m: val = m.group(1) attr[str(key)] = val # will be used as a __call__ kwd if self._quoted_re.match(filespec): filespec = filespec.strip('\'"') # parse filespec argument to get realm and id if contained. parts = [i.strip('\'"') for i in self._split_filespec_re.split(filespec)[1::2]] realm = parts[0] if parts else None url = raw_url = desc = None attachment = None interwikimap = InterWikiMap(self.env) if realm in ('http', 'https', 'ftp', 'data'): # absolute raw_url = url = filespec desc = url.rsplit('?')[0] elif realm in interwikimap: url, desc = interwikimap.url(realm, ':'.join(parts[1:])) raw_url = url elif filespec.startswith('//'): # server-relative raw_url = url = filespec[1:] desc = url.rsplit('?')[0] elif filespec.startswith('/'): # project-relative params = '' if '?' in filespec: filespec, params = filespec.rsplit('?', 1) url = formatter.href(filespec) if params: url += '?' + params raw_url, desc = url, filespec elif len(parts) == 3: # realm:id:attachment-filename # # or intertrac:realm:id realm, id, filename = parts intertrac_target = "%s:%s" % (id, filename) it = formatter.get_intertrac_url(realm, intertrac_target) if it: url, desc = it raw_url = url + unicode_quote('?format=raw') else: attachment = Resource(realm, id).child('attachment', filename) elif len(parts) == 2: realm, filename = parts if realm in browser_links: # source:path # TODO: use context here as well rev = None if '@' in filename: filename, rev = filename.rsplit('@', 1) url = formatter.href.browser(filename, rev=rev) raw_url = formatter.href.browser(filename, rev=rev, format='raw') desc = filespec else: # #ticket:attachment or WikiPage:attachment # FIXME: do something generic about shorthand forms... realm = None id, filename = parts if id and id[0] == '#': realm = 'ticket' id = id[1:] elif id == 'htdocs': raw_url = url = formatter.href.chrome('site', filename) desc = os.path.basename(filename) elif id == 'shared': raw_url = url = formatter.href.chrome('shared', filename) desc = os.path.basename(filename) else: realm = 'wiki' if realm: attachment = Resource(realm, id).child('attachment', filename) elif len(parts) == 1: # it's an attachment of the current resource attachment = formatter.resource.child('attachment', filespec) else: return system_message(_("No filespec given")) if attachment: try: desc = get_resource_summary(self.env, attachment) except ResourceNotFound: link = None raw_url = chrome_resource_path(formatter.context.req, 'common/attachment.png') desc = _('No image "%(id)s" attached to %(parent)s', id=attachment.id, parent=get_resource_name(self.env, attachment.parent)) else: if 'ATTACHMENT_VIEW' in formatter.perm(attachment): url = get_resource_url(self.env, attachment, formatter.href) raw_url = get_resource_url(self.env, attachment, formatter.href, format='raw') for key in ('title', 'alt'): if desc and key not in attr: attr[key] = desc if style: attr['style'] = '; '.join('%s:%s' % (k, escape(v)) for k, v in style.iteritems()) if not WikiSystem(self.env).is_safe_origin(raw_url, formatter.context.req): attr['crossorigin'] = 'anonymous' # avoid password prompt result = tag.img(src=raw_url, **attr) if link is not None: result = tag.a(result, href=link or url, style='padding:0; border:none') return result
if ticket.getfield( 'status') in countStatus.keys(): # count values countStatus[ticket.getfield('status')] += 1 else: countStatus[ticket.getfield('status')] = 1 #tr(tag.td( tag.div( td_div, style = 'border-left:3px solid %s;' % (color) ) ) ) tr( tag.td(tag.div(td_div), self.render_statistics(orderedtickets[segment][o]), class_='%s %s %s' % (color_class, class_, self.statistics_class))) if self.showsummarypiechart: tr( tag.td( tag.img(src=self.createGoogleChartFromDict( 'ColorForStatus', countStatus)))) # Summary tbody(tr) table(tbody) countTickets = 0 tfoot = tag.tfoot() tr = tag.tr() tr(tag.td(tag.h5(self.rowtype + ': ' + str(len(self.rows))))) for segment in self.segments: tr(tag.td(tag.h5(str(counttickets[segment]) + ' tickets'))) countTickets += counttickets[segment] if self.showsummarypiechart: tr(tag.td(tag.h5(str(str(countTickets)) + ' tickets'))) # Summary tfoot(tr) table(tfoot)
def expand_macro(self, formatter_or_context, name, content): """Return the HTML output of the macro. :param formatter_or_context: a Formatter when called as a macro, a Context when called by `GraphvizPlugin.render` :param name: Wiki macro command that resulted in this method being called. In this case, it should be 'graphviz', followed (or not) by the processor name, then by an output format, as following: graphviz.<processor>/<format> Valid processor names are: dot, neato, twopi, circo, and fdp. The default is dot. Valid output formats are: jpg, png, gif, svg and svgz. The default is the value specified in the out_format configuration parameter. If out_format is not specified in the configuration, then the default is png. examples: graphviz.dot/png -> dot png graphviz.neato/jpg -> neato jpg graphviz.circo -> circo png graphviz/svg -> dot svg :param content: The text the user entered for the macro to process. """ # check and load the configuration errmsg = self._load_config() if errmsg: return self._error_div(errmsg) ## Extract processor and format from name processor = out_format = None # first try with the RegExp engine try: m = re.match('graphviz\.?([a-z]*)\/?([a-z]*)', name) (processor, out_format) = m.group(1, 2) # or use the string.split method except: (d_sp, s_sp) = (name.split('.'), name.split('/')) if len(d_sp) > 1: s_sp = d_sp[1].split('/') if len(s_sp) > 1: out_format = s_sp[1] processor = s_sp[0] elif len(s_sp) > 1: out_format = s_sp[1] # assign default values, if instance ones are empty if not out_format: out_format = self.out_format if not processor: processor = self.processor if processor in Graphviz.Processors: proc_cmd = self.cmds[processor] else: self.log.error( 'render_macro: requested processor (%s) not found.' % processor) return self._error_div('requested processor (%s) not found.' % processor) if out_format not in Graphviz.Formats: self.log.error('render_macro: requested format (%s) not found.' % out_format) return self._error_div( tag.p( _( "Graphviz macro processor error: " "requested format (%(fmt)s) not valid.", fmt=out_format))) encoded_cmd = (processor + unicode(self.processor_options)) \ .encode(self.encoding) encoded_content = content.encode(self.encoding) sha_key = sha1(encoded_cmd + encoded_content).hexdigest() img_name = '%s.%s.%s' % (sha_key, processor, out_format) # cache: hash.<dot>.<png> img_path = os.path.join(self.cache_dir, img_name) map_name = '%s.%s.map' % (sha_key, processor) # cache: hash.<dot>.map map_path = os.path.join(self.cache_dir, map_name) # Check for URL="" presence in graph code URL_in_graph = 'URL=' in content # Create image if not in cache if not os.path.exists(img_path): self._clean_cache() if URL_in_graph: # translate wiki TracLinks in URL if isinstance(formatter_or_context, Context): context = formatter_or_context else: context = formatter_or_context.context content = self._expand_wiki_links(context, out_format, content) encoded_content = content.encode(self.encoding) # Antialias PNGs with rsvg, if requested if out_format == 'png' and self.png_anti_alias == True: # 1. SVG output failure, errmsg = self._launch(encoded_content, proc_cmd, '-Tsvg', '-o%s.svg' % img_path, *self.processor_options) if failure: return self._error_div(errmsg) # 2. SVG to PNG rasterization failure, errmsg = self._launch(None, self.rsvg_path, '--dpi-x=%d' % self.dpi, '--dpi-y=%d' % self.dpi, '%s.svg' % img_path, img_path) if failure: return self._error_div(errmsg) else: # Render other image formats failure, errmsg = self._launch(encoded_content, proc_cmd, '-T%s' % out_format, '-o%s' % img_path, *self.processor_options) if failure: return self._error_div(errmsg) # Generate a map file for binary formats if URL_in_graph and out_format in Graphviz.Bitmap_Formats: # Create the map if not in cache if not os.path.exists(map_path): failure, errmsg = self._launch(encoded_content, proc_cmd, '-Tcmap', '-o%s' % map_path, *self.processor_options) if failure: return self._error_div(errmsg) if errmsg: # there was a warning. Ideally we should be able to use # `add_warning` here, but that's not possible as the warnings # are already emitted at this point in the template processing return self._error_div(errmsg) # Generate HTML output img_url = formatter_or_context.href.graphviz(img_name) # for SVG(z) if out_format in Graphviz.Vector_Formats: try: # try to get SVG dimensions f = open(img_path, 'r') svg = f.readlines(1024) # don't read all f.close() svg = "".join(svg).replace('\n', '') w = re.search('width="([0-9]+)(.*?)" ', svg) h = re.search('height="([0-9]+)(.*?)"', svg) (w_val, w_unit) = w.group(1, 2) (h_val, h_unit) = h.group(1, 2) # Graphviz seems to underestimate height/width for SVG images, # so we have to adjust them. # The correction factor seems to be constant. w_val, h_val = [1.35 * float(x) for x in (w_val, h_val)] width = unicode(w_val) + w_unit height = unicode(h_val) + h_unit except ValueError: width = height = '100%' # insert SVG, IE compatibility return tag.object(tag.embed(src=img_url, type="image/svg+xml", width=width, height=height), data=img_url, type="image/svg+xml", width=width, height=height) # for binary formats, add map elif URL_in_graph and os.path.exists(map_path): f = open(map_path, 'r') map = f.readlines() f.close() map = "".join(map).replace('\n', '') return tag( tag.map(Markup(map), id='G' + sha_key, name='G' + sha_key), tag.img(src=img_url, usemap="#G" + sha_key, alt=_("GraphViz image"))) else: return tag.img(src=img_url, alt=_("GraphViz image"))
def expand_macro(self, formatter, name, content, args=None): if args is None: args = {} if name[-4:] in ('_svg', '_png'): name, type = name.split('_') else: type = (args.get('type') or self._default_type).lower() if type not in ('svg', 'png'): return system_message( "Invalid type(%s). Type must be 'svg' or 'png'" % type) font = self._font # nonascii unicode can't be passed to hashlib. id = make_hash('%s,%s,%s,%r' % (name, type, font, content)).hexdigest() ## Create img tag. params = {"src": formatter.req.href("%s/%s.%s" % (name, id, type))} for key, value in args.iteritems(): if key != "type": params[key] = value output = tag.img(**params) ## Generate image and cache it. def generate_image(): infile = mktemp(prefix='%s-' % name) outfile = mktemp(prefix='%s-' % name) try: try: f = codecs.open(infile, 'w', 'utf8') try: f.write(content) finally: f.close() cmd = [name, '-a', '-T', type, '-o', outfile, infile] if font: cmd.extend(['-f', font]) self.env.log.debug('(%s) command: %r' % (name, cmd)) try: proc = Popen(cmd, stderr=PIPE) stderr_value = proc.communicate()[1] except Exception, e: self.env.log.error('(%s) %r' % (name, e)) raise ImageGenerationError( "Failed to generate diagram. (%s is not found.)" % name) if proc.returncode != 0 or not os.path.isfile(outfile): self.env.log.error('(%s) %s' % (name, stderr_value)) raise ImageGenerationError( "Failed to generate diagram. (rc=%d)" % proc.returncode) f = open(outfile, 'rb') try: data = f.read() finally: f.close() return data except ImageGenerationError: raise except Exception, e: self.env.log.error('(%s) %r' % (name, e)) raise ImageGenerationError("Failed to generate diagram.")