# # # add_file "fdo/icontheme.py" # content [407d0730a7313c980f87814164bc3fe4229877ca] # # patch "templates/revisionbrowse.html" # from [e2cbeec9a51d57941e238432870701b13f1e5bbc] # to [a4175d3be3ff73d4e8d27667de546355fcece82d] # # patch "viewmtn.py" # from [c729e83bf6d36d4680f6f2d288765e4c75d46ea5] # to [e4a95861e0d7a5a8f58187818aba0a3a6b1956a5] # # set "fdo/icontheme.py" # attr "mtn:execute" # value "true" # ============================================================ --- fdo/icontheme.py 407d0730a7313c980f87814164bc3fe4229877ca +++ fdo/icontheme.py 407d0730a7313c980f87814164bc3fe4229877ca @@ -0,0 +1,124 @@ +#!/usr/bin/env python2.4 + +# an implementation of: +# http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html +# (or at least, enough of it to do mime_type->icon file conversion; more could +# be added later if someone was keen..) + +from ConfigParser import ConfigParser +import xdgbasedir +import os + +class IconTheme: + def __init__(self, icon_theme): + self.icon_theme = icon_theme + # list of directories in order, in which to look for files + self.locs = [] + home = os.getenv('HOME') + if home: + self.locs.append(os.path.join(home, '.icons')) + for path in xdgbasedir.xdg_data_dirs(): + self.locs.append(os.path.join(path, 'icons')) + self.locs.append('/usr/share/pixmaps') + self.locs = filter(lambda x: os.access(x, os.R_OK), self.locs) + + # find our index.theme file + index_theme_file = None + for path in self.locs: + ini = os.path.join(path, icon_theme, 'index.theme') + if os.access(ini, os.R_OK): + index_theme_file = ini + break + + if not index_theme_file: + raise Exception("Unable to load index.theme for theme %s" % icon_theme) + + self.cp = cp = ConfigParser() + cp.read(index_theme_file) + it = "Icon Theme" + if not cp.has_section(it): + raise Exception("Theme does not have an 'Icon Theme' section.") + if not cp.has_option(it, "Directories"): + raise Exception("Theme does not specify its directories.") + else: + self.directories = cp.get(it, "Directories").split(',') + if cp.has_option(it, "Inherits"): + self.inherits = cp.get(it, "Inherits").split(',') + elif icon_theme != 'hicolor': + self.inherits = ['hicolor'] + else: + self.inherits = [] + self.inherits = map(IconTheme, self.inherits) + + # most of the time, we'll care about directories by type and + # then by size + self.dir_by_size = {} + for path in self.directories: + context = cp.get(path, 'Context', None) + if not cp.has_option(path, 'Size'): + raise Exception("Directory '%s' has no size." % (path)) + size = cp.get(path, 'Size') + self.dir_by_size.setdefault(context, {}).setdefault(size, []).append(path) + + def lookup(self, icon_name, contexts=None, size=None, accept_extensions=None): + if accept_extensions == None: + accept_extensions = ["png", "xpm", "svg"] + to_scan = [] + if contexts == None: + contexts = self.dir_by_size.keys() + + for context in contexts: + for dir_size in self.dir_by_size[context]: + if size == None or size == dir_size: + for path in self.dir_by_size[context][dir_size]: + for loc in self.locs: + for ext in accept_extensions: + attempt = os.path.join(loc, self.icon_theme, path, icon_name+'.'+ext) + #print "attempt:", attempt + if os.access(attempt, os.R_OK): + #print "success!" + return attempt + + # if we get here, try our parent themes + for it in self.inherits: + rv = it.lookup(icon_name, contexts, size, accept_extensions) + if rv: return rv + return None + +class MimeIcon: + def __init__(self, icon_theme, size=None): + self.icon_theme = icon_theme + self.size = size + self.cache = {} + + def lookup(self, mime_type): + def __lookup(): + def gnome_mime(mime_type): + return "gnome-mime-" + mime_type.replace('/', '-') + # iff we are a inode/ type, then let's look in 'Places' instead + if mime_type.startswith('inode/'): + gnome_name = 'gnome-fs-' + mime_type.split('/')[-1] + rv = self.icon_theme.lookup(gnome_name, contexts=['Places'], size=self.size) + if rv: return rv + # stolen from gnome-ui; it's rather unfortunate but there is not a standard + # on how to name mime icons! + # http://cvs.gnome.org/viewcvs/libgnomeui/libgnomeui/gnome-icon-lookup.c + gnome_name = gnome_mime(mime_type) + rv = self.icon_theme.lookup(gnome_name, contexts=['MimeTypes'], size=self.size) + if rv: return rv + # try the x-generic stuff + generic_name = mime_type.split('/')[0] + '-x-generic' + rv = self.icon_theme.lookup(generic_name, contexts=['MimeTypes'], size=self.size) + if rv: return rv + # otherwise, this seems to work some of the time + gnome_name = gnome_mime(mime_type.split('/')[0]) + rv = self.icon_theme.lookup(gnome_name, contexts=['MimeTypes'], size=self.size) + return rv + if not self.cache.has_key(mime_type): + self.cache[mime_type] = __lookup() + return self.cache[mime_type] + +if __name__ == '__main__': + it = IconTheme('gnome') + mi = MimeIcon(it, size="16") + print mi.lookup('text/plain') ============================================================ --- templates/revisionbrowse.html e2cbeec9a51d57941e238432870701b13f1e5bbc +++ templates/revisionbrowse.html a4175d3be3ff73d4e8d27667de546355fcece82d @@ -25,10 +25,10 @@ $branch_links
| Name | Age | Author | Last log entry | |
|---|---|---|---|---|
|
-
+ |
#filter Filter ============================================================ --- viewmtn.py c729e83bf6d36d4680f6f2d288765e4c75d46ea5 +++ viewmtn.py e4a95861e0d7a5a8f58187818aba0a3a6b1956a5 @@ -19,7 +19,7 @@ from colorsys import hls_to_rgb import datetime import cStringIO from colorsys import hls_to_rgb -from fdo import sharedmimeinfo +from fdo import sharedmimeinfo, icontheme import release hq = cgi.escape @@ -313,6 +313,7 @@ mimehelp = sharedmimeinfo.LookupHelper() renderer = Renderer() ops = mtn.Operations([config.monotone, config.dbfile]) mimehelp = sharedmimeinfo.LookupHelper() +mimeicon = icontheme.MimeIcon(icontheme.IconTheme(config.icon_theme), config.icon_size) class Index: def GET(self): @@ -734,9 +735,11 @@ class RevisionBrowse(RevisionPage): author, ago, shortlog, content_mark = mtn.Author(""), "", "", None if stanza_type == "file": file_obj = mtn.File(this_path, revision) + mime_type = mimehelp.lookup(this_path, "") else: file_obj = mtn.Dir(this_path, revision) - yield (stanza_type, file_obj, author, ago, content_mark, shortlog) + mime_type = 'inode/directory' + yield (stanza_type, file_obj, author, ago, content_mark, shortlog, mime_type) def path_links(components): # we always want a link to '/' @@ -751,6 +754,9 @@ class RevisionBrowse(RevisionPage): yield "odd" yield "even" + def mime_icon(mime_type): + return dynamic_join('/mimeicon/' + mime_type) + renderer.render('revisionbrowse.html', branches=branches, branch_links=', '.join([link(mtn.Branch(b)).html() for b in branches]), @@ -758,7 +764,8 @@ class RevisionBrowse(RevisionPage): page_title=page_title, revision=revision, path_links=path_links(path_components), - row_class=row_class(), + row_class=row_class(), + mime_icon=mime_icon, entries=info_for_manifest(cut_manifest_to_subdir())) def ancestry_dot(revision): @@ -965,6 +972,16 @@ class BranchHead: anyhead=anyhead, head_links=head_links) +class MimeIcon: + def GET(self, type, sub_type): + mime_type = type+'/'+sub_type + icon_file = mimeicon.lookup(mime_type) + if icon_file: + web.header('Content-Type', 'image/png') + sys.stdout.write(open(icon_file).read()) + else: + return web.notfound() + branch_re = r'' urls = ( r'/', 'Index', #done @@ -994,7 +1011,8 @@ urls = ( r'/branch/(head)/([A-Za-z]+)/([^/]+)(.*)', 'BranchHead', r'/branch/(anyhead)/([A-Za-z]+)/([^/]+)(.*)', 'BranchHead', - r'/static/(.*)', 'Static' + r'/static/(.*)', 'Static', + r'/mimeicon/([A-Za-z0-9][a-z0-9\-\+]*)/([A-Za-z0-9][a-z0-9\-\+]*)', 'MimeIcon', ) if __name__ == '__main__': |