def annotate_wait(self, thread, q, model, curdate, colormap, frame): """ Handle all the messages currently in the queue (if any). """ while q.qsize(): line = q.get(0).rstrip('\r\n') try: (revpath, text) = line.split(':', 1) revid, path = revpath.lstrip().split(' ', 1) rowrev = long(revid) except ValueError: continue tip, user = self.get_rev_desc(rowrev) ctx = self.repo.changectx(rowrev) color = colormap.get_color(ctx, curdate) model.append((revid, toutf(text), tip, toutf(path.strip()), color, toutf(user))) if thread.isAlive(): return True else: if threading.activeCount() == 1: self.stop_button.set_sensitive(False) frame._mythread = None self.stbar.end() return False
def __init__(self, title, files, parent, primary=None): SimpleMessage.__init__(self, parent, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO) self.set_title(toutf("Confirm " + title)) if primary is None: primary = title + " file" + ((len(files) > 1 and "s") or "") + "?" primary = "<b>" + primary + "</b>" self.set_markup(toutf(primary)) message = "" for i, file in enumerate(files): message += " " + file + "\n" if i == 9: message += " ...\n" break self.format_secondary_text(toutf(message))
def prepare_diff(self, difflines, offset, fname): '''Borrowed from hgview; parses changeset diffs''' DIFFHDR = "=== %s ===\n" idx = 0 outlines = [] tags = [] filespos = [] def addtag( name, offset, length ): if tags and tags[-1][0] == name and tags[-1][2]==offset: tags[-1][2] += length else: tags.append( [name, offset, offset+length] ) stats = [0,0] statmax = 0 for i,l1 in enumerate(difflines): l = toutf(l1) if l.startswith("diff"): txt = toutf(DIFFHDR % fname) addtag( "greybg", offset, len(txt) ) outlines.append(txt) markname = "file%d" % idx idx += 1 statmax = max( statmax, stats[0]+stats[1] ) stats = [0,0] filespos.append(( markname, offset, stats )) offset += len(txt.decode('utf-8')) continue elif l.startswith("+++"): continue elif l.startswith("---"): continue elif l.startswith("+"): tag = "green" stats[0] += 1 elif l.startswith("-"): stats[1] += 1 tag = "red" elif l.startswith("@@"): tag = "blue" else: tag = "black" l = l+"\n" length = len(l.decode('utf-8')) addtag( tag, offset, length ) outlines.append( l ) offset += length statmax = max( statmax, stats[0]+stats[1] ) return filespos, tags, outlines, statmax
def dohgdiff(): difftext = StringIO.StringIO() try: if len(files) != 0: wfiles = [self.repo.wjoin(x) for x in files] fns, matchfn, anypats = cmdutil.matchpats(self.repo, wfiles, self.opts) patch.diff(self.repo, self._node1, self._node2, fns, match=matchfn, fp=difftext, opts=patch.diffopts(self.ui, self.opts)) buffer = gtk.TextBuffer() buffer.create_tag('removed', foreground='#900000') buffer.create_tag('added', foreground='#006400') buffer.create_tag('position', foreground='#FF8000') buffer.create_tag('header', foreground='#000090') difftext.seek(0) iter = buffer.get_start_iter() for line in difftext: line = toutf(line) if line.startswith('---') or line.startswith('+++'): buffer.insert_with_tags_by_name(iter, line, 'header') elif line.startswith('-'): buffer.insert_with_tags_by_name(iter, line, 'removed') elif line.startswith('+'): buffer.insert_with_tags_by_name(iter, line, 'added') elif line.startswith('@@'): buffer.insert_with_tags_by_name(iter, line, 'position') else: buffer.insert(iter, line) self.diff_text.set_buffer(buffer) finally: difftext.close()
def get_diffs(self, iterator, nodes, pctx, buf, filelist): if self.curnodes != nodes: return False try: status, file, txt = iterator.next() except StopIteration: self.stbar.end() return False lines = txt.splitlines() eob = buf.get_end_iter() offset = eob.get_offset() fileoffs, tags, lines, statmax = self.prepare_diff(lines, offset, file) for l in lines: buf.insert(eob, l) # inserts the tags for name, p0, p1 in tags: i0 = buf.get_iter_at_offset(p0) i1 = buf.get_iter_at_offset(p1) txt = buf.get_text(i0, i1) buf.apply_tag_by_name(name, i0, i1) # inserts the marks for mark, offset, stats in fileoffs: pos = buf.get_iter_at_offset(offset) mark = 'mark_%d' % offset buf.create_mark(mark, pos) filelist.append((status, toutf(file), mark, True, stats)) sob, eob = buf.get_bounds() buf.apply_tag_by_name("mono", pos, eob) return True
def _write(self, msg, append=True): msg = hglib.toutf(msg) if append: enditer = self.textbuffer.get_end_iter() self.textbuffer.insert(enditer, msg) else: self.textbuffer.set_text(msg)
def _do_reload_status(self): """Clear out the existing ListStore model and reload it from the repository status. Also recheck and reselect files that remain in the list. """ self.repo.dirstate.invalidate() self.repo.invalidate() # The following code was copied from the status function in mercurial\commands.py # and modified slightly to work here # node2 is None (the working dir) when 0 or 1 rev is specificed self._node1, self._node2 = cmdutil.revpair(self.repo, self.opts.get('rev')) files, matchfn, anypats = cmdutil.matchpats(self.repo, self.pats, self.opts) cwd = (self.pats and self.repo.getcwd()) or '' modified, added, removed, deleted, unknown, ignored, clean = [ n for n in self.repo.status(node1=self._node1, node2=self._node2, files=files, match=matchfn, list_ignored=self.test_opt('ignored'), list_clean=self.test_opt('clean'))] changetypes = (('modified', 'M', modified), ('added', 'A', added), ('removed', 'R', removed), ('deleted', '!', deleted), ('unknown', '?', unknown), ('ignored', 'I', ignored)) explicit_changetypes = changetypes + (('clean', 'C', clean),) # List of the currently checked and selected files to pass on to the new data recheck = [entry[2] for entry in self.model if entry[0]] reselect = [self.model[iter][2] for iter in self.tree.get_selection().get_selected_rows()[1]] # Load the new data into the tree's model self.tree.hide() self.model.clear() for opt, char, changes in ([ct for ct in explicit_changetypes if self.test_opt(ct[0])] or changetypes) : for file in changes: file = util.localpath(file) self.model.append([file in recheck, char, toutf(file), file]) self._update_check_count() selection = self.tree.get_selection() selected = False for row in self.model: if row[2] in reselect: selection.select_iter(row.iter) selected = True if not selected: selection.select_path((0,)) self.tree.show() self.tree.grab_focus() return True
def write(self, msg, append=True): msg = toutf(msg) if append: enditer = self.textbuffer.get_end_iter() self.textbuffer.insert(enditer, msg) self.textview.scroll_to_mark(self.textbuffer.get_insert(), 0) else: self.textbuffer.set_text(msg)
def _grep_selection_changed(self, treeview): """ Callback for when the user selects grep output. """ (path, focus) = treeview.get_cursor() model = treeview.get_model() if path is not None and model is not None: iter = model.get_iter(path) self.currev = model[iter][self.COL_REVID] self.curpath = fromutf(model[iter][self.COL_PATH]) self.stbar.set_status_text(toutf(model[iter][self.COL_TOOLTIP]))
def grep_wait(self, thread, q, model, search_hbox, regexp, frame): """ Handle all the messages currently in the queue (if any). """ while q.qsize(): line = q.get(0).rstrip('\r\n') try: (path, revid, text) = line.split(':', 2) except ValueError: continue tip, user = self.get_rev_desc(long(revid)) model.append((revid, toutf(text), tip, toutf(path))) if thread.isAlive(): return True else: if threading.activeCount() == 1: self.stop_button.set_sensitive(False) frame._mythread = None search_hbox.set_sensitive(True) regexp.grab_focus() self.stbar.end() return False
def trigger_annotate(self, rev, objs): ''' User has selected a file revision to annotate. Trigger a background thread to perform the annotation. Disable the select button until this operation is complete. ''' (frame, model, path) = objs q = Queue.Queue() args = [self.repo.root, q, 'annotate', '--follow', '--number', '--rev', str(rev), path] thread = threading.Thread(target=hgcmd_toq, args=args) thread.start() frame._mythread = thread self.stop_button.set_sensitive(True) # date of selected revision ctx = self.repo.changectx(long(rev)) curdate = ctx.date()[0] # date of initial revision fctx = self.repo.filectx(path, fileid=0) basedate = fctx.date()[0] agedays = (curdate - basedate) / (24 * 60 * 60) colormap = AnnotateColorSaturation(agedays) model.clear() self.stbar.begin() self.stbar.set_status_text(toutf('hg ' + ' '.join(args[2:]))) hbox = gtk.HBox() lbl = gtk.Label(toutf(os.path.basename(path) + '@' + str(rev))) 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() self.notebook.set_tab_label(frame, hbox) gobject.timeout_add(50, self.annotate_wait, thread, q, model, curdate, colormap, frame)
def log_selection_changed(self, graphview, path, label, button): row = graphview.get_revision() rev = row[treemodel.REVID] self.currev = str(rev) ctx = self.repo.changectx(rev) filectx = ctx.filectx(path) info = filectx.renamed() if info: (rpath, node) = info frev = self.repo.file(rpath).linkrev(node) button.set_label(toutf('%s@%s' % (rpath, frev))) button.show() button.set_sensitive(True) label.set_text('Follow Rename:') else: button.hide() button.set_sensitive(False) label.set_text('')
def process_queue(self): """ Handle all the messages currently in the queue (if any). """ self.hgthread.process_dialogs() enditer = self.textbuffer.get_end_iter() while self.hgthread.getqueue().qsize(): try: msg = self.hgthread.getqueue().get(0) self.textbuffer.insert(enditer, toutf(msg)) self.textview.scroll_to_mark(self.textbuffer.get_insert(), 0) except Queue.Empty: pass self.update_progress() if not self.hgthread.isAlive(): self._button_ok.set_sensitive(True) self._button_stop.set_sensitive(False) self.returncode = self.hgthread.return_code() if self.returncode is None: self.write("\n[command interrupted]") return False # Stop polling this function else: return True
def _fill_buffer(self, buf, rev, ctx, filelist): self.stbar.begin('Retrieving changeset data...') def title_line(title, text, tag): pad = ' ' * (12 - len(title)) utext = toutf(title + pad + text) buf.insert_with_tags_by_name(eob, utext, tag) buf.insert(eob, "\n") # TODO: Add toggle for gmtime/localtime eob = buf.get_end_iter() date = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(ctx.date()[0])) if self.clipboard: self.clipboard.set_text(short(ctx.node())) change = str(rev) + ':' + short(ctx.node()) tags = ' '.join(ctx.tags()) parents = self.parents title_line('changeset:', change, 'changeset') if ctx.branch() != 'default': title_line('branch:', ctx.branch(), 'greybg') title_line('user/date:', ctx.user() + '\t' + date, 'changeset') for p in parents: pctx = self.repo.changectx(p) summary = pctx.description().splitlines()[0] summary = toutf(summary) change = str(p) + ':' + short(self.repo.changelog.node(p)) title = 'parent:' title += ' ' * (12 - len(title)) buf.insert_with_tags_by_name(eob, title, 'parent') buf.insert_with_tags_by_name(eob, change, 'link') buf.insert_with_tags_by_name(eob, ' ' + summary, 'parent') buf.insert(eob, "\n") for n in self.repo.changelog.children(ctx.node()): cctx = self.repo.changectx(n) summary = cctx.description().splitlines()[0] summary = toutf(summary) childrev = self.repo.changelog.rev(n) change = str(childrev) + ':' + short(n) title = 'child:' title += ' ' * (12 - len(title)) buf.insert_with_tags_by_name(eob, title, 'parent') buf.insert_with_tags_by_name(eob, change, 'link') buf.insert_with_tags_by_name(eob, ' ' + summary, 'parent') buf.insert(eob, "\n") for n in self.repo.changelog.children(ctx.node()): childrev = self.repo.changelog.rev(n) if tags: title_line('tags:', tags, 'tag') log = toutf(ctx.description()) buf.insert(eob, '\n' + log + '\n\n') if self.parent_toggle.get_active(): parent = self.repo.changelog.node(parents[1]) elif parents: parent = self.repo.changelog.node(parents[0]) else: parent = nullid buf.create_mark('begmark', buf.get_start_iter()) filelist.append(('*', '[Description]', 'begmark', False, ())) pctx = self.repo.changectx(parent) nodes = parent, ctx.node() iterator = self.diff_generator(*nodes) gobject.idle_add(self.get_diffs, iterator, nodes, pctx, buf, filelist) self.curnodes = nodes
def title_line(title, text, tag): pad = ' ' * (12 - len(title)) utext = toutf(title + pad + text) buf.insert_with_tags_by_name(eob, utext, tag) buf.insert(eob, "\n")
def __init__(self, title, message, parent): SimpleMessage.__init__(self, parent, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE) self.set_title(toutf(title)) self.set_markup("<b>" + toutf(message) + "</b>")
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.workingctx().parents()[0] try: fctx = ctx.filectx(path) except revlog.LookupError: Prompt('File is unrevisioned', 'Unable to annotate ' + path, self).run() return rev = fctx.filelog().linkrev(fctx.filenode()) revid = str(rev) else: rev = long(revid) frame = gtk.Frame() frame.set_border_width(10) vbox = gtk.VBox() # File log revision graph graphview = TreeView(self.repo, 5000, self.stbar) graphview.connect('revisions-loaded', self.revisions_loaded, rev) graphview.refresh(True, None, {'filehist':path, 'filerev':rev}) graphview.set_property('rev-column-visible', True) graphview.set_property('date-column-visible', True) hbox = gtk.HBox() followlabel = gtk.Label('') follow = gtk.Button('Follow') follow.connect('clicked', self.follow_rename) follow.hide() follow.set_sensitive(False) hbox.pack_start(gtk.Label(''), True, True) hbox.pack_start(followlabel, False, False) hbox.pack_start(follow, False, False) # 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) treeview.connect("cursor-changed", self._ann_selection_changed) treeview.connect('button-release-event', self._ann_button_release) treeview.connect('popup-menu', self._ann_popup_menu) treeview.connect('row-activated', self._ann_row_act) results = gtk.ListStore(str, str, str, str, str, str) treeview.set_model(results) context_menu = self.ann_header_context_menu(treeview) for title, width, col, emode, visible in ( ('Rev', 10, self.COL_REVID, pango.ELLIPSIZE_NONE, True), ('File', 15, self.COL_PATH, pango.ELLIPSIZE_START, False), ('User', 15, self.COL_USER, pango.ELLIPSIZE_END, False), ('Matches', 80, self.COL_TEXT, 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", self.COL_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(self.COL_TOOLTIP) 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) vbox.pack_start(hbox, False, False) frame.add(vbox) frame.show_all() hbox = gtk.HBox() lbl = gtk.Label(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(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, followlabel, follow) objs = (frame, treeview.get_model(), path) graphview.treeview.connect('row-activated', self.log_activate, objs) graphview.treeview.connect('button-release-event', self._ann_button_release) graphview.treeview.connect('popup-menu', self._ann_popup_menu)
def __init__(self, cmdline, progressbar=True, width=520, height=400): title = 'hg ' + ' '.join(cmdline[1:]) gtk.Dialog.__init__(self, title=title, flags=gtk.DIALOG_MODAL, #buttons=(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT) ) set_tortoise_icon(self, 'hg.ico') self.cmdline = cmdline self.returncode = None # construct dialog self.set_default_size(width, height) self._button_stop = gtk.Button("Stop") self._button_stop.connect('clicked', self._on_stop_clicked) self.action_area.pack_start(self._button_stop) self._button_ok = gtk.Button("Close") self._button_ok.connect('clicked', self._on_ok_clicked) self.action_area.pack_start(self._button_ok) self.connect('delete-event', self._delete) self.connect('response', self._response) self.pbar = None if progressbar: self.last_pbar_update = 0 hbox = gtk.HBox() self.status_text = gtk.Label() self.status_text.set_text(toutf(" ".join(cmdline).replace("\n", " "))) self.status_text.set_alignment(0, 0.5) self.status_text.set_ellipsize(pango.ELLIPSIZE_END) hbox.pack_start(self.status_text, True, True, 3) # Create a centering alignment object align = gtk.Alignment(0.0, 0.0, 1, 0) hbox.pack_end(align, False, False, 3) align.show() # create the progress bar self.pbar = gtk.ProgressBar() align.add(self.pbar) self.pbar.pulse() self.pbar.show() self.vbox.pack_start(hbox, False, False, 3) 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) self.textview.modify_font(pango.FontDescription("Monospace")) scrolledwindow.add(self.textview) self.textbuffer = self.textview.get_buffer() self.vbox.pack_start(scrolledwindow, True, True) self.connect('map_event', self._on_window_map_event) self.show_all()