Exemple #1
0
    def get_accelgroup(self):
        accelgroup = gtk.AccelGroup()
        mod = gtklib.get_thg_modifier()
        
        gtklib.add_accelerator(self.filetree, 'thg-diff', accelgroup, mod+'d')
        self.filetree.connect('thg-diff', self.thgdiff)
        self.connect('thg-refresh', self.thgrefresh)

        # set CTRL-c accelerator for copy-clipboard
        gtklib.add_accelerator(self.chunks.difftree(), 'copy-clipboard', accelgroup, mod+'c')

        def scroll_diff_notebook(widget, direction=gtk.SCROLL_PAGE_DOWN):
            page_num = self.diff_notebook.get_current_page()
            page = self.diff_notebook.get_nth_page(page_num)

            page.emit("scroll-child", direction, False)

        def toggle_filetree_selection(*arguments):
            self.sel_clicked(not self.selcb.get_active())

        def next_diff_notebook_page(*arguments):
            notebook = self.diff_notebook
            if notebook.get_current_page() >= len(notebook) - 1:
                notebook.set_current_page(0)
            else:
                notebook.next_page()
                
        def previous_diff_notebook_page(*arguments):
            notebook = self.diff_notebook
            if notebook.get_current_page() <= 0:
                notebook.set_current_page(len(notebook) - 1)
            else:
                notebook.prev_page()
                
        # signal, accelerator key, handler, (parameters)
        status_accelerators = [
            ('status-scroll-down', 'bracketright', scroll_diff_notebook,
             (gtk.SCROLL_PAGE_DOWN,)),
            ('status-scroll-up', 'bracketleft', scroll_diff_notebook,
             (gtk.SCROLL_PAGE_UP,)),
            ('status-next-file', 'period', gtklib.move_treeview_selection,
             (self.filetree, 1)),
            ('status-previous-file', 'comma', gtklib.move_treeview_selection,
             (self.filetree, -1)),
            ('status-select-all', 'u', toggle_filetree_selection, ()),
            ('status-next-page', 'p', next_diff_notebook_page, ()),
            ('status-previous-page', '<Shift>p',
             previous_diff_notebook_page, ()),
        ]
        
        for signal, accelerator, handler, parameters in status_accelerators:
            gtklib.add_accelerator(self, signal, accelgroup,
                                   mod + accelerator)
            self.connect(signal, handler, *parameters)

        return accelgroup
Exemple #2
0
 def __init__(self, title, message, parent, type=gtk.MESSAGE_INFO):
     SimpleMessage.__init__(self, parent, gtk.DIALOG_MODAL,
             type, gtk.BUTTONS_CLOSE)
     self.set_title('TortoiseHg')
     self.set_markup(gtklib.markup(hglib.toutf(title), weight='bold'))
     self.format_secondary_text(hglib.toutf(message))
     mod = gtklib.get_thg_modifier()
     key, modifier = gtk.accelerator_parse(mod+'Return')
     accel_group = gtk.AccelGroup()
     self.add_accel_group(accel_group)
     try:
         buttons = self.get_children()[0].get_children()[1].get_children()
         buttons[0].add_accelerator('clicked', accel_group, key,
                                    modifier, gtk.ACCEL_VISIBLE)
     except IndexError:
         pass
Exemple #3
0
    def get_body(self):
        """ Initialize the Dialog. """
        self.grep_cmenu = self.grep_context_menu()
        self.changedesc = {}
        self.newpagecount = 1
        self.currev = None
        vbox = gtk.VBox()
        notebook = gtk.Notebook()
        notebook.set_tab_pos(gtk.POS_TOP)
        notebook.set_scrollable(True)
        notebook.popup_enable()
        notebook.show()
        self.notebook = notebook
        vbox.pack_start(self.notebook, True, True, 2)

        self.stop_button.set_sensitive(False)

        accelgroup = gtk.AccelGroup()
        self.add_accel_group(accelgroup)
        mod = gtklib.get_thg_modifier()
        key, modifier = gtk.accelerator_parse(mod+'w')
        notebook.add_accelerator('thg-close', accelgroup, key,
                        modifier, gtk.ACCEL_VISIBLE)
        notebook.connect('thg-close', self.close_notebook)
        key, modifier = gtk.accelerator_parse(mod+'n')
        notebook.add_accelerator('thg-new', accelgroup, key,
                        modifier, gtk.ACCEL_VISIBLE)
        notebook.connect('thg-new', self.new_notebook)

        # status bar
        hbox = gtk.HBox()
        style = csinfo.labelstyle(contents=('%(shortuser)s@%(revnum)s '
                       '%(dateage)s', ' "%(summary)s"',), selectable=True)
        self.cslabel = csinfo.create(self.repo, style=style)
        hbox.pack_start(self.cslabel, False, False, 4)
        self.stbar = statusbar.StatusBar()
        hbox.pack_start(self.stbar)
        vbox.pack_start(hbox, False, False)

        return vbox
Exemple #4
0
    def __init__(self, buffer=None, accelgroup=None):
        if buffer is None:
            buffer = UndoableTextBuffer()
        gtk.TextView.__init__(self, buffer)

        if accelgroup:
            mod = gtklib.get_thg_modifier()
            key, modifier = gtk.accelerator_parse(mod+'z')
            self.add_accelerator('thg-undo', accelgroup, key,
                                 modifier, gtk.ACCEL_VISIBLE)
            def do_undo(view):
                buffer = self.get_buffer()
                if hasattr(buffer, 'undo'):
                    buffer.undo()
            self.connect('thg-undo', do_undo)

            key, modifier = gtk.accelerator_parse(mod+'y')
            self.add_accelerator('thg-redo', accelgroup, key,
                                 modifier, gtk.ACCEL_VISIBLE)
            def do_redo(view):
                buffer = self.get_buffer()
                if hasattr(buffer, 'redo'):
                    buffer.redo()
            self.connect('thg-redo', do_redo)
Exemple #5
0
    def __init__(self, repo, pats, ctx1a, sa, ctx1b, sb, ctx2, cpy):
        'Initialize the Dialog'
        gtk.Dialog.__init__(self, title=_('Visual Diffs'))
        gtklib.set_tortoise_icon(self, 'menushowchanged.ico')
        gtklib.set_tortoise_keys(self)

        if ctx2.rev() is None:
            title = _('working changes')
        elif ctx1a == ctx2.parents()[0]:
            title = _('changeset ') + str(ctx2.rev())
        else:
            title = _('revisions %d to %d') % (ctx1a.rev(), ctx2.rev())
        title = _('Visual Diffs - ') + title
        if pats:
            title += _(' filtered')
        self.set_title(title)

        self.set_default_size(400, 250)
        self.set_has_separator(False)
        self.reponame=hglib.get_reponame(repo)

        self.ctxs = (ctx1a, ctx1b, ctx2)
        self.copies = cpy
        self.ui = repo.ui

        lbl = gtk.Label(_('Temporary files are removed when this dialog '
                          'is closed'))
        self.vbox.pack_start(lbl, False, False, 2)

        scroller = gtk.ScrolledWindow()
        scroller.set_shadow_type(gtk.SHADOW_IN)
        scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        treeview = gtk.TreeView()
        self.treeview = treeview
        treeview.get_selection().set_mode(gtk.SELECTION_SINGLE)
        treeview.set_search_equal_func(self.search_filelist)
        scroller.add(treeview)
        self.vbox.pack_start(scroller, True, True, 2)

        treeview.connect('row-activated', self.rowactivated)
        treeview.set_headers_visible(False)
        treeview.set_property('enable-grid-lines', True)
        treeview.set_enable_search(False)

        accelgroup = gtk.AccelGroup()
        self.add_accel_group(accelgroup)
        mod = gtklib.get_thg_modifier()
        key, modifier = gtk.accelerator_parse(mod+'d')
        treeview.add_accelerator('thg-diff', accelgroup, key,
                        modifier, gtk.ACCEL_VISIBLE)
        treeview.connect('thg-diff', self.rowactivated)

        cell = gtk.CellRendererText()
        stcol = gtk.TreeViewColumn('Status', cell)
        stcol.set_resizable(True)
        stcol.add_attribute(cell, 'text', 0)
        treeview.append_column(stcol)

        cell = gtk.CellRendererText()
        fcol = gtk.TreeViewColumn('Filename', cell)
        fcol.set_resizable(True)
        fcol.add_attribute(cell, 'text', 1)
        treeview.append_column(fcol)

        model = gtk.ListStore(str, str)
        treeview.set_model(model)

        tools = hglib.difftools(repo.ui)
        preferred = besttool(repo.ui, tools)
        self.diffpath, self.diffopts, self.mergeopts = tools[preferred]

        hbox = gtk.HBox()
        self.vbox.pack_start(hbox, False, False, 2)

        if ctx2.rev() is None:
            pass
            # Do not offer directory diffs when the working directory
            # is being referenced directly
        elif ctx1b:
            self.p1button = gtk.Button(_('Dir diff to p1'))
            self.p1button.connect('pressed', self.p1dirdiff)
            self.p2button = gtk.Button(_('Dir diff to p2'))
            self.p2button.connect('pressed', self.p2dirdiff)
            self.p3button = gtk.Button(_('3-way dir diff'))
            self.p3button.connect('pressed', self.threewaydirdiff)
            hbox.pack_end(self.p3button, False, False)
            hbox.pack_end(self.p2button, False, False)
            hbox.pack_end(self.p1button, False, False)
        else:
            self.dbutton = gtk.Button(_('Directory diff'))
            self.dbutton.connect('pressed', self.p1dirdiff)
            hbox.pack_end(self.dbutton, False, False)

        self.update_diff_buttons(preferred)

        if len(tools) > 1:
            combo = gtk.combo_box_new_text()
            for i, name in enumerate(tools.iterkeys()):
                combo.append_text(name)
                if name == preferred:
                    defrow = i
            combo.set_active(defrow)
            combo.connect('changed', self.toolselect, tools)
            hbox.pack_start(combo, False, False, 2)

            patterns = repo.ui.configitems('diff-patterns')
            patterns = [(p, t) for p,t in patterns if t in tools]
            filesel = treeview.get_selection()
            filesel.connect('changed', self.fileselect, repo, combo, tools,
                            patterns, preferred)

        gobject.idle_add(self.fillmodel, repo, model, sa, sb)
Exemple #6
0
    def add_annotate_page(self, path, revid):
        '''
        Add new annotation page to notebook.  Start scan of
        file 'path' revision history, start annotate of supplied
        revision 'revid'.
        '''
        if revid == '.':
            ctx = self.repo.parents()[0]
            try:
                fctx = ctx.filectx(path)
            except error.LookupError:
                gdialog.Prompt(_('File is unrevisioned'),
                       _('Unable to annotate ') + path, self).run()
                return
            rev = fctx.filelog().linkrev(fctx.filerev())
            revid = str(rev)
        else:
            rev = long(revid)

        frame = gtk.Frame()
        frame.set_border_width(10)
        vbox = gtk.VBox()

        graphopts = { 'date': None, 'no_merges':False, 'only_merges':False,
                'keyword':[], 'branch':None, 'pats':[], 'revrange':[],
                'revlist':[], 'noheads':False, 'orig-tip':len(self.repo),
                'branch-view':False, 'rev':[], 'npreviews':0 }
        graphopts['filehist'] = path

        # File log revision graph
        graphview = LogTreeView(self.repo, 5000)
        graphview.set_property('rev-column-visible', True)
        graphview.set_property('msg-column-visible', True)
        graphview.set_property('user-column-visible', True)
        graphview.set_property('age-column-visible', True)
        graphview.set_columns(['graph', 'rev', 'msg', 'user', 'age'])
        graphview.connect('revisions-loaded', self.revisions_loaded, rev)
        graphview.refresh(True, [path], graphopts)

        # Annotation text tree view
        treeview = gtk.TreeView()
        treeview.get_selection().set_mode(gtk.SELECTION_SINGLE)
        treeview.set_property('fixed-height-mode', True)
        treeview.set_border_width(0)

        accelgroup = gtk.AccelGroup()
        self.add_accel_group(accelgroup)
        mod = gtklib.get_thg_modifier()
        key, modifier = gtk.accelerator_parse(mod+'d')
        treeview.add_accelerator('thg-diff', accelgroup, key,
                        modifier, gtk.ACCEL_VISIBLE)
        treeview.connect('thg-diff', self.annotate_thgdiff)

        results = gtk.ListStore(str, # revision id
                                str, # file line (utf-8)
                                str, # description (utf-8, escaped)
                                str, # file path (utf-8)
                                str, # color
                                str, # author (utf-8)
                                str) # line number
        treeview.set_model(results)
        treeview.set_search_equal_func(self.search_in_file)

        context_menu = self.ann_header_context_menu(treeview)
        for title, width, col, emode, visible in (
                (_('Line'), 8, ACOL_LNUM, pango.ELLIPSIZE_NONE, True),
                (_('Rev'), 10, ACOL_REVID, pango.ELLIPSIZE_NONE, True),
                (_('File'), 15, ACOL_PATH, pango.ELLIPSIZE_START, False),
                (_('User'), 15, ACOL_USER, pango.ELLIPSIZE_END, False),
                (_('Source'), 80, ACOL_LINE, pango.ELLIPSIZE_END, True)):
            cell = gtk.CellRendererText()
            cell.set_property('width-chars', width)
            cell.set_property('ellipsize', emode)
            cell.set_property('family', 'Monospace')
            column = gtk.TreeViewColumn(title)
            column.set_resizable(True)
            column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
            column.set_fixed_width(cell.get_size(treeview)[2])
            column.pack_start(cell, expand=True)
            column.add_attribute(cell, 'text', col)
            column.add_attribute(cell, 'background', ACOL_COLOR)
            column.set_visible(visible)
            treeview.append_column(column)
            self.add_header_context_menu(column, context_menu)
        treeview.set_headers_clickable(True)
        if hasattr(treeview, 'set_tooltip_column'):
            treeview.set_tooltip_column(ACOL_DESC)
        results.path = path
        results.rev = revid
        scroller = gtk.ScrolledWindow()
        scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        scroller.add(treeview)

        vpaned = gtk.VPaned()
        vpaned.pack1(graphview, True, True)
        vpaned.pack2(scroller, True, True)
        vbox.pack_start(vpaned, True, True)
        frame.add(vbox)
        frame.show_all()

        hbox = gtk.HBox()
        lbl = gtk.Label(hglib.toutf(os.path.basename(path) + '@' + revid))
        close = self.create_tab_close_button()
        close.connect('clicked', self.close_page, frame)
        hbox.pack_start(lbl, True, True, 2)
        hbox.pack_start(close, False, False)
        hbox.show_all()
        num = self.notebook.append_page_menu(frame,
                hbox, gtk.Label(hglib.toutf(path + '@' + revid)))

        if hasattr(self.notebook, 'set_tab_reorderable'):
            self.notebook.set_tab_reorderable(frame, True)
        self.notebook.set_current_page(num)

        graphview.connect('revision-selected', self.log_selection_changed, path)

        objs = (frame, treeview, path, graphview)
        graphview.treeview.connect('row-activated', self.log_activate, objs)
        graphview.treeview.connect('button-release-event',
                self.ann_button_release, objs)
        graphview.treeview.connect('popup-menu', self.ann_popup_menu, objs)

        treeview.connect("cursor-changed", self.ann_selection_changed)
        treeview.connect('button-release-event', self.ann_button_release, objs)
        treeview.connect('popup-menu', self.ann_popup_menu, objs)
        treeview.connect('row-activated', self.ann_row_act, objs)

        self.stbar.begin(msg=_('Loading history...'))
Exemple #7
0
    def add_search_page(self):
        frame = gtk.Frame()
        frame.set_border_width(10)
        vbox = gtk.VBox()

        search_hbox = gtk.HBox()
        regexp = gtk.Entry()
        includes = gtk.Entry()
        if self.cwd.startswith(self.repo.root):
            try:
                relpath = util.canonpath(self.repo.root, self.cwd, '.')
                includes.set_text(relpath)
            except util.Abort:
                # Some paths inside root are invalid (.hg/*)
                pass
        excludes = gtk.Entry()
        search = gtk.Button(_('Search'))
        search_hbox.pack_start(gtk.Label(_('Regexp:')), False, False, 4)
        search_hbox.pack_start(regexp, True, True, 4)
        search_hbox.pack_start(gtk.Label(_('Includes:')), False, False, 4)
        search_hbox.pack_start(includes, True, True, 4)
        search_hbox.pack_start(gtk.Label(_('Excludes:')), False, False, 4)
        search_hbox.pack_start(excludes, True, True, 4)
        search_hbox.pack_start(search, False, False, 4)
        self.tooltips.set_tip(search, _('Start this search'))
        self.tooltips.set_tip(regexp, _('Regular expression search pattern'))
        self.tooltips.set_tip(includes, _('Comma separated list of '
                'inclusion patterns.  By default, the entire repository '
                'is searched.'))
        self.tooltips.set_tip(excludes, _('Comma separated list of '
                'exclusion patterns.  Exclusion patterns are applied '
                'after inclusion patterns.'))
        vbox.pack_start(search_hbox, False, False, 4)

        hbox = gtk.HBox()
        follow = gtk.CheckButton(_('Follow copies and renames'))
        ignorecase = gtk.CheckButton(_('Ignore case'))
        linenum = gtk.CheckButton(_('Show line numbers'))
        showall = gtk.CheckButton(_('Show all matching revisions'))
        hbox.pack_start(follow, False, False, 4)
        hbox.pack_start(ignorecase, False, False, 4)
        hbox.pack_start(linenum, False, False, 4)
        hbox.pack_start(showall, False, False, 4)
        vbox.pack_start(hbox, False, False, 4)

        treeview = gtk.TreeView()
        treeview.get_selection().set_mode(gtk.SELECTION_SINGLE)
        treeview.set_rules_hint(True)
        treeview.set_property('fixed-height-mode', True)
        treeview.connect("cursor-changed", self.grep_selection_changed)
        treeview.connect('button-release-event', self.grep_button_release)
        treeview.connect('popup-menu', self.grep_popup_menu)
        treeview.connect('row-activated', self.grep_row_act)

        accelgroup = gtk.AccelGroup()
        self.add_accel_group(accelgroup)
        mod = gtklib.get_thg_modifier()
        key, modifier = gtk.accelerator_parse(mod+'d')
        treeview.add_accelerator('thg-diff', accelgroup, key,
                        modifier, gtk.ACCEL_VISIBLE)
        treeview.connect('thg-diff', self.grep_thgdiff)

        results = gtk.ListStore(str, # revision id
                                str, # matched line (utf-8)
                                str, # description (utf-8, escaped)
                                str) # file path (utf-8)
        treeview.set_model(results)
        treeview.set_search_equal_func(self.search_in_grep)
        for title, width, ttype, col, emode in (
                (_('Rev'), 10, 'text', GCOL_REVID, pango.ELLIPSIZE_NONE),
                (_('File'), 25, 'text', GCOL_PATH, pango.ELLIPSIZE_START),
                (_('Matches'), 80, 'markup', GCOL_LINE, pango.ELLIPSIZE_END)):
            cell = gtk.CellRendererText()
            cell.set_property('width-chars', width)
            cell.set_property('ellipsize', emode)
            cell.set_property('family', 'Monospace')
            column = gtk.TreeViewColumn(title)
            column.set_resizable(True)
            column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
            column.set_fixed_width(cell.get_size(treeview)[2])
            column.pack_start(cell, expand=True)
            column.add_attribute(cell, ttype, col)
            treeview.append_column(column)
        if hasattr(treeview, 'set_tooltip_column'):
            treeview.set_tooltip_column(GCOL_DESC)
        scroller = gtk.ScrolledWindow()
        scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        scroller.add(treeview)
        vbox.pack_start(scroller, True, True)
        frame.add(vbox)
        frame.show_all()

        hbox = gtk.HBox()
        lbl = gtk.Label(_('Search %d') % self.newpagecount)
        close = self.create_tab_close_button()
        close.connect('clicked', self.close_page, frame)
        hbox.pack_start(lbl, True, True, 2)
        hbox.pack_start(close, False, False)
        hbox.show_all()
        num = self.notebook.append_page(frame, hbox)

        self.newpagecount += 1
        objs = (treeview.get_model(), frame, regexp, follow, ignorecase,
                excludes, includes, linenum, showall, search_hbox)
        # Clicking 'search' or hitting Enter in any text entry triggers search
        search.connect('clicked', self.trigger_search, objs)
        regexp.connect('activate', self.trigger_search, objs)
        includes.connect('activate', self.trigger_search, objs)
        excludes.connect('activate', self.trigger_search, objs)
        # Includes/excludes must disable following copies
        objs = (includes, excludes, follow)
        includes.connect('changed', self.update_following_possible, objs)
        excludes.connect('changed', self.update_following_possible, objs)
        self.update_following_possible(includes, objs)

        if hasattr(self.notebook, 'set_tab_reorderable'):
            self.notebook.set_tab_reorderable(frame, True)
        self.notebook.set_current_page(num)
        regexp.grab_focus()
Exemple #8
0
    def get_body(self):
        embedded = bool(self.stbar)
        use_expander = embedded and self.ui.configbool(
            'tortoisehg', 'changeset-expander')

        self.curfile = ''
        if self.repo.ui.configbool('tortoisehg', 'copyhash'):
            sel = (os.name == 'nt') and 'CLIPBOARD' or 'PRIMARY'
            self.clipboard = gtk.Clipboard(selection=sel)
        else:
            self.clipboard = None
        self.filemenu = self.file_context_menu()

        details_frame_parent = gtk.VBox()

        # changeset frame
        details_frame = gtk.Frame()
        details_frame.set_shadow_type(gtk.SHADOW_ETCHED_IN)
        scroller = gtk.ScrolledWindow()
        scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        details_frame.add(scroller)
        self.diffscroller = scroller

        details_box = gtk.VBox()
        scroller.add_with_viewport(details_box)
        scroller.child.set_shadow_type(gtk.SHADOW_NONE)

        ## changeset panel
        def revid_markup(revid, **kargs):
            opts = dict(face='monospace', size='9000')
            opts.update(kargs)
            return gtklib.markup(revid, **opts)
        def data_func(widget, item, ctx):
            def summary_line(desc):
                desc = hglib.tounicode(desc.replace('\0', '').split('\n')[0])
                return hglib.toutf(desc[:80])
            def revline_data(ctx, hl=False, branch=None):
                if isinstance(ctx, basestring):
                    return ctx
                desc = ctx.description()
                return (str(ctx.rev()), str(ctx), summary_line(desc), hl, branch)
            if item == 'cset':
                return revline_data(ctx)
            elif item == 'branch':
                value = hglib.toutf(ctx.branch())
                return value != 'default' and value or None
            elif item == 'parents':
                pindex = self.diff_other_parent() and 1 or 0
                pctxs = ctx.parents()
                parents = []
                for pctx in pctxs:
                    highlight = len(pctxs) == 2 and pctx == pctxs[pindex]
                    branch = None
                    if hasattr(pctx, 'branch') and pctx.branch() != ctx.branch():
                        branch = pctx.branch()
                    parents.append(revline_data(pctx, highlight, branch))
                return parents
            elif item == 'children':
                children = []
                for cctx in ctx.children():
                    branch = None
                    if hasattr(cctx, 'branch') and cctx.branch() != ctx.branch():
                        branch = cctx.branch()
                    children.append(revline_data(cctx, branch=branch))
                return children
            elif item in ('transplant', 'p4', 'svn'):
                ts = widget.get_data(item, usepreset=True)
                if not ts:
                    return None
                try:
                    tctx = self.repo[ts]
                    return revline_data(tctx)
                except (error.LookupError, error.RepoLookupError, error.RepoError):
                    return ts
            elif item == 'patch':
                if hasattr(ctx, '_patchname'):
                    desc = ctx.description()
                    return (ctx._patchname, str(ctx), summary_line(desc))
                return None
            raise csinfo.UnknownItem(item)
        def label_func(widget, item):
            if item == 'cset':
                return _('Changeset:')
            elif item == 'parents':
                return _('Parent:')
            elif item == 'children':
                return _('Child:')
            elif item == 'patch':
                return _('Patch:')
            raise csinfo.UnknownItem(item)
        def markup_func(widget, item, value):
            def revline_markup(revnum, revid, summary, highlight=None, branch=None):
                revnum = gtklib.markup(revnum)
                summary = gtklib.markup(summary)
                if revid:
                    revid = revid_markup(revid)
                    if branch:
                        return '%s (%s) %s %s' % (revnum, revid, branch, summary)
                    return '%s (%s) %s' % (revnum, revid, summary)
                else:
                    if branch:
                        return '%s - %s %s' % (revnum, branch, summary)
                    return '%s - %s' % (revnum, summary)
            if item in ('cset', 'transplant', 'patch', 'p4', 'svn'):
                if isinstance(value, basestring):
                    return revid_markup(value)
                return revline_markup(*value)
            elif item in ('parents', 'children'):
                csets = []
                for cset in value:
                    if isinstance(cset, basestring):
                        csets.append(revid_markup(cset))
                    else:
                        csets.append(revline_markup(*cset))
                return csets
            raise csinfo.UnknownItem(item)
        def widget_func(widget, item, markups):
            def linkwidget(revnum, revid, summary, highlight=None, branch=None):
                # revision label
                opts = dict(underline='single', color=gtklib.BLUE)
                if highlight:
                    opts['weight'] = 'bold'
                rev = '%s (%s)' % (gtklib.markup(revnum, **opts),
                        revid_markup(revid, **opts))
                revlabel = gtk.Label()
                revlabel.set_markup(rev)
                revlabel.set_selectable(True)
                revlabel.connect('button-release-event', self.link_event, revnum)
                # summary & branch label
                sum = gtklib.markup(summary)
                if branch:
                    sum = gtklib.markup(branch, color=gtklib.NORMAL,
                        background=gtklib.PGREEN) + ' ' + sum
                sumlabel = gtk.Label()
                sumlabel.set_markup(sum)
                sumlabel.set_selectable(True)
                box = gtk.HBox()
                box.pack_start(revlabel, False, False)
                box.pack_start(sumlabel, True, True, 4)
                return box
            def genwidget(param):
                if isinstance(param, basestring):
                    label = gtk.Label()
                    label.set_markup(param)
                    label.set_selectable(True)
                    return label
                return linkwidget(*param)
            if item in ('parents', 'children'):
                csets = widget.get_data(item)
                return [genwidget(cset) for cset in csets]
            elif item == 'transplant':
                cset = widget.get_data(item)
                return genwidget(cset)
            raise csinfo.UnknownItem(item)

        custom = csinfo.custom(data=data_func, label=label_func,
                               markup=markup_func, widget=widget_func)
        self.csetstyle = csinfo.panelstyle(contents=('cset', 'branch',
                                'user', 'dateage', 'parents', 'children',
                                'tags', 'transplant', 'p4', 'svn'), selectable=True)
        self.patchstyle = csinfo.panelstyle(contents=('patch', 'branch',
                                 'user', 'dateage', 'parents'),
                                 selectable=True)
        if use_expander:
            self.csetstyle['expander'] = True
            self.patchstyle['expander'] = True

        self.summarypanel = csinfo.create(self.repo, custom=custom)

        ## summary box (summarypanel + separator)
        self.summarybox = gtk.VBox()
        if use_expander:
            # don't scroll summarybox
            details_frame_parent.pack_start(self.summarybox, False, False)
        else:
            # scroll summarybox
            details_box.pack_start(self.summarybox, False, False)
        self.summarybox.pack_start(self.summarypanel, False, False)
        self.summarybox.pack_start(gtk.HSeparator(), False, False)

        ## changeset diff
        details_text = gtk.TextView()
        details_text.set_wrap_mode(gtk.WRAP_NONE)
        details_text.connect('populate-popup', self.add_to_popup)
        details_text.set_editable(False)
        details_text.modify_font(self.fonts['comment'])
        details_box.pack_start(details_text)

        self._buffer = gtk.TextBuffer()
        self.setup_tags()
        details_text.set_buffer(self._buffer)
        self.textview = details_text

        ## file list
        filelist_tree = gtk.TreeView()
        filelist_tree.set_headers_visible(False)
        filesel = filelist_tree.get_selection()
        filesel.connect('changed', self.filelist_rowchanged)
        self._filesel = filesel
        filelist_tree.connect('button-release-event',
                self.file_button_release)
        filelist_tree.connect('popup-menu', self.file_popup_menu)
        filelist_tree.connect('row-activated', self.file_row_act)
        filelist_tree.set_search_equal_func(self.search_filelist)
        filelist_tree.modify_font(self.fonts['list'])
        self._filelist_tree = filelist_tree

        accelgroup = gtk.AccelGroup()
        if self.glog_parent:
            self.glog_parent.add_accel_group(accelgroup)
        else:
            self.add_accel_group(accelgroup)
        mod = gtklib.get_thg_modifier()
        key, modifier = gtk.accelerator_parse(mod+'d')
        filelist_tree.add_accelerator('thg-diff', accelgroup, key,
                        modifier, gtk.ACCEL_VISIBLE)
        filelist_tree.connect('thg-diff', self.thgdiff)

        def scroll_details(widget, direction=gtk.SCROLL_PAGE_DOWN):
            self.diffscroller.emit("scroll-child", direction, False)

        # signal, accelerator key, handler, (parameters,)
        status_accelerators = [
            ('status-scroll-down', 'bracketright', scroll_details,
             (gtk.SCROLL_PAGE_DOWN,)),
            ('status-scroll-up', 'bracketleft', scroll_details,
             (gtk.SCROLL_PAGE_UP,)),
            ('status-next-file', 'period', gtklib.move_treeview_selection,
             (filelist_tree, 1)),
            ('status-previous-file', 'comma', gtklib.move_treeview_selection,
             (filelist_tree, -1)),
        ]
        
        for signal, accelerator, handler, param in status_accelerators:
            root = self.glog_parent or self
            gtklib.add_accelerator(root, signal, accelgroup,
                                   mod + accelerator)
            root.connect(signal, handler, *param)

        self._filelist = gtk.ListStore(
                gobject.TYPE_STRING,   # MAR status
                gobject.TYPE_STRING,   # filename (utf-8 encoded)
                gobject.TYPE_STRING,   # filename
                )
        filelist_tree.set_model(self._filelist)

        column = gtk.TreeViewColumn()
        filelist_tree.append_column(column)

        iconcell = gtk.CellRendererPixbuf()
        filecell = gtk.CellRendererText()

        column.pack_start(iconcell, expand=False)
        column.pack_start(filecell, expand=False)
        column.add_attribute(filecell, 'text', 1)

        size = gtk.ICON_SIZE_SMALL_TOOLBAR
        addedpixbuf = gtklib.get_icon_pixbuf('fileadd.ico', size)
        removedpixbuf = gtklib.get_icon_pixbuf('filedelete.ico', size)
        modifiedpixbuf = gtklib.get_icon_pixbuf('filemodify.ico', size)

        def cell_seticon(column, cell, model, iter):
            state = model.get_value(iter, 0)
            pixbuf = None
            if state == 'A':
                pixbuf = addedpixbuf
            elif state == 'R':
                pixbuf = removedpixbuf
            elif state == 'M':
                pixbuf = modifiedpixbuf
            cell.set_property('pixbuf', pixbuf)

        column.set_cell_data_func(iconcell, cell_seticon)

        list_frame = gtk.Frame()
        list_frame.set_shadow_type(gtk.SHADOW_ETCHED_IN)
        scroller = gtk.ScrolledWindow()
        scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        scroller.add(filelist_tree)
        flbox = gtk.VBox()
        list_frame.add(flbox)
        self.parent_box = gtk.VBox()
        flbox.pack_start(self.parent_box, False, False)
        flbox.pack_start(scroller)

        btn = gtk.CheckButton(_('Diff to second Parent'))
        btn.connect('toggled', self.parent_toggled)
        # don't pack btn yet to keep it initially invisible
        self.parent_button = btn

        self._hpaned = gtk.HPaned()
        self._hpaned.pack1(list_frame, True, True)
        self._hpaned.pack2(details_frame_parent, True, True)
        self._hpaned.set_position(self._setting_hpos)

        details_frame_parent.pack_start(details_frame, True, True)

        if embedded:
            # embedded by changelog browser
            return self._hpaned
        else:
            # add status bar for main app
            vbox = gtk.VBox()
            vbox.pack_start(self._hpaned, True, True)
            self.stbar = statusbar.StatusBar()
            self.stbar.show()
            vbox.pack_start(gtk.HSeparator(), False, False)
            vbox.pack_start(self.stbar, False, False)
            return vbox