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
def get_body(self, vbox): rev0, rev1 = self.revs prevs = [ctx.rev() for ctx in self.repo.parents()] if len(prevs) > 1: rev0, rev1 = prevs elif (not rev1 and rev1 != 0): gdialog.Prompt(_('Unable to merge'), _('Must supply a target revision'), self).run() gtklib.idle_add_single_call(self.hide) return False elif (not rev0 and rev0 != 0): rev0 = prevs[0] elif rev1 == prevs[0]: # selected pair was backwards rev0, rev1 = rev1, rev0 elif rev0 != prevs[0]: # working parent not in selected revision pair modified, added, removed, deleted = self.repo.status()[:4] if modified or added or removed or deleted: gdialog.Prompt(_('Unable to merge'), _('Outstanding uncommitted changes'), self).run() gtklib.idle_add_single_call(self.hide) return False self.repo.ui.quiet = True commands.update(self.repo.ui, self.repo, rev=str(rev0), check=True) self.repo.ui.quiet = False # changeset info style = csinfo.panelstyle(contents=csinfo.PANEL_DEFAULT + ('ishead',), margin=5, padding=2) def markup_func(widget, item, value): if item == 'ishead' and value is False: text = _('Not a head revision!') return gtklib.markup(text, weight='bold') raise csinfo.UnknownItem(item) custom = csinfo.custom(markup=markup_func) factory = csinfo.factory(self.repo, custom, style, withupdate=True) info = factory(rev1, style={'label': _('Merge target (other)')}) self.vbox.pack_start(info, False, False) self.otherframe = info self.otherrev = str(info.get_data('revnum')) info = factory(rev0, style={'label': _('Current revision (local)')}) self.vbox.pack_start(info, False, False) self.localframe = info self.localrev = str(info.get_data('revnum')) # expander for advanced options expander = gtk.Expander(_('Advanced options')) self.vbox.pack_start(expander, False, False) # layout table for advanced options table = gtklib.LayoutTable() expander.add(table) vlist = gtk.ListStore(str, # tool name bool) # separator combo = gtk.ComboBoxEntry(vlist, 0) self.mergetool = combo combo.set_row_separator_func(lambda model, path: model[path][1]) combo.child.set_width_chars(16) chtool = gtk.RadioButton(None, _('Use merge tool:')) self.mergelabel = chtool table.add_row(chtool, combo) prev = False for tool in hglib.mergetools(self.repo.ui): cur = tool.startswith('internal:') vlist.append((hglib.toutf(tool), prev != cur)) prev = cur mtool = self.repo.ui.config('ui', 'merge', None) if mtool: combo.child.set_text(hglib.toutf(mtool)) else: combo.child.set_text('') discard = gtk.RadioButton(chtool, _('Discard all changes from merge target (other) revision')) self.discard = discard table.add_row(discard) # prepare to show if len(self.repo.parents()) == 2: self.mergetool.set_sensitive(False) self.mergelabel.set_sensitive(False) self.discard.set_sensitive(False) self.buttons['merge'].set_sensitive(False) self.buttons['commit'].set_sensitive(True) self.buttons['undo'].set_sensitive(True) else: self.buttons['commit'].set_sensitive(False) self.buttons['undo'].set_sensitive(False)