Below is the file 'links.py' from this revision. You can also download the file.

# Copyright (C) 2005 Grahame Bowland <grahame@angrygoats.net>
#
# This program is made available under the GNU GPL version 2.0 or
# greater. See the accompanying file COPYING for details.
#
# This program is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE.

#
# links.py:
# link to various objects within a monotone database
#

import urllib, urlparse, cgi, binascii, rfc822
import json
import config

hq = cgi.escape

class Link(object):
    def __init__(self, description=None, link_type=None, **kwargs):
        self.absolute_uri = None
        self.relative_uri = None
        self.description = description
        self.json_args = None
        self.ctxt = kwargs['ctxt']

    def nbhq(self, s):
        return '&nbsp;'.join([hq(t) for t in s.split(' ')])

    def uri(self):
        if not self.absolute_uri is None:
            return self.absolute_uri
        elif not self.relative_uri is None:
            return self.ctxt.perdb_join(self.relative_uri)
        else:
            return None

    def html(self, override_description=None, force_nbsp=False):
        if override_description:
            if force_nbsp:
                d = self.nbhq(override_description)
            else:
                d = hq(override_description)
        else:
            d = self.description
        uri = self.uri()
        if uri is None:
            return hq(self.description)
        rv = '<a href="%s">%s</a>' % (uri, d)
        if self.json_args != None:
            enc_args = binascii.hexlify(json.write(self.json_args))
            rv = '<span id="js_%s" class="%s">' % (hq(enc_args),
                                                hq(str(self.__class__).split('.')[-1])) + rv + '</span>'
        return rv

class AuthorLink(Link):
    def __init__(self, author, **kwargs):
        Link.__init__(*(self, ), **kwargs)
        name, email = rfc822.parseaddr(author)
        self.description = author
        if email:
            self.absolute_uri = "mailto:%s" % urllib.quote(email)
        if name:
            self.description = hq(name)

class RevisionLink(Link):
    def __init__(self, revision, **kwargs):
        link_type = kwargs.get("link_type")
        if link_type == "browse":
            subpage = "browse"
        else:
            subpage = "info"
        Link.__init__(*(self, ), **kwargs)
        self.json_args = [str(revision)]
        self.relative_uri = 'revision/%s/%s' % (subpage, revision)
        self.description = revision.abbrev()

class TagLink(Link):
    def __init__(self, tag, **kwargs):
        Link.__init__(*(self, ), **kwargs)
        self.relative_uri = 'revision/info/%s' % (tag.revision)
        self.description = tag.name

class BranchLink(Link):
    def __init__(self, branch, **kwargs):
        Link.__init__(*(self, ), **kwargs)
        self.json_args = [branch.name]
        from_change, to_change = kwargs.get('from_change'), kwargs.get('to_change')
        if from_change and to_change:
            self.relative_uri = 'branch/changes/%s/from/%d/to/%d' % (urllib.quote(branch.name, safe = ''), from_change, to_change)
        else:
            self.relative_uri = 'branch/changes/' + urllib.quote(branch.name, safe = '')
        self.description = hq(branch.name)

class DiffLink(Link):
    def __init__(self, diff, **kwargs):
        Link.__init__(*(self, ), **kwargs)
        if kwargs.get('link_type', None) == "raw":
            mode = "rawdiff"
        else:
            mode = "diff"
        self.relative_uri = 'revision/%s/' % (mode) + diff.from_rev + '/with/' + diff.to_rev
        if isinstance(diff.fname, list):
            # TODO: figure out a linking scheme for diffs of multiple files.
            if len(diff.fname) > 0:
                fname = diff.fname[0]
            else:
                fname = None
        else:
            fname = diff.fname
        if fname is not None:
            self.relative_uri += '/'+urllib.quote(fname)
        self.description = "diff"

class DirLink(Link):
    def __init__(self, file, **kwargs):
        Link.__init__(*(self, ), **kwargs)
        # handle the root directory
        if file.name == '/':
            fn = ''
        else:
            fn = file.name
        self.relative_uri = 'revision/browse/' + file.in_revision + '/' + urllib.quote(fn)
        self.description = hq(file.name)

class FileLink(Link):
    def __init__(self, file, **kwargs):
        Link.__init__(*(self, ), **kwargs)
        if kwargs.has_key('for_download'):
            access_method = 'downloadfile'
        elif kwargs.has_key('for_changes'):
            access_method = 'filechanges'
        elif kwargs.has_key('for_changes_rss'):
            access_method = 'filechanges/rss'
        else:
            access_method = 'file'
        self.relative_uri = 'revision/' + access_method + '/' + file.in_revision + '/' + urllib.quote(file.name)
        self.description = hq(file.name)

type_to_link_class = {
    'author' : AuthorLink,
    'branch' : BranchLink,
    'diff' : DiffLink,
    'dir' : DirLink,
    'file' : FileLink,
    'revision' : RevisionLink,
    'tag' : TagLink,
}

def link(obj, link_type=None, **kwargs):
    link_class = type_to_link_class.get(obj.obj_type)
    if not link_class:
        raise LinkException("Unable to link to objects of type: '%s'" % (obj.obj_type))
    # bodgy, but can't give named arguments from the templates so we need to
    # have the second argument go into link_type
    if not link_type is None:
        kwargs['link_type'] = link_type
    rv = link_class(obj, **kwargs)
    return rv