def __init__(self, resizable=False, norepo=False): gtk.Dialog.__init__(self) gtklib.set_tortoise_icon(self, self.get_icon()) gtklib.set_tortoise_keys(self) self.set_resizable(resizable) self.set_has_separator(False) self.earlyout = False self.ui = ui.ui() if norepo: repo = None else: try: repo = hg.repository(self.ui, path=paths.find_root()) except error.RepoError: gtklib.idle_add_single_call(self.destroy) return self.repo = repo self.after_done = True # persistent settings name = self.get_setting_name() if name: self.settings = settings.Settings(name) # signal handler self.connect('realize', self.realized) # disable entire dialog self.set_sensitive(False)
def operation(self): fm = self.filetree.get_model() deleting = self.command == 'remove' list, dellist = [], [] for row in fm: if not row[0]: continue if deleting and row[3] in (_('unknown'), _('ignored')): dellist.append(row[1]) else: list.append(row[1]) if not (list or dellist): gdialog.Prompt(_('No files selected'), _('No operation to perform'), self).run() return for file in dellist: try: os.unlink(file) except EnvironmentError: pass if not list: gtklib.idle_add_single_call(self.response, gtk.RESPONSE_CLOSE) return # prepare command line cmdline = ['hg', self.command, '--verbose'] if hasattr(self, 'nobackup') and self.nobackup.get_active(): cmdline.append('--no-backup') cmdline.append('--') cmdline += list # execute command self.execute_command(cmdline, list)
def list_pressed(self, list, event): x, y = int(event.x), int(event.y) pathinfo = list.get_path_at_pos(x, y) if event.button == 1: if not pathinfo: # HACK: clear selection after this function calling, # against selection by getting focus def unselect(): selection = list.get_selection() selection.unselect_all() gtklib.idle_add_single_call(unselect) elif event.button == 3: if pathinfo: self.show_patch_cmenu(self.list, pathinfo[0])
def __init__(self, extra=None): gtk.HBox.__init__(self) self.fields = {} self.boxes = {} self.idle_text = None self.timeout_id = None self.append_field('status', expand=True, sep=False) self.pbar = gtk.ProgressBar() self.pbar.set_no_show_all(True) self.append_widget(self.pbar, pack=gtk.PACK_START) gtklib.idle_add_single_call(self.after_init)
def process_queue(self, callback, args, kargs): # process queue self.hgthread.process_dialogs() # output to buffer while self.hgthread.geterrqueue().qsize(): try: msg = self.hgthread.geterrqueue().get(0) self.log.append(hglib.toutf(msg), error=True) except Queue.Empty: pass while self.hgthread.getqueue().qsize(): try: msg, label = self.hgthread.getqueue().get(0) self.log.append(hglib.toutf(msg)) except Queue.Empty: pass # update progress bar self.update_progress() # check thread if not self.hgthread.isAlive(): returncode = self.hgthread.return_code() if returncode == 0 and not self.already_opened: self.set_pbar(False) else: self.set_pbar(True) self.switch_to(ready=True) self.set_buttons(stop=False, close=True) if returncode is None: self.log.append(_('\n[command interrupted]')) if not returncode == 0: self.show_log() self.hgthread = None def call_callback(): callback(returncode, self.useraborted, *args, **kargs) self.useraborted = False gtklib.idle_add_single_call(call_callback) return False # Stop polling this function else: return True # Continue polling
def list_pressed(self, list, event): x, y = int(event.x), int(event.y) pathinfo = list.get_path_at_pos(x, y) if event.button == 1: if not pathinfo: # HACK: clear selection after this function calling, # against selection by getting focus def unselect(): selection = list.get_selection() selection.unselect_all() gtklib.idle_add_single_call(unselect) elif event.button == 3 and pathinfo: sel = list.get_selection() sel_rows = sel.get_selected_rows()[1] # list of paths if pathinfo[0] not in sel_rows: sel.unselect_all() sel.select_path(pathinfo[0]) return True
def realized(self, *args): # set title reponame = self.repo and hglib.get_reponame(self.repo) or '' self.set_title(self.get_title(reponame)) # add user-defined buttons self.buttons = {} for name, label, res in self.get_buttons(): btn = self.add_button(label, res) self.buttons[name] = btn # create Abort button (add later) btn = gtk.Button(_('Abort')) btn.connect('clicked', lambda *a: self.response(gtk.RESPONSE_CANCEL)) self.buttons['abort'] = btn # construct dialog body self.get_body(self.vbox) if self.earlyout: gtklib.idle_add_single_call(self.destroy) return # load persistent settings self.load_settings() # dialog size defsize = self.get_defsize() if defsize != (-1, -1): self.set_default_size(*defsize) # signal handler self.connect('response', self.dialog_response) # prepare to show self.before_show() self.vbox.show_all() gtklib.idle_add_single_call(self.after_init)
def process_queue(self, callback, args, kargs): # process queue self.hgthread.process_dialogs() # receive messages from queue while self.hgthread.getqueue().qsize(): try: msg = hglib.toutf(self.hgthread.getqueue().get(0)[0]) self.buffer.append((msg, LOG_NORMAL)) self.dlg.log.append(msg) except Queue.Empty: pass while self.hgthread.geterrqueue().qsize(): try: msg = hglib.toutf(self.hgthread.geterrqueue().get(0)) self.buffer.append((msg, LOG_ERROR)) self.dlg.log.append(msg, error=True) except Queue.Empty: pass # check thread state if not self.hgthread.isAlive(): returncode = self.hgthread.return_code() self.hgthread = None if len(self.get_err_buffer()) > 0: self.show_log(True) if returncode == 0 and self.cmdlist: def call_next(): self.execute_next(callback, args, kargs) gtklib.idle_add_single_call(call_next) else: def call_callback(): callback(returncode, self.get_buffer(), *args, **kargs) gtklib.idle_add_single_call(call_callback) return False # Stop polling this function else: return True # Continue polling
def __init__(self, root='', revargs=[]): """ Initialize the Dialog """ gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL) gtklib.set_tortoise_icon(self, 'hg.ico') gtklib.set_tortoise_keys(self) self.root = root self.revargs = revargs self.tbar = gtk.Toolbar() self.tips = gtklib.Tooltips() tbuttons = [ self._toolbutton(gtk.STOCK_GOTO_LAST, _('Send'), self._on_send_clicked, _('Send emails')), self._toolbutton(gtk.STOCK_FIND, _('Test'), self._on_test_clicked, _('Show emails which would be sent')), gtk.SeparatorToolItem(), self._toolbutton(gtk.STOCK_PREFERENCES, _('Configure'), self._on_conf_clicked, _('Configure email settings')) ] for btn in tbuttons: self.tbar.insert(btn, -1) mainvbox = gtk.VBox() self.add(mainvbox) mainvbox.pack_start(self.tbar, False, False, 2) # set dialog title if revargs[0] in ('--outgoing', '-o'): self.set_title(_('Email outgoing changes')) elif revargs[0] in ('--rev', '-r'): self.set_title(_('Email revisions ') + ' '.join(revargs[1:])) else: self.set_title(_('Email Mercurial Patches')) self.set_default_size(650, 450) hbox = gtk.HBox() envframe = gtk.Frame(_('Envelope')) flagframe = gtk.Frame(_('Options')) hbox.pack_start(envframe, True, True, 4) hbox.pack_start(flagframe, False, False, 4) mainvbox.pack_start(hbox, False, True, 4) # Envelope settings table = gtklib.LayoutTable() envframe.add(table) ## To: combo box self._tolist = gtk.ListStore(str) self._tobox = gtk.ComboBoxEntry(self._tolist, 0) table.add_row(_('To:'), self._tobox, padding=False) ## Cc: combo box self._cclist = gtk.ListStore(str) self._ccbox = gtk.ComboBoxEntry(self._cclist, 0) table.add_row(_('Cc:'), self._ccbox, padding=False) ## From: combo box self._fromlist = gtk.ListStore(str) self._frombox = gtk.ComboBoxEntry(self._fromlist, 0) table.add_row(_('From:'), self._frombox, padding=False) ## In-Reply-To: entry self._replyto = gtk.Entry() table.add_row(_('In-Reply-To:'), self._replyto, padding=False) self.tips.set_tip(self._replyto, _('Message identifier to reply to, for threading')) # Options table = gtklib.LayoutTable() flagframe.add(table) self._normal = gtk.RadioButton(None, _('Send changesets as Hg patches')) table.add_row(self._normal) self.tips.set_tip(self._normal, _('Hg patches (as generated by export command) are compatible ' 'with most patch programs. They include a header which ' 'contains the most important changeset metadata.')) self._git = gtk.RadioButton(self._normal, _('Use extended (git) patch format')) table.add_row(self._git) self.tips.set_tip(self._git, _('Git patches can describe binary files, copies, and ' 'permission changes, but recipients may not be able to ' 'use them if they are not using git or Mercurial.')) self._plain = gtk.RadioButton(self._normal, _('Plain, do not prepend Hg header')) table.add_row(self._plain) self.tips.set_tip(self._plain, _('Stripping Mercurial header removes username and parent ' 'information. Only useful if recipient is not using ' 'Mercurial (and does not like to see the headers).')) self._bundle = gtk.RadioButton(self._normal, _('Send single binary bundle, not patches')) table.add_row(self._bundle) if revargs[0] in ('--outgoing', '-o'): self.tips.set_tip(self._bundle, _('Bundles store complete changesets in binary form. ' 'Upstream users can pull from them. This is the safest ' 'way to send changes to recipient Mercurial users.')) else: self._bundle.set_sensitive(False) self.tips.set_tip(self._bundle, _('This feature is only available when sending outgoing ' 'changesets. It is not applicable with revision ranges.')) self._attach = gtk.CheckButton(_('attach')) self.tips.set_tip(self._attach, _('send patches as attachments')) self._inline = gtk.CheckButton(_('inline')) self.tips.set_tip(self._inline, _('send patches as inline attachments')) self._diffstat = gtk.CheckButton(_('diffstat')) self.tips.set_tip(self._diffstat, _('add diffstat output to messages')) table.add_row(self._attach, self._inline, self._diffstat, padding=False) # Subject combo vbox = gtk.VBox() hbox = gtk.HBox() self._subjlist = gtk.ListStore(str) self._subjbox = gtk.ComboBoxEntry(self._subjlist, 0) hbox.pack_start(gtk.Label(_('Subject:')), False, False, 4) hbox.pack_start(self._subjbox, True, True, 4) hglib.loadextension(ui.ui(), 'patchbomb') # --flags was added after hg 1.3 hasflags = False for arg in extensions.find('patchbomb').emailopts: if arg[1] == 'flag': hasflags = True break self._flaglist = gtk.ListStore(str) self._flagbox = gtk.ComboBoxEntry(self._flaglist, 0) if hasflags: hbox.pack_start(gtk.Label(_('Flags:')), False, False, 4) hbox.pack_start(self._flagbox, False, False, 4) vbox.pack_start(hbox, False, False, 4) # Description TextView accelgroup = gtk.AccelGroup() self.add_accel_group(accelgroup) self.descview = textview.UndoableTextView(accelgroup=accelgroup) self.descview.set_editable(True) fontcomment = hglib.getfontconfig()['fontcomment'] self.descview.modify_font(pango.FontDescription(fontcomment)) self.descbuffer = self.descview.get_buffer() scrolledwindow = gtk.ScrolledWindow() scrolledwindow.set_shadow_type(gtk.SHADOW_ETCHED_IN) scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scrolledwindow.add(self.descview) frame = gtk.Frame(_('Patch Series (Bundle) Description')) frame.set_border_width(4) vbox.pack_start(scrolledwindow, True, True, 4) vbox.set_border_width(4) eventbox = gtk.EventBox() eventbox.add(vbox) frame.add(eventbox) self._eventbox = eventbox mainvbox.pack_start(frame, True, True, 4) gtklib.idle_add_single_call(self._refresh, True)
def _drag_receive(self, widget, context, x, y, selection, targetType, time): if time != self.last_drop_time: files = selection.get_uris() gtklib.idle_add_single_call(self._set_path, files[0]) self.last_drop_time = time
def __init__(self, repo, accelgroup=None, tooltips=None): gtk.VBox.__init__(self) self.repo = repo self.mqloaded = hasattr(repo, 'mq') # top toolbar tbar = gtklib.SlimToolbar(tooltips) ## buttons self.btn = {} popallbtn = tbar.append_button(gtk.STOCK_GOTO_TOP, _('Unapply all patches')) popallbtn.connect('clicked', lambda *a: self.qpop(all=True)) self.btn['popall'] = popallbtn popbtn = tbar.append_button(gtk.STOCK_GO_UP, _('Unapply last patch')) popbtn.connect('clicked', lambda *a: self.qpop()) self.btn['pop'] = popbtn pushbtn = tbar.append_button(gtk.STOCK_GO_DOWN, _('Apply next patch')) pushbtn.connect('clicked', lambda *a: self.qpush()) self.btn['push'] = pushbtn pushallbtn = tbar.append_button(gtk.STOCK_GOTO_BOTTOM, _('Apply all patches')) pushallbtn.connect('clicked', lambda *a: self.qpush(all=True)) self.btn['pushall'] = pushallbtn ## separator tbar.append_space() ## drop-down menu menubtn = gtk.MenuToolButton('') menubtn.set_menu(self.create_view_menu()) tbar.append_widget(menubtn, padding=0) self.btn['menu'] = menubtn def after_init(): menubtn.child.get_children()[0].hide() gtklib.idle_add_single_call(after_init) self.pack_start(tbar, False, False) closebtn = tbar.append_button(gtk.STOCK_CLOSE, _('Close')) closebtn.connect('clicked', lambda *a: self.emit('close-mq')) self.btn['close'] = closebtn # center pane mainbox = gtk.VBox() self.pack_start(mainbox, True, True) ## scrolled pane pane = gtk.ScrolledWindow() pane.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) pane.set_shadow_type(gtk.SHADOW_IN) mainbox.pack_start(pane) ### patch list self.model = gtk.ListStore(int, # patch index str, # patch status str, # patch name str, # summary (utf-8) str) # escaped summary (utf-8) self.list = gtk.TreeView(self.model) self.list.set_row_separator_func(self.row_sep_func) # To support old PyGTK (<2.12) if hasattr(self.list, 'set_tooltip_column'): self.list.set_tooltip_column(MQ_ESCAPED) self.list.get_selection().set_mode(gtk.SELECTION_MULTIPLE) if hasattr(self.list, 'set_rubber_banding'): self.list.set_rubber_banding(True) self.list.connect('cursor-changed', self.list_sel_changed) self.list.connect('button-press-event', self.list_pressed) self.list.connect('button-release-event', self.list_released) self.list.connect('row-activated', self.list_row_activated) self.list.connect('size-allocate', self.list_size_allocated) ### dnd setup for patch list targets = [('text/uri-list', 0, MQ_DND_URI_LIST)] self.list.drag_dest_set(gtk.DEST_DEFAULT_MOTION | \ gtk.DEST_DEFAULT_DROP, targets, gtk.gdk.ACTION_MOVE) self.list.connect('drag-data-received', self.dnd_received) self.cols = {} self.cells = {} def addcol(header, col_idx, right=False, resizable=False, editable=False, editfunc=None): header = (right and '%s ' or ' %s') % header cell = gtk.CellRendererText() if editfunc: cell.set_property('editable', editable) cell.connect('edited', editfunc) col = gtk.TreeViewColumn(header, cell) col.add_attribute(cell, 'text', col_idx) col.set_cell_data_func(cell, self.cell_data_func) col.set_resizable(resizable) col.set_visible(self.get_property(self.col_to_prop(col_idx))) if right: col.set_alignment(1) cell.set_property('xalign', 1) self.list.append_column(col) self.cols[col_idx] = col self.cells[col_idx] = cell def cell_edited(cell, path, newname): row = self.model[path] if row[MQ_INDEX] < 0: return patchname = row[MQ_NAME] if newname != patchname: self.qrename(newname, patch=patchname) addcol(_('#'), MQ_INDEX, right=True) addcol(_('st'), MQ_STATUS) addcol(_('Patch'), MQ_NAME, editfunc=cell_edited) addcol(_('Summary'), MQ_SUMMARY, resizable=True) pane.add(self.list) ## command widget self.cmd = hgcmd.CmdWidget(style=hgcmd.STYLE_COMPACT, tooltips=tooltips) mainbox.pack_start(self.cmd, False, False) # accelerators if accelgroup: key, mod = gtk.accelerator_parse('F2') self.list.add_accelerator('thg-rename', accelgroup, key, mod, gtk.ACCEL_VISIBLE) def thgrename(list): sel = self.list.get_selection() if sel.count_selected_rows() == 1: model, paths = sel.get_selected_rows() self.qrename_ui(model[paths[0]][MQ_NAME]) self.list.connect('thg-rename', thgrename) def add(name, key, mod, func, *args): self.list.add_accelerator(name, accelgroup, key, mod, 0) self.list.connect(name, lambda *a: func(*args)) mod = gtk.gdk.CONTROL_MASK|gtk.gdk.SHIFT_MASK add('mq-move-top', gtk.keysyms.Page_Up, mod, self.qreorder_ui, MOVE_TOP) add('mq-move-up', gtk.keysyms.Up, mod, self.qreorder_ui, MOVE_UP) add('mq-move-down', gtk.keysyms.Down, mod, self.qreorder_ui, MOVE_DOWN) add('mq-move-bottom', gtk.keysyms.Page_Down, mod, self.qreorder_ui, MOVE_BOTTOM) mod = gtk.gdk.CONTROL_MASK add('mq-pop', gtk.keysyms.Up, mod, self.qpop) add('mq-push', gtk.keysyms.Down, mod, self.qpush)
def __init__(self): 'Initialize the Dialog' gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL) gtklib.set_tortoise_icon(self, 'detect_rename.ico') gtklib.set_tortoise_keys(self) try: repo = hg.repository(ui.ui(), path=paths.find_root()) except error.RepoError: gtklib.idle_add_single_call(self.destroy) return self.repo = repo self.notify_func = None reponame = hglib.get_reponame(repo) self.set_title(_('Detect Copies/Renames in %s') % reponame) self.settings = settings.Settings('guess') dims = self.settings.get_value('dims', (800, 600)) self.set_default_size(dims[0], dims[1]) # vbox for dialog main & status bar mainvbox = gtk.VBox() self.add(mainvbox) # vsplit for top & diff self.vpaned = gtk.VPaned() mainvbox.pack_start(self.vpaned, True, True, 2) pos = self.settings.get_value('vpaned', None) if pos: self.vpaned.set_position(pos) # vbox for top contents topvbox = gtk.VBox() self.vpaned.pack1(topvbox, True, False) # frame for simularity frame = gtk.Frame(_('Minimum Simularity Percentage')) topvbox.pack_start(frame, False, False, 2) #$ simularity slider self.adjustment = gtk.Adjustment(50, 0, 100, 1) value = self.settings.get_value('percent', None) if value: self.adjustment.set_value(value) hscale = gtk.HScale(self.adjustment) frame.add(hscale) # horizontal splitter for unknown & candidate self.hpaned = gtk.HPaned() topvbox.pack_start(self.hpaned, True, True, 2) pos = self.settings.get_value('hpaned', None) if pos: self.hpaned.set_position(pos) #$ frame for unknown list unknownframe = gtk.Frame(_('Unrevisioned Files')) self.hpaned.pack1(unknownframe, True, True) #$$ vbox for unknown list & rename/copy buttons unkvbox = gtk.VBox() unknownframe.add(unkvbox) #$$$ scroll window for unknown list scroller = gtk.ScrolledWindow() unkvbox.pack_start(scroller, True, True, 2) scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) #$$$$ unknown list unkmodel = gtk.ListStore(str, # path str) # path (utf-8) self.unktree = gtk.TreeView(unkmodel) scroller.add(self.unktree) self.unktree.get_selection().set_mode(gtk.SELECTION_MULTIPLE) cell = gtk.CellRendererText() cell.set_property("ellipsize", pango.ELLIPSIZE_START) col = gtk.TreeViewColumn('File', cell, text=1) self.unktree.append_column(col) self.unktree.set_enable_search(True) self.unktree.set_headers_visible(False) #$$$ hbox for rename/copy buttons btnhbox = gtk.HBox() unkvbox.pack_start(btnhbox, False, False, 2) #$$$$ rename/copy buttons in unknown frame self.renamebtn = gtk.Button(_('Find Renames')) self.renamebtn.set_sensitive(False) btnhbox.pack_start(self.renamebtn, False, False, 2) self.copybtn = gtk.Button(_('Find Copies')) self.copybtn.set_sensitive(False) btnhbox.pack_start(self.copybtn, False, False, 2) #$ frame for candidate list candidateframe = gtk.Frame(_('Candidate Matches')) self.hpaned.pack2(candidateframe, True, True) #$$ vbox for candidate list & accept button canvbox = gtk.VBox() candidateframe.add(canvbox) #$$$ scroll window for candidate list scroller = gtk.ScrolledWindow() canvbox.pack_start(scroller, True, True, 2) scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) #$$$$ candidate list canmodel = gtk.ListStore(str, # source str, # source (utf-8) str, # dest str, # dest (utf-8) str, # percent bool) # sensitive self.cantree = gtk.TreeView(canmodel) scroller.add(self.cantree) self.cantree.set_rules_hint(True) self.cantree.set_reorderable(False) self.cantree.set_enable_search(False) self.cantree.get_selection().set_mode(gtk.SELECTION_MULTIPLE) cell = gtk.CellRendererText() cell.set_property('width-chars', 30) cell.set_property('ellipsize', pango.ELLIPSIZE_START) col = gtk.TreeViewColumn(_('Source'), cell, text=1, sensitive=5) col.set_resizable(True) self.cantree.append_column(col) cell = gtk.CellRendererText() cell.set_property('width-chars', 30) cell.set_property('ellipsize', pango.ELLIPSIZE_START) col = gtk.TreeViewColumn(_('Dest'), cell, text=3, sensitive=5) col.set_resizable(True) self.cantree.append_column(col) cell = gtk.CellRendererText() cell.set_property('width-chars', 5) cell.set_property('ellipsize', pango.ELLIPSIZE_NONE) col = gtk.TreeViewColumn('%', cell, text=4, sensitive=5) col.set_resizable(True) self.cantree.append_column(col) #$$$ hbox for accept button btnhbox = gtk.HBox() canvbox.pack_start(btnhbox, False, False, 2) #$$$$ accept button in candidate frame self.acceptbtn = gtk.Button(_('Accept Match')) btnhbox.pack_start(self.acceptbtn, False, False, 2) self.acceptbtn.set_sensitive(False) # frame for diff diffframe = gtk.Frame(_('Differences from Source to Dest')) self.vpaned.pack2(diffframe) diffframe.set_shadow_type(gtk.SHADOW_ETCHED_IN) #$ scroll window for diff scroller = gtk.ScrolledWindow() diffframe.add(scroller) scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) #$$ text view for diff self.buf = gtk.TextBuffer() self.buf.create_tag('removed', foreground=gtklib.DRED) self.buf.create_tag('added', foreground=gtklib.DGREEN) self.buf.create_tag('position', foreground=gtklib.DORANGE) self.buf.create_tag('header', foreground=gtklib.DBLUE) diffview = gtk.TextView(self.buf) scroller.add(diffview) fontdiff = hglib.getfontconfig()['fontdiff'] diffview.modify_font(pango.FontDescription(fontdiff)) diffview.set_wrap_mode(gtk.WRAP_NONE) diffview.set_editable(False) # status bar self.stbar = statusbar.StatusBar() mainvbox.pack_start(self.stbar, False, False, 2) # register signal handlers self.copybtn.connect('pressed', lambda b: self.find_copies()) self.renamebtn.connect('pressed', lambda b: self.find_renames()) self.acceptbtn.connect('pressed', lambda b: self.accept_match()) self.unktree.get_selection().connect('changed', self.unknown_sel_change) self.cantree.connect('row-activated', lambda t,p,c: self.accept_match()) self.cantree.get_selection().connect('changed', self.show_diff) self.connect('delete-event', lambda *a: self.save_settings()) gtklib.idle_add_single_call(self.refresh)
def prepare_display(self): val = self.repo.ui.config('tortoisehg', 'ciexclude', '') self.excludes = [i.strip() for i in val.split(',') if i.strip()] gtklib.idle_add_single_call(self.realize_status_settings)
def __init__(self, style=STYLE_NORMAL, tooltips=None, logsize=None): """ style: String. Predefined constans of CmdWidget style. Two styles, STYLE_NORMAL (progress bar + popup log viewer) and STYLE_COMPACT (progress bar + embedded log viewer) are available. Default: STYLE_NORMAL. tooltips: Reference. gtk.Tooltips instance to show tooltips of several buttons. If omitted, a new instance of gtk.Tooltips will be created. Default: None. logsize: Tuple or list containing two numbers. Specify the size of the embedded log viewer. size[0] = width, size[1] = height. If you pass -1 as width or height size, it will be set to the natural size of the widget. Default: tuple(-1, 180). """ gtk.VBox.__init__(self) self.hgthread = None self.last_pbar_update = 0 self.useraborted = False self.is_normal = style == STYLE_NORMAL self.is_compact = style == STYLE_COMPACT # tooltips if tooltips is None: tooltips = gtklib.Tooltips() # log viewer if self.is_normal: self.log = CmdLogWidget() if logsize is None: logsize = (-1, 180) self.log.set_size_request(logsize[0], logsize[1]) self.log.size_request() self.pack_start(self.log) elif self.is_compact: self.dlg = CmdLogDialog() def close_hook(dialog): self.show_log(False) return False self.dlg.set_close_hook(close_hook) self.log = self.dlg.get_logwidget() else: raise _('unknown CmdWidget style: %s') % style # progress status frame statframe = gtk.Frame() statframe.set_border_width(4) statframe.set_shadow_type(gtk.SHADOW_NONE) self.pack_start(statframe, False, False) # progress bar box self.progbox = progbox = gtklib.SlimToolbar(tooltips) self.pack_start(progbox, False, False) def add_button(stock_id, tooltip, handler, toggle=False): btn = progbox.append_button(stock_id, tooltip, toggle) btn.connect('clicked', handler) return btn ## log toggle button self.log_btn = add_button(gtk.STOCK_JUSTIFY_LEFT, _('Toggle log window'), self.log_toggled, toggle=True) ## result frame self.rframe = gtk.Frame() progbox.append_widget(self.rframe, expand=True) self.rframe.set_shadow_type(gtk.SHADOW_IN) rhbox = gtk.HBox() self.rframe.add(rhbox) ### result label self.rlabel = gtk.Label() rhbox.pack_end(self.rlabel, True, True, 2) self.rlabel.set_alignment(0, 0.5) def after_init(): # result icons self.icons = {} def add_icon(name, stock): img = gtk.Image() rhbox.pack_start(img, False, False, 2) img.set_from_stock(stock, gtk.ICON_SIZE_SMALL_TOOLBAR) self.icons[name] = img add_icon('succeed', gtk.STOCK_APPLY) add_icon('error', gtk.STOCK_DIALOG_ERROR) # progres status label self.progstat = gtk.Label() statframe.add(self.progstat) self.progstat.set_alignment(0, 0.5) self.progstat.set_ellipsize(pango.ELLIPSIZE_END) self.progstat.hide() # progress bar self.pbar = gtk.ProgressBar() progbox.append_widget(self.pbar, expand=True) self.pbar.hide() # stop & close buttons if self.is_compact: self.stop_btn = add_button(gtk.STOCK_STOP, _('Stop transaction'), self.stop_clicked) self.close_btn = add_button(gtk.STOCK_CLOSE, _('Close this'), self.close_clicked) self.set_buttons(stop=False) if self.is_normal: self.show_log(False) if self.is_compact: self.set_pbar(False) gtklib.idle_add_single_call(after_init)
def __init__(self, repos=[], pushmode=False): """ Initialize the Dialog. """ gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL) gtklib.set_tortoise_icon(self, 'menusynch.ico') gtklib.set_tortoise_keys(self) self.root = paths.find_root() self.selected_path = None self.hgthread = None self.notify_func = None self.last_drop_time = None self.lastcmd = [] # persistent app data self._settings = settings.Settings('synch') self.set_default_size(655, 552) self.paths = self.get_paths() self.set_title(_('%s - synchronize') % hglib.get_reponame(self.repo)) self.connect('delete-event', self.delete) # toolbar self.tbar = gtk.Toolbar() self.tips = gtklib.Tooltips() self.stop_button = self.toolbutton(gtk.STOCK_STOP, _('Stop'), self.stop_clicked, tip=_('Stop the hg operation')) self.stop_button.set_sensitive(False) tbuttons = [ self.toolbutton(gtk.STOCK_GO_DOWN, _('Incoming'), self.incoming_clicked, tip=_('Display changes that can be pulled ' 'from selected repository')), self.toolbutton(gtk.STOCK_GOTO_BOTTOM, _(' Pull '), self.pull_clicked, tip=_('Pull changes from selected ' 'repository')), gtk.SeparatorToolItem(), self.toolbutton(gtk.STOCK_GO_UP, _('Outgoing'), self.outgoing_clicked, tip=_('Display local changes that will be ' 'pushed to selected repository')), self.toolbutton(gtk.STOCK_GOTO_TOP, _('Push'), self.push_clicked, tip=_('Push local changes to selected ' 'repository')), self.toolbutton(gtk.STOCK_GOTO_LAST, _('Email'), self.email_clicked, tip=_('Email local outgoing changes to ' 'one or more recipients')), self.toolbutton(gtk.STOCK_UNDO, _('Shelve'), self.shelve_clicked, tip=_('Shelve uncommited changes')), gtk.SeparatorToolItem(), self.stop_button, gtk.SeparatorToolItem(), self.toolbutton(gtk.STOCK_PREFERENCES, _('Configure'), self.conf_clicked, tip=_('Configure peer repository paths')), gtk.SeparatorToolItem(), ] for btn in tbuttons: self.tbar.insert(btn, -1) # Base box self.basevbox = basevbox = gtk.VBox() self.add(basevbox) basevbox.pack_start(self.tbar, False, False, 2) # Sync Target Path targethbox = gtk.HBox() ## target selection buttons lbl = gtk.Button(_('Repo:')) lbl.unset_flags(gtk.CAN_FOCUS) lbl.connect('clicked', self.btn_remotepath_clicked) targethbox.pack_start(lbl, False, False) lbl = gtk.Button(_('Bundle:')) lbl.unset_flags(gtk.CAN_FOCUS) lbl.connect('clicked', self.btn_bundlepath_clicked) targethbox.pack_start(lbl, False, False) ## target path combobox self.pathlist = gtk.ListStore(str, str) self.pathbox = gtk.ComboBoxEntry(self.pathlist, 0) self.pathtext = self.pathbox.get_child() cell = gtk.CellRendererText() self.pathbox.pack_end(cell, False) self.pathbox.add_attribute(cell, 'text', 1) targethbox.pack_start(self.pathbox, True, True) self.fill_path_combo() defrow = None defpushrow = None for i, (path, alias) in enumerate(self.pathlist): if alias == 'default': defrow = i if defpushrow is None: defpushrow = i elif alias == 'default-push': defpushrow = i if repos: self.pathtext.set_text(hglib.toutf(repos[0])) elif defpushrow is not None and pushmode: self.pathbox.set_active(defpushrow) elif defrow is not None: self.pathbox.set_active(defrow) exs = [ name for name, module in extensions.extensions() ] # Post Pull Operation ppullhbox = gtk.HBox() self.ppulldata = [('none', _('Nothing')), ('update', _('Update'))] cfg = self.repo.ui.config('tortoisehg.postpull', 'none') if 'fetch' in exs or 'fetch' == cfg: self.ppulldata.append(('fetch', _('Fetch'))) if 'rebase' in exs or 'rebase' == cfg: self.ppulldata.append(('rebase', _('Rebase'))) self.ppullcombo = combo = gtk.combo_box_new_text() for (index, (name, label)) in enumerate(self.ppulldata): combo.insert_text(index, label) ppullhbox.pack_start(gtk.Label(_('Post Pull: ')), False, False, 2) ppullhbox.pack_start(self.ppullcombo, True, True) # Fixed options box (non-foldable) fixedhbox = gtk.HBox() fixedhbox.pack_start(targethbox, True, True, 2) fixedhbox.pack_start(ppullhbox, False, False, 2) # Advanced options (foldable) opthbox = gtk.HBox() self.expander = expander = gtk.Expander(_('Advanced Options')) expander.set_expanded(False) expander.connect_after('activate', self.expanded) expander.add(opthbox) ## checkbox options chkopthbox = gtk.HBox() self.force = gtk.CheckButton(_('Force pull or push')) self.tips.set_tip(self.force, _('Run even when remote repository is unrelated.')) self.newbranch = gtk.CheckButton(_('Push new branch')) self.tips.set_tip(self.newbranch, _('Allow pushing a new branch')) self.use_proxy = gtk.CheckButton(_('Use proxy server')) if ui.ui().config('http_proxy', 'host', ''): self.use_proxy.set_active(True) else: self.use_proxy.set_sensitive(False) chkopthbox.pack_start(self.force, False, False, 4) chkopthbox.pack_start(self.newbranch, False, False, 4) chkopthbox.pack_start(self.use_proxy, False, False, 4) ## target revision option revhbox = gtk.HBox() self.reventry = gtk.Entry() revhbox.pack_start(gtk.Label(_('Target revision:')), False, False, 2) revhbox.pack_start(self.reventry, True, True, 2) reveventbox = gtk.EventBox() reveventbox.add(revhbox) self.tips.set_tip(reveventbox, _('A specific revision up to which you ' 'would like to push or pull.')) ## remote command option cmdhbox = gtk.HBox() self.cmdentry = gtk.Entry() cmdhbox.pack_start(gtk.Label(_('Remote command:')), False, False, 2) cmdhbox.pack_start(self.cmdentry, True, True, 2) cmdeventbox = gtk.EventBox() cmdeventbox.add(cmdhbox) self.tips.set_tip(cmdeventbox, _('Name of hg executable on remote machine.')) revvbox = gtk.VBox() revvbox.pack_start(chkopthbox, False, False, 8) revvbox.pack_start(reveventbox, False, False, 4) revvbox.pack_start(cmdeventbox, False, False, 4) opthbox.pack_start(revvbox, True, True, 4) ## incoming/outgoing options frame = gtk.Frame(_('Incoming/Outgoing')) opthbox.pack_start(frame, False, False, 2) self.showpatch = gtk.CheckButton(_('Show patches')) self.newestfirst = gtk.CheckButton(_('Show newest first')) self.nomerge = gtk.CheckButton(_('Show no merges')) iovbox = gtk.VBox() iovbox.pack_start(self.showpatch, False, False, 2) iovbox.pack_start(self.newestfirst, False, False, 2) iovbox.pack_start(self.nomerge, False, False, 2) frame.add(iovbox) # Main option box topvbox = gtk.VBox() topvbox.pack_start(fixedhbox, True, True, 2) topvbox.pack_start(expander, False, False, 2) basevbox.pack_start(topvbox, False, False, 2) # hg output window scrolledwindow = gtk.ScrolledWindow() scrolledwindow.set_shadow_type(gtk.SHADOW_ETCHED_IN) scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.textview = gtk.TextView(buffer=None) self.textview.set_editable(False) fontlog = hglib.getfontconfig()['fontlog'] self.textview.modify_font(pango.FontDescription(fontlog)) scrolledwindow.add(self.textview) self.textview.connect('populate-popup', self.add_to_popup) self.textbuffer = self.textview.get_buffer() gtklib.configstyles(self.repo.ui) for tag, argdict in gtklib.TextBufferTags.iteritems(): self.textbuffer.create_tag(tag, **argdict) basevbox.pack_start(scrolledwindow, True, True) # statusbar self.stbar = statusbar.StatusBar() basevbox.pack_end(self.stbar, False, False, 2) # support dropping of repos or bundle files self.drag_dest_set(gtk.DEST_DEFAULT_ALL, [("text/uri-list", 0, 1)], gtk.gdk.ACTION_COPY) self.connect('drag_data_received', self._drag_receive) # prepare to show self.load_settings() self.update_pull_setting() gtklib.idle_add_single_call(self.finalize_startup)
def __init__(self, fileglob='', *pats): 'Initialize the Dialog' gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL) gtklib.set_tortoise_icon(self, 'ignore.ico') gtklib.set_tortoise_keys(self) self.set_default_size(630, 400) try: repo = hg.repository(ui.ui(), path=paths.find_root()) except error.RepoError: gtklib.idle_add_single_call(self.destroy) return self.repo = repo self.set_title(_('Ignore filter - %s') % hglib.get_reponame(repo)) self.notify_func = None # vbox for dialog main mainvbox = gtk.VBox() self.add(mainvbox) mainvbox.set_border_width(2) ## layout table for top table = gtklib.LayoutTable() mainvbox.pack_start(table, False, False) ### hbox for glob entry self.glob_entry = gtk.Entry() self.glob_entry.set_text(hglib.toutf(fileglob)) self.glob_entry.connect('activate', self.add_glob) glob_button = gtk.Button(_('Add')) glob_button.connect('clicked', self.add_glob) table.add_row(_('Glob:'), self.glob_entry, 0, glob_button, expand=0) ### hbox for regexp entry self.regexp_entry = gtk.Entry() self.regexp_entry.connect('activate', self.add_regexp) regexp_button = gtk.Button(_('Add')) regexp_button.connect('clicked', self.add_regexp) table.add_row(_('Regexp:'), self.regexp_entry, 0, regexp_button, expand=0) ignorefiles = [repo.wjoin('.hgignore')] for name, value in repo.ui.configitems('ui'): if name == 'ignore' or name.startswith('ignore.'): ignorefiles.append(os.path.expanduser(value)) ### ignore file combo if needs if len(ignorefiles) > 1: # file selector combo = gtk.combo_box_new_text() for f in ignorefiles: combo.append_text(hglib.toutf(f)) combo.set_active(0) combo.connect('changed', self.file_selected) # edit button edit = gtk.Button(_('Edit File')) edit.connect('clicked', self.edit_clicked) table.add_row(_('Apply to:'), combo, 0, edit, padding=False, expand=0) self.ignorefile = ignorefiles[0] ## hbox for filter & unknown list hbox = gtk.HBox() mainvbox.pack_start(hbox, True, True) ### frame for filter list & button frame = gtk.Frame(_('Filters')) hbox.pack_start(frame, True, True, 4) vbox = gtk.VBox() frame.add(vbox) vbox.set_border_width(2) #### filter list scrolledwindow = gtk.ScrolledWindow() vbox.pack_start(scrolledwindow, True, True, 2) scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scrolledwindow.set_border_width(4) pattree = gtk.TreeView() scrolledwindow.add(pattree) pattree.set_enable_search(False) pattree.set_reorderable(False) pattree.get_selection().set_mode(gtk.SELECTION_SINGLE) col = gtk.TreeViewColumn(_('Patterns'), gtk.CellRendererText(), text=0) pattree.append_column(col) pattree.set_headers_visible(False) self.pattree = pattree #### remove button bhbox = gtk.HBox() vbox.pack_start(bhbox, False, False, 2) self.removebtn = gtk.Button(_('Remove Selected')) bhbox.pack_start(self.removebtn, False, False, 2) self.removebtn.connect('clicked', self.remove_clicked) self.removebtn.set_sensitive(False) ### frame for unknown file list & button frame = gtk.Frame(_('Unknown Files')) hbox.pack_start(frame, True, True, 4) vbox = gtk.VBox() frame.add(vbox) vbox.set_border_width(2) #### unknown file list scrolledwindow = gtk.ScrolledWindow() vbox.pack_start(scrolledwindow, True, True, 2) scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scrolledwindow.set_border_width(4) unktree = gtk.TreeView() scrolledwindow.add(unktree) unktree.set_search_equal_func(self.unknown_search) col = gtk.TreeViewColumn(_('Files'), gtk.CellRendererText(), text=0) unktree.append_column(col) model = gtk.ListStore(str, str) unktree.set_model(model) unktree.set_headers_visible(False) self.unkmodel = model #### refresh button bhbox = gtk.HBox() vbox.pack_start(bhbox, False, False, 2) refresh = gtk.Button(_('Refresh')) bhbox.pack_start(refresh, False, False, 2) refresh.connect('pressed', lambda b: self.refresh()) self.connect('thg-refresh', lambda w: self.refresh()) # register signal handlers pattree.get_selection().connect('changed', self.pattree_rowchanged) unktree.get_selection().connect('changed', self.unknown_rowchanged) # prepare to show self.glob_entry.grab_focus() gtklib.idle_add_single_call(self.refresh)
def __init__(self, parentwin, repo, statusbar, accelgroup=None, tooltips=None): gtk.VBox.__init__(self) self.parent_window = parentwin self.repo = repo self.pbranch = extensions.find('pbranch') self.statusbar = statusbar # top toolbar tbar = gtklib.SlimToolbar(tooltips) ## buttons self.btn = {} pmergebtn = tbar.append_button(gtk.STOCK_CONVERT, _('Merge all pending dependencies')) pmergebtn.connect('clicked', self.pmerge_clicked) self.btn['pmerge'] = pmergebtn pbackoutbtn = tbar.append_button(gtk.STOCK_GO_BACK, _('Backout current patch branch')) pbackoutbtn.connect('clicked', self.pbackout_clicked) self.btn['pbackout'] = pbackoutbtn reapplybtn = gtk.ToolButton(gtk.STOCK_GO_FORWARD) reapplybtn = tbar.append_button(gtk.STOCK_GO_FORWARD, _('Backport part of a changeset to a dependency')) reapplybtn.connect('clicked', self.reapply_clicked) self.btn['reapply'] = reapplybtn pnewbtn = tbar.append_button(gtk.STOCK_NEW, _('Start a new patch branch')) pnewbtn.connect('clicked', self.pnew_clicked) self.btn['pnew'] = pnewbtn pgraphbtn = tbar.append_button(gtk.STOCK_EDIT, _('Edit patch dependency graph')) pgraphbtn.connect('clicked', self.edit_pgraph_clicked) self.btn['pnew'] = pnewbtn ## separator tbar.append_space() ## drop-down menu menubtn = gtk.MenuToolButton('') menubtn.set_menu(self.create_view_menu()) tbar.append_widget(menubtn, padding=0) self.btn['menu'] = menubtn def after_init(): menubtn.child.get_children()[0].hide() gtklib.idle_add_single_call(after_init) self.pack_start(tbar, False, False) # center pane mainbox = gtk.VBox() self.pack_start(mainbox, True, True) ## scrolled pane pane = gtk.ScrolledWindow() pane.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) pane.set_shadow_type(gtk.SHADOW_IN) mainbox.pack_start(pane) ### patch list #### patch list model self.model = gtk.ListStore( gobject.TYPE_PYOBJECT, # node info gobject.TYPE_PYOBJECT, # in-lines gobject.TYPE_PYOBJECT, # out-lines str, # patch name str, # patch status str, # patch title str, # patch message str) # patch message escaped #### patch list view self.list = gtk.TreeView(self.model) # To support old PyGTK (<2.12) if hasattr(self.list, 'set_tooltip_column'): self.list.set_tooltip_column(M_MSGESC) self.list.connect('cursor-changed', self.list_sel_changed) self.list.connect('button-press-event', self.list_pressed) self.list.connect('row-activated', self.list_row_activated) self.list.connect('size-allocate', self.list_size_allocated) #### patch list columns self.cols = {} self.cells = {} def addcol(header, col_idx, model_idx=None, right=False, resizable=False, editable=False, editfunc=None, cell_renderer=None, properties=[]): header = (right and '%s ' or ' %s') % header cell = cell_renderer or gtk.CellRendererText() if editfunc: cell.set_property('editable', editable) cell.connect('edited', editfunc) col = gtk.TreeViewColumn(header, cell) if cell_renderer is None: col.add_attribute(cell, 'text', model_idx) col.set_resizable(resizable) col.set_visible(self.get_property(self.col_to_prop(col_idx))) if right: col.set_alignment(1) cell.set_property('xalign', 1) for (property_name, model_index) in properties: col.add_attribute(cell, property_name, model_index) self.list.append_column(col) self.cols[col_idx] = col self.cells[col_idx] = cell def cell_edited(cell, path, newname): row = self.model[path] patchname = row[M_NAME] if newname != patchname: self.qrename(newname, patch=patchname) #### patch list columns and cell renderers addcol(_('Graph'), C_GRAPH, resizable=True, cell_renderer=graphcell.CellRendererGraph(), properties=[("node", M_NODE), ("in-lines",M_IN_LINES), ("out-lines", M_OUT_LINES)] ) addcol(_('St'), C_STATUS, M_STATUS) addcol(_('Name'), C_NAME, M_NAME, editfunc=cell_edited) addcol(_('Title'), C_TITLE, M_TITLE) addcol(_('Message'), C_MSG, M_MSG) pane.add(self.list) ## command widget self.cmd = hgcmd.CmdWidget(style=hgcmd.STYLE_COMPACT, tooltips=tooltips) mainbox.pack_start(self.cmd, False, False) # accelerator if accelgroup: # TODO pass
def __init__(self): """ Initialize the Dialog. """ gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL) gtklib.set_tortoise_icon(self, 'general.ico') gtklib.set_tortoise_keys(self) self.set_default_size(600, 400) self.connect('delete-event', self._delete) self.hgthread = None self.inprogress = False self.last_pbar_update = 0 try: repo = hg.repository(ui.ui(), path=paths.find_root()) except error.RepoError: gtklib.idle_add_single_call(self.destroy) return self.repo = repo self.reponame = hglib.get_reponame(repo) self.set_title(_('%s - recovery') % self.reponame) # toolbar self.tbar = gtk.Toolbar() self.tips = gtklib.Tooltips() self._stop_button = self._toolbutton(gtk.STOCK_STOP, _('Stop'), self._stop_clicked, tip=_('Stop the hg operation')) self._stop_button.set_sensitive(False) tbuttons = [ self._toolbutton(gtk.STOCK_CLEAR, _('Clean'), self._clean_clicked, tip=_('Clean checkout, undo all changes')), gtk.SeparatorToolItem(), self._toolbutton(gtk.STOCK_UNDO, _('Rollback'), self._rollback_clicked, tip=_('Rollback (undo) last transaction to ' 'repository (pull, commit, etc)')), gtk.SeparatorToolItem(), self._toolbutton(gtk.STOCK_CLEAR, _('Recover'), self._recover_clicked, tip=_('Recover from interrupted operation')), gtk.SeparatorToolItem(), self._toolbutton(gtk.STOCK_APPLY, _('Verify'), self._verify_clicked, tip=_('Validate repository consistency')), gtk.SeparatorToolItem(), self._stop_button, gtk.SeparatorToolItem(), ] for btn in tbuttons: self.tbar.insert(btn, -1) vbox = gtk.VBox() self.add(vbox) vbox.pack_start(self.tbar, False, False, 2) # hg output window scrolledwindow = gtk.ScrolledWindow() scrolledwindow.set_shadow_type(gtk.SHADOW_ETCHED_IN) scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.textview = gtk.TextView(buffer=None) self.textview.set_editable(False) fontlog = hglib.getfontconfig()['fontlog'] self.textview.modify_font(pango.FontDescription(fontlog)) scrolledwindow.add(self.textview) self.textbuffer = self.textview.get_buffer() gtklib.configstyles(repo.ui) for tag, argdict in gtklib.TextBufferTags.iteritems(): self.textbuffer.create_tag(tag, **argdict) vbox.pack_start(scrolledwindow, True, True) self.progstat = gtk.Label() vbox.pack_start(self.progstat, False, False, 0) self.progstat.set_alignment(0, 0.5) self.progstat.set_ellipsize(pango.ELLIPSIZE_END) self.pbar = gtk.ProgressBar() vbox.pack_start(self.pbar, False, False, 2)
def update(self): cmdline = ['hg', 'update', '--verbose'] rev = hglib.fromutf(self.revcombo.get_active_text()) cmdline.append('--rev') cmdline.append(rev) if self.opt_clean.get_active(): cmdline.append('--clean') else: cur = self.repo['.'] node = self.repo[rev] def isclean(): '''whether WD is changed''' wc = self.repo[None] return not (wc.modified() or wc.added() or wc.removed()) def ismergedchange(): '''whether the local changes are merged (have 2 parents)''' wc = self.repo[None] return len(wc.parents()) == 2 def iscrossbranch(p1, p2): '''whether p1 -> p2 crosses branch''' pa = p1.ancestor(p2) return p1.branch() != p2.branch() or (p1 != pa and p2 != pa) def islocalmerge(p1, p2, clean=None): if clean is None: clean = isclean() pa = p1.ancestor(p2) return not clean and (p1 == pa or p2 == pa) def confirmupdate(clean=None): if clean is None: clean = isclean() msg = _('Detected uncommitted local changes in working tree.\n' 'Please select to continue:\n\n') data = {'discard': (_('&Discard'), _('Discard - discard local changes, no backup')), 'shelve': (_('&Shelve'), _('Shelve - launch Shelve tool and continue')), 'merge': (_('&Merge'), _('Merge - allow to merge with local changes')), 'cancel': (_('&Cancel'), None)} opts = [data['discard']] if not ismergedchange(): opts.append(data['shelve']) if islocalmerge(cur, node, clean): opts.append(data['merge']) opts.append(data['cancel']) msg += '\n'.join([ desc for label, desc in opts if desc ]) buttons = [ label for label, desc in opts ] cancel = len(opts) - 1 retcode = gdialog.CustomPrompt(_('Confirm Update'), msg, self, buttons, default=cancel, esc=cancel).run() retlabel = buttons[retcode] retid = [ id for id, (label, desc) in data.items() \ if label == retlabel ][0] return dict([(id, id == retid) for id in data.keys()]) # If merge-by-default, we want to merge whenever possible, # without prompting user (similar to command-line behavior) defaultmerge = self.opt_merge.get_active() clean = isclean() if clean: cmdline.append('--check') elif not (defaultmerge and islocalmerge(cur, node, clean)): ret = confirmupdate(clean) if ret['discard']: cmdline.append('--clean') elif ret['shelve']: def launch_shelve(): from tortoisehg.hgtk import thgshelve dlg = thgshelve.run(ui.ui()) dlg.set_transient_for(self) dlg.set_modal(True) dlg.display() dlg.connect('destroy', lambda w: self.update()) gtklib.idle_add_single_call(launch_shelve) return # retry later, no need to destroy elif ret['merge']: pass # no args elif ret['cancel']: self.cmd.log.append(_('[canceled by user]\n'), error=True) self.do_switch_to(gdialog.MODE_WORKING) self.abort() return else: raise _('invalid dialog result: %s') % ret # start updating self.execute_command(cmdline)
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)