by
Changes to 18 files · Browse files at 6d1f7432424c Showing diff from parent b2245f94a8fd 0fe7f965f9e3 Diff from another changeset...
@@ -50,6 +50,9 @@ Launch the web server dialog in a separate process
:guilabel:`Shelve`
Launch the shelve tool in a separate process
+ :guilabel:`Patch Branch`
+ Toggles the display of the Patch Branch pane. This button is only
+ visible when the pbranch extension has been enabled by the user.
:guilabel:`Load more`
Load the next N revisions into the graph
:guilabel:`Load all`
|
@@ -230,3 +230,44 @@ remote_repository_url combination).
.. vim: noet ts=4
+
+pbranch
+=======
+
+Patch Branches (`pbranch <http://mercurial.selenic.com/wiki/PatchBranchExtension>`_)
+is a way to develop a series of patches for submission into a main
+repo. It is based on topic branches, one per patch, and is thus highly
+suitable for collaborative and/or long-term patch development and
+maintenance.
+
+'A detailed manual <http://arrenbrecht.ch/mercurial/pbranch/>'_ can be found online.
+
+It adds a number of commands which can be listed with
+:command:`hg help pbranch`::
+
+ pbackout - backs out the current patch branch (undoes all its changes)
+ pdiff - prints the final diff for the current or given patch branch
+ peditmessage - edit the patch message
+ pemail - send patches by email
+ pexport - exports patches
+ pextdiff - combines pdiff and extdiff
+ pgraph - print an ASCII art rendering of the patch dependency graph
+ pmerge - merge pending heads from dependencies into patch branches
+ pmessage - print the patch message(s)
+ pnew - start a new patch branch
+ pstatus - print status of current (or given) patch branch
+ reapply - reverts the working copy of all files touched by REV to REV
+
+**Installation**
+
+To test the use of this plugin, you can specify it on the Mercurial
+command line like this::
+
+ hg --config "extensions.pbranch=" pstatus
+
+You may want to add it to your Mercurial.ini or a repository's hgrc like this::
+
+ [extensions]
+ pbranch=
+
+If you do this, you can omit the --config command-line option.
|
|
@@ -194,6 +194,16 @@
def load_patch_details(self, patchfile):
'Load specified patch details into buffer and file list'
+ pf = open(patchfile)
+ self.load_patch_details_from_file_object(pf, patchfile)
+
+ def load_patch_details_from_file_object(self, pf, patchfile, isTemp=False):
+ """ Load patch details into buffer and file list
+ :param pf: open file object
+ :param patchfile: path and name of patch file
+ :param isTemp: if True, then pf is a temporary file
+ and patchfile does not exist
+ """
self._filelist.clear()
self._filelist.append(('*', _('[All Files]'), ''))
@@ -201,7 +211,11 @@ self.currev = -1
self.curphunks = {}
self.curpatch = patchfile
- pf = open(self.curpatch)
+ if isTemp:
+ # pf is a temporary, so update panel cache while we can
+ patch_ctx = csinfo.patchctx(patchfile, self.repo, patchHandle=pf)
+ self.summarypanel.update(patch_ctx, self.patchstyle)
+ pf.seek(0)
def get_path(a, b):
type = (a == '/dev/null') and 'A' or 'M'
type = (b == '/dev/null') and 'R' or type
@@ -343,7 +357,6 @@ tags, lines = self.prepare_diff(lines, offset, wfile)
for l in lines:
buf.insert(eob, l)
-
# inserts the tags
for name, p0, p1 in tags:
i0 = buf.get_iter_at_offset(p0)
@@ -422,7 +435,7 @@ tag = 'red'
l = hglib.diffexpand(l)
else:
- tag = 'black'
+ tag = 'normal'
l = hglib.diffexpand(l)
l = l+"\n"
length = len(l.decode('utf-8'))
@@ -578,7 +591,7 @@ def widget_func(widget, item, markups):
def linkwidget(revnum, revid, summary, highlight=None, branch=None):
# revision label
- opts = dict(underline='single', color='blue')
+ opts = dict(underline='single', color=gtklib.BLUE)
if highlight:
opts['weight'] = 'bold'
rev = '%s (%s)' % (gtklib.markup(revnum, **opts),
@@ -590,7 +603,7 @@ # summary & branch label
sum = gtklib.markup(summary)
if branch:
- sum = gtklib.markup(branch, color='black',
+ sum = gtklib.markup(branch, color=gtklib.NORMAL,
background=gtklib.PGREEN) + ' ' + sum
sumlabel = gtk.Label()
sumlabel.set_markup(sum)
@@ -793,7 +806,7 @@ tag_table = self._buffer.get_tag_table()
tag_table.add(make_texttag('diff', font=self.rawfonts['fontdiff']))
- tag_table.add(make_texttag('blue', foreground='blue'))
+ tag_table.add(make_texttag('blue', foreground=gtklib.BLUE))
if self.colorstyle == 'background':
tag_table.add(make_texttag('red',
paragraph_background=gtklib.PRED))
@@ -805,21 +818,21 @@ else:
tag_table.add(make_texttag('red', foreground=gtklib.DRED))
tag_table.add(make_texttag('green', foreground=gtklib.DGREEN))
- tag_table.add(make_texttag('black', foreground='black'))
+ tag_table.add(make_texttag('normal', foreground=gtklib.NORMAL))
tag_table.add(make_texttag('greybg',
- paragraph_background='grey',
+ paragraph_background=gtklib.CHANGE_HEADER,
weight=pango.WEIGHT_BOLD))
- tag_table.add(make_texttag('yellowbg', background='yellow'))
+ tag_table.add(make_texttag('yellowbg', background=gtklib.YELLOW))
- issuelink_tag = make_texttag('issuelink', foreground='blue',
+ issuelink_tag = make_texttag('issuelink', foreground=gtklib.BLUE,
underline=pango.UNDERLINE_SINGLE)
issuelink_tag.connect('event', self.issuelink_event)
tag_table.add(issuelink_tag)
- urllink_tag = make_texttag('urllink', foreground='blue',
+ urllink_tag = make_texttag('urllink', foreground=gtklib.BLUE,
underline=pango.UNDERLINE_SINGLE)
urllink_tag.connect('event', self.urllink_event)
tag_table.add(urllink_tag)
- csetlink_tag = make_texttag('csetlink', foreground='blue',
+ csetlink_tag = make_texttag('csetlink', foreground=gtklib.BLUE,
underline=pango.UNDERLINE_SINGLE)
csetlink_tag.connect('event', self.csetlink_event)
tag_table.add(csetlink_tag)
|
@@ -1084,9 +1084,8 @@ # bring up the config dialog for user to enter their username.
# But since we can't be sure they will do it right, we will
# have them to retry, to re-trigger the checking mechanism.
- dlg = thgconfig.ConfigDialog(False)
+ dlg = thgconfig.ConfigDialog(False, focus='ui.username')
dlg.show_all()
- dlg.focus_field('ui.username')
dlg.run()
dlg.hide()
self.refreshui()
@@ -1299,9 +1298,8 @@ buf.set_text('\n'.join(lines))
def msg_config(self, sender):
- dlg = thgconfig.ConfigDialog(True)
+ dlg = thgconfig.ConfigDialog(True, focus='tortoisehg.summarylen')
dlg.show_all()
- dlg.focus_field('tortoisehg.summarylen')
dlg.run()
dlg.hide()
self.refreshui()
|
@@ -136,18 +136,31 @@
class patchctx(object):
- def __init__(self, patchpath, repo):
+ def __init__(self, patchpath, repo, patchHandle=None):
+ """ Read patch context from file
+ :param patchHandle: If set, then the patch is a temporary.
+ The provided handle is used to read the patch and
+ the patchpath contains the name of the patch.
+ The handle is NOT closed.
+ """
self._path = patchpath
self._patchname = os.path.basename(patchpath)
self._repo = repo
- pf = open(patchpath)
+ if patchHandle:
+ pf = patchHandle
+ pf_start_pos = pf.tell()
+ else:
+ pf = open(patchpath)
try:
data = patch.extract(self._repo.ui, pf)
tmpfile, msg, user, date, branch, node, p1, p2 = data
if tmpfile:
os.unlink(tmpfile)
finally:
- pf.close()
+ if patchHandle:
+ pf.seek(pf_start_pos)
+ else:
+ pf.close()
if not msg and hasattr(repo, 'mq'):
# attempt to get commit message
from hgext import mq
@@ -350,10 +363,10 @@ elif item in ('revnum', 'p4', 'svn'):
return str(value)
elif item in ('rawbranch', 'branch'):
- return gtklib.markup(' %s ' % value, color='black',
+ return gtklib.markup(' %s ' % value, color=gtklib.BLACK,
background=gtklib.PGREEN)
elif item in ('rawtags', 'tags'):
- opts = dict(color='black', background=gtklib.PYELLOW)
+ opts = dict(color=gtklib.BLACK, background=gtklib.PYELLOW)
tags = [gtklib.markup(' %s ' % tag, **opts) for tag in value]
return ' '.join(tags)
elif item in ('desc', 'summary', 'user', 'shortuser',
@@ -470,6 +483,13 @@ return self.info.get_widget(item, self, self.ctx, self.custom, **kargs)
def update(self, target=None, custom=None, repo=None):
+ self.ctx = None
+ if type(target) == patchctx:
+ # If a patchctx is specified as target, use it instead
+ # of creating a context from revision or patch file
+ self.ctx = target
+ target = None
+ self.target = None
if target is None:
target = self.target
if target is not None:
@@ -481,7 +501,8 @@ repo = self.repo
if repo is not None:
self.repo = repo
- self.ctx = create_context(repo, target)
+ if self.ctx is None:
+ self.ctx = create_context(repo, target)
if self.ctx is None:
return False # cannot update
return True
|
@@ -677,9 +677,8 @@ if os.path.basename(editor) in ('vi', 'vim', 'hgeditor'):
Prompt(_('No visual editor configured'),
_('Please configure a visual editor.'), self).run()
- dlg = thgconfig.ConfigDialog(False)
+ dlg = thgconfig.ConfigDialog(False, focus='tortoisehg.editor')
dlg.show_all()
- dlg.focus_field('tortoisehg.editor')
dlg.run()
dlg.hide()
self.ui = ui.ui()
|
|
@@ -37,6 +37,9 @@ DRED = '#900000'
DGREEN = '#006400'
DBLUE = '#000090'
+DYELLOW = '#6A6A00'
+DORANGE = '#AA5000'
+# DORANGE = '#FF8000'
PRED = '#ffcccc'
PGREEN = '#aaffaa'
@@ -44,6 +47,102 @@PYELLOW = '#ffffaa'
PORANGE = '#ffddaa'
+RED = 'red'
+GREEN = 'green'
+BLUE = 'blue'
+YELLOW = 'yellow'
+BLACK = 'black'
+WHITE = 'white'
+GREY = 'grey'
+
+NORMAL = BLACK
+NEW_REV_COLOR = DGREEN
+CHANGE_HEADER = GREY
+
+UP_ARROW_COLOR = '#feaf3e'
+DOWN_ARROW_COLOR = '#8ae234'
+STAR_COLOR = '#fce94f'
+CELL_GREY = '#2e3436'
+STATUS_HEADER = '#DDDDDD'
+STATUS_REJECT_BACKGROUND = '#EEEEEE'
+STATUS_REJECT_FOREGROUND = '#888888'
+
+# line colors
+MAINLINE_COLOR = ( 0.0, 0.0, 0.0 )
+LINE_COLORS = [
+ ( 1.0, 0.0, 0.0 ),
+ ( 1.0, 1.0, 0.0 ),
+ ( 0.0, 1.0, 0.0 ),
+ ( 0.0, 1.0, 1.0 ),
+ ( 0.0, 0.0, 1.0 ),
+ ( 1.0, 0.0, 1.0 ),
+ ]
+
+def get_gtk_colors():
+ color_scheme = gtk.settings_get_default().get_property('gtk-color-scheme')
+ colors = {}
+ for color in color_scheme.split('\n'):
+ color = color.strip()
+ if color:
+ name, color = color.split(':')
+ colors[name.strip()] = gtk.gdk.color_parse(color.strip())
+ return colors
+
+def _init_colors():
+ global NORMAL, MAINLINE_COLOR
+
+ gtk_colors = get_gtk_colors()
+
+ try:
+ normal = gtk_colors['fg_color']
+ except KeyError:
+ # TODO: find out how to log such errors
+ pass
+ else:
+ NORMAL = str(normal)
+ MAINLINE_COLOR = (
+ normal.red_float,
+ normal.green_float,
+ normal.blue_float
+ )
+
+ # adjust colors for a dark color scheme:
+ if normal.value > 0.5:
+ global RED, GREEN, BLUE, BLACK, WHITE, \
+ DRED, DGREEN, DBLUE, DYELLOW, DORANGE, \
+ PRED, PGREEN, PBLUE, PYELLOW, PORANGE, \
+ NEW_REV_COLOR, LINE_COLORS, CHANGE_HEADER
+
+ RED = PRED
+ GREEN = NEW_REV_COLOR = PGREEN
+ BLUE = PBLUE
+ PRED = DRED
+ DRED = '#FF6161'
+# DRED, PRED = PRED, DRED
+ DGREEN, PGREEN = PGREEN, DGREEN
+ DBLUE, PBLUE = PBLUE, DBLUE
+ DYELLOW, PYELLOW = PYELLOW, DYELLOW
+ DORANGE, PORANGE = PORANGE, DORANGE
+ BLACK, WHITE = WHITE, BLACK
+
+ CHANGE_HEADER = '#404040'
+
+ LINE_COLORS = [
+ ( 1.0, 0.3804, 0.3804 ),
+ ( 1.0, 1.0, 0.0 ),
+ ( 0.0, 1.0, 0.0 ),
+ ( 0.0, 1.0, 1.0 ),
+ ( 0.2902, 0.4863, 0.851 ),
+ ( 1.0, 0.3882, 1.0 ),
+ ]
+
+ # TODO: dark color scheme for:
+ # UP_ARROW_COLOR, DOWN_ARROW_COLOR, STAR_COLOR,
+ # CELL_GREY, STATUS_HEADER, STATUS_REJECT_BACKGROUND,
+ # STATUS_REJECT_FOREGROUND
+
+_init_colors()
+
def set_tortoise_icon(window, thgicon):
ico = paths.get_tortoise_icon(thgicon)
if ico: window.set_icon_from_file(ico)
|
@@ -196,7 +196,7 @@ 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='#FF8000')
+ self.buf.create_tag('position', foreground=gtklib.DORANGE)
self.buf.create_tag('header', foreground=gtklib.DBLUE)
diffview = gtk.TextView(self.buf)
scroller.add(diffview)
|
@@ -406,7 +406,7 @@ markup = markup % (gtklib.DRED, 'bold')
icons = {'error': True}
else:
- markup = markup % ('black', 'normal')
+ markup = markup % (gtklib.NORMAL, 'normal')
icons = {}
text = gtklib.markup_escape_text(text)
self.rlabel.set_markup(markup % text)
|
@@ -235,9 +235,8 @@ self._flaglist.append(['STABLE'])
def _on_conf_clicked(self, button):
- dlg = thgconfig.ConfigDialog(False)
+ dlg = thgconfig.ConfigDialog(False, focus='email.from')
dlg.show_all()
- dlg.focus_field('email.from')
dlg.run()
dlg.hide()
self._refresh(False)
@@ -281,9 +280,8 @@ if not self.repo.ui.config('smtp', 'host'):
dialog.info_dialog(self, _('Info required'),
_('You must configure SMTP'))
- dlg = thgconfig.ConfigDialog(False)
+ dlg = thgconfig.ConfigDialog(False, focus='smtp.host')
dlg.show_all()
- dlg.focus_field('smtp.host')
dlg.run()
dlg.hide()
self._refresh(False)
|
|
|
@@ -28,6 +28,7 @@ from tortoisehg.hgtk import backout, status, hgemail, tagadd, update, merge
from tortoisehg.hgtk import archive, changeset, thgconfig, thgmq, histdetails
from tortoisehg.hgtk import statusbar, bookmark, thgimport
+from tortoisehg.hgtk import thgpbranch
MODE_REVRANGE = 0
MODE_FILEPATS = 1
@@ -215,7 +216,17 @@ tip=_('Show/Hide Patch Queue'),
toggle=True,
icon='menupatch.ico')
- tbar += [gtk.SeparatorToolItem(), self.mqtb]
+ tbar += [self.mqtb]
+ if 'pbranch' in self.exs:
+ self.pbranchtb = self.make_toolbutton(gtk.STOCK_DIRECTORY,
+ _('Patch Branch'),
+ self.pbranch_clicked, name='pbranch',
+ tip=_('Show/Hide Patch Branch'),
+ toggle=True,
+ icon='menupatch.ico')
+ tbar += [self.pbranchtb]
+ if 'mq' in self.exs or 'pbranch' in self.exs:
+ tbar += [gtk.SeparatorToolItem()]
sep = gtk.SeparatorToolItem()
sep.set_expand(True)
sep.set_draw(False)
@@ -322,6 +333,12 @@ else:
p4menu = []
+ if 'pbranch' in self.exs:
+ pbranch_item = [dict(text=_('Patch Branch'), name='pbranch', ascheck=True,
+ func=self.pbranch_clicked, check=self.setting_pbranchvis) ]
+ else:
+ pbranch_item = []
+
return [
dict(text=_('_View'), subitems=[
dict(text=_('Load more Revisions'), name='load-more',
@@ -334,7 +351,7 @@ ] + sync_bar_item + [
dict(text=_('Filter Bar'), ascheck=True,
func=self.toggle_show_filterbar, check=self.show_filterbar),
- ] + mq_item + [
+ ] + mq_item + pbranch_item + [
dict(text='----'),
dict(text=_('Refresh'), func=refresh, args=[False],
icon=gtk.STOCK_REFRESH),
@@ -826,7 +843,24 @@ else:
self.goto_rev(revid)
- def repo_invalidated(self, mqwidget):
+ def pbranch_selected(self, pbranchwidget, revid, patchname):
+ 'if revid < 0 then the patch is listed in .hg/pgraph but not in repo'
+ self.stbar.set_text('')
+ pf = tempfile.TemporaryFile()
+ try:
+ try:
+ pf.writelines(pbranchwidget.pdiff(patchname))
+ except (util.Abort, error.RepoError), e:
+ self.stbar.set_text(str(e))
+ return
+ self.currevid = self.lastrevid = None
+ pf.seek(0)
+ self.changeview.load_patch_details_from_file_object(pf, patchname, isTemp=True)
+ finally:
+ pf.close()
+
+ def repo_invalidated(self, widget):
+ 'Emitted from MQWidget and PBranchWidget'
self.reload_log()
def files_dropped(self, mqwidget, files, *args):
@@ -900,8 +934,9 @@ else:
item.set_sensitive(False)
- # enable MQ panel
+ # enable panels
self.enable_mqpanel()
+ self.enable_pbranchpanel()
def get_proxy_args(self):
item = self.get_menuitem('use-proxy-server')
@@ -933,6 +968,13 @@ else:
settings['glog-mqpane'] = self.setting_mqhpos
settings['glog-mqvis'] = self.setting_mqvis
+ if hasattr(self, 'pbranchpaned') and self.pbranchwidget.has_patch():
+ curpos = self.pbranchpaned.get_position()
+ settings['glog-pbranchpane'] = curpos or self.setting_pbranchhpos
+ settings['glog-pbranchvis'] = bool(curpos)
+ else:
+ settings['glog-pbranchpane'] = self.setting_pbranchhpos
+ settings['glog-pbranchvis'] = self.setting_pbranchvis
settings['branch-color'] = self.graphview.get_property('branch-color')
settings['show-output'] = self.showoutput
settings['show-toolbar'] = self.show_toolbar
@@ -954,6 +996,8 @@ self.setting_hpos = settings.get('glog-hpane', -1)
self.setting_mqhpos = settings.get('glog-mqpane', 140) or 140
self.setting_mqvis = settings.get('glog-mqvis', False)
+ self.setting_pbranchhpos = settings.get('glog-pbranchpane', 140) or 140
+ self.setting_pbranchvis = settings.get('glog-pbranchvis', False)
self.branch_color = settings.get('branch-color', False)
self.showoutput = settings.get('show-output', False)
self.show_toolbar = settings.get('show-toolbar', True)
@@ -993,6 +1037,10 @@ if hasattr(self, 'mqwidget'):
self.mqwidget.refresh()
+ # refresh pbranch widget if exists
+ if hasattr(self, 'pbranchwidget'):
+ self.pbranchwidget.refresh()
+
# force a redraw of the visible rows
self.graphview.hide()
self.graphview.show()
@@ -1127,6 +1175,10 @@ 'count': ncount, 'total': ntotal}
self.stbar.set_text(mq_text, name='mq')
+ # refresh pbranch widget if exists
+ if hasattr(self, 'pbranchwidget'):
+ self.pbranchwidget.refresh()
+
# Remember options to next time reload_log is called
self.filteropts = opts
@@ -1316,6 +1368,7 @@ # prepare statusbar
self.stbar = statusbar.StatusBar()
self.stbar.append_field('mq')
+ self.stbar.append_field('pbranch')
self.stbar.append_field('filter')
self.stbar.append_field('rev')
@@ -1527,6 +1580,25 @@ midpane.pack_start(self.graphview)
midpane.show_all()
+ # pbranch widget
+ if 'pbranch' in self.exs:
+ # create PBranchWidget
+ self.pbranchwidget = thgpbranch.PBranchWidget(
+ self, self.repo, self.stbar, accelgroup, self.tooltips)
+ self.pbranchwidget.connect('patch-selected', self.pbranch_selected)
+ self.pbranchwidget.connect('repo-invalidated', self.repo_invalidated)
+
+ def wrapframe(widget):
+ frame = gtk.Frame()
+ frame.set_shadow_type(gtk.SHADOW_ETCHED_IN)
+ frame.add(widget)
+ return frame
+ self.pbranchpaned = gtk.HPaned()
+ self.pbranchpaned.add1(wrapframe(self.pbranchwidget))
+ self.pbranchpaned.add2(wrapframe(midpane))
+
+ midpane = self.pbranchpaned
+
# MQ widget
if 'mq' in self.exs:
# create MQWidget
@@ -2059,6 +2131,8 @@ self.hpaned.set_position(self.setting_hpos)
if hasattr(self, 'mqpaned') and self.mqtb.get_active():
self.mqpaned.set_position(self.setting_mqhpos)
+ if hasattr(self, 'pbranchpaned') and self.pbranchtb.get_active():
+ self.pbranchpaned.set_position(self.setting_pbranchhpos)
def thgdiff(self, treeview):
'ctrl-d handler'
@@ -2647,6 +2721,26 @@ def mq_clicked(self, widget, *args):
self.enable_mqpanel(widget.get_active())
+ def enable_pbranchpanel(self, enable=None):
+ if not hasattr(self, 'pbranchpaned'):
+ return
+ if enable is None:
+ enable = self.setting_pbranchvis and self.pbranchwidget.has_patch()
+ oldpos = self.pbranchpaned.get_position()
+ self.pbranchpaned.set_position(enable and self.setting_pbranchhpos or 0)
+ if not enable and oldpos:
+ self.setting_pbranchhpos = oldpos
+
+ # set the state of PBranch toolbutton
+ if hasattr(self, 'pbranchtb'):
+ self.pbranchtb.handler_block_by_func(self.pbranch_clicked)
+ self.cmd_set_active('pbranch', enable)
+ self.pbranchtb.handler_unblock_by_func(self.pbranch_clicked)
+ self.cmd_set_sensitive('pbranch', self.pbranchwidget.has_pbranch())
+
+ def pbranch_clicked(self, widget, data=None):
+ self.enable_pbranchpanel(widget.get_active())
+
def tree_button_press(self, tree, event):
if event.button == 3 and not (event.state & (gtk.gdk.SHIFT_MASK |
gtk.gdk.CONTROL_MASK)):
|
@@ -19,6 +19,8 @@ import pango
import cairo
+from tortoisehg.hgtk import gtklib
+
# Styles used when rendering revision graph edges
style_SOLID = 0
style_DASHED = 1
@@ -87,24 +89,15 @@ colours and the fg parameter provides the multiplier that should be
applied to the foreground colours.
"""
- mainline_color = ( 0.0, 0.0, 0.0 )
- colours = [
- ( 1.0, 0.0, 0.0 ),
- ( 1.0, 1.0, 0.0 ),
- ( 0.0, 1.0, 0.0 ),
- ( 0.0, 1.0, 1.0 ),
- ( 0.0, 0.0, 1.0 ),
- ( 1.0, 0.0, 1.0 ),
- ]
if isinstance(colour, str):
r, g, b = colour[1:3], colour[3:5], colour[5:7]
colour_rgb = int(r, 16) / 255., int(g, 16) / 255., int(b, 16) / 255.
else:
if colour == 0:
- colour_rgb = mainline_color
+ colour_rgb = gtklib.MAINLINE_COLOR
else:
- colour_rgb = colours[colour % len(colours)]
+ colour_rgb = gtklib.LINE_COLORS[colour % len(gtklib.LINE_COLORS)]
red = (colour_rgb[0] * fg) or bg
green = (colour_rgb[1] * fg) or bg
@@ -189,7 +182,7 @@ # Possible node status
if status != 0:
def draw_arrow(x, y, dir):
- self.set_colour(ctx, '#2e3436', 0.0, 1.0)
+ self.set_colour(ctx, gtklib.CELL_GREY, 0.0, 1.0)
ctx.rectangle(x, y, 2, 5)
ax, ay = x, y + (dir == 'down' and 5 or 0)
inc = 3 * (dir == 'up' and -1 or 1)
@@ -198,12 +191,12 @@ ctx.line_to(ax + 1, ay + inc)
ctx.line_to(ax - 2, ay)
ctx.stroke_preserve()
- fillcolor = dir == 'up' and '#feaf3e' or '#8ae234'
+ fillcolor = dir == 'up' and gtklib.UP_ARROW_COLOR or gtklib.DOWN_ARROW_COLOR
self.set_colour(ctx, fillcolor, 0.0, 1.0)
ctx.fill()
def draw_star(x, y, radius, nodes, offset=False):
- self.set_colour(ctx, '#2e3436', 0.0, 1.0)
+ self.set_colour(ctx, gtklib.CELL_GREY, 0.0, 1.0)
total_nodes = nodes * 2 #inner + outer nodes
angle = 2 * math.pi / total_nodes;
offset = offset and angle / 2 or 0
@@ -218,7 +211,7 @@ else:
ctx.line_to(arc_x, arc_y)
ctx.stroke_preserve()
- self.set_colour(ctx, '#fce94f', 0.0, 1.0)
+ self.set_colour(ctx, gtklib.STAR_COLOR, 0.0, 1.0)
ctx.fill()
arrow_y = arc_start_position_y - box_size / 4
|
@@ -179,7 +179,7 @@ if parent is None:
parent = ctx.parents()[0].node()
M, A, R = self.repo.status(parent, ctx.node())[:3]
- common = dict(color='black')
+ common = dict(color=gtklib.BLACK)
M = M and gtklib.markup(' %s ' % len(M),
background=gtklib.PORANGE, **common) or ''
A = A and gtklib.markup(' %s ' % len(A),
@@ -217,13 +217,13 @@ bg = gtklib.PORANGE
elif tag in self.mqpatches:
bg = gtklib.PBLUE
- style = {'color': 'black', 'background': bg}
+ style = {'color': gtklib.BLACK, 'background': bg}
tstr += gtklib.markup(' %s ' % tag, **style) + ' '
branch = ctx.branch()
bstr = ''
if self.branchtags.get(branch) == node:
- bstr += gtklib.markup(' %s ' % branch, color='black',
+ bstr += gtklib.markup(' %s ' % branch, color=gtklib.BLACK,
background=gtklib.PGREEN) + ' '
if revid in self.wcparents:
@@ -295,7 +295,7 @@ self.color_func = self.text_color_author
def text_color_default(self, rev, author):
- return int(rev) >= self.origtip and 'darkgreen' or 'black'
+ return int(rev) >= self.origtip and gtklib.NEW_REV_COLOR or gtklib.NORMAL
colors = '''black blue deeppink mediumorchid blue burlywood4 goldenrod
slateblue red2 navy dimgrey'''.split()
@@ -303,7 +303,7 @@
def text_color_author(self, rev, author):
if int(rev) >= self.origtip:
- return 'darkgreen'
+ return gtklib.NEW_REV_COLOR
for re, v in self.author_pats:
if (re.search(author)):
return v
|
@@ -214,9 +214,8 @@ threading.Thread(target=start_browser).start()
def _on_conf_clicked(self, *args):
- dlg = thgconfig.ConfigDialog(True)
+ dlg = thgconfig.ConfigDialog(True, focus='web.name')
dlg.show_all()
- dlg.focus_field('web.name')
dlg.run()
dlg.hide()
self._get_config()
|
@@ -53,7 +53,7 @@ elif line.startswith('+'):
hunk += gtklib.markup(line, color=gtklib.DGREEN)
elif line.startswith('@@'):
- hunk = gtklib.markup(line, color='#FF8000')
+ hunk = gtklib.markup(line, color=gtklib.DORANGE)
else:
hunk += gtklib.markup(line)
return hunk
@@ -411,7 +411,7 @@ diffcol.add_attribute(cell, 'markup', DM_DISP_TEXT)
# differentiate header chunks
- cell.set_property('cell-background', '#DDDDDD')
+ cell.set_property('cell-background', gtklib.STATUS_HEADER)
diffcol.add_attribute(cell, 'cell_background_set', DM_IS_HEADER)
self.headerfont = self.difffont.copy()
self.headerfont.set_weight(pango.WEIGHT_HEAVY)
@@ -420,8 +420,8 @@ self.rejfont = self.difffont.copy()
self.rejfont.set_weight(pango.WEIGHT_LIGHT)
diffcol.add_attribute(cell, 'font-desc', DM_FONT)
- cell.set_property('background', '#EEEEEE')
- cell.set_property('foreground', '#888888')
+ cell.set_property('background', gtklib.STATUS_REJECT_BACKGROUND)
+ cell.set_property('foreground', gtklib.STATUS_REJECT_FOREGROUND)
diffcol.add_attribute(cell, 'background-set', DM_REJECTED)
diffcol.add_attribute(cell, 'foreground-set', DM_REJECTED)
difftree.append_column(diffcol)
@@ -870,7 +870,8 @@ sel = lambda x: x >= lasthunk or not dmodel[hc+x+1][DM_REJECTED]
newtext = chunks[0].selpretty(sel)
if not selected:
- newtext = "<span foreground='#888888'>" + newtext + "</span>"
+ newtext = "<span foreground='" + gtklib.STATUS_REJECT_FOREGROUND + \
+ "'>" + newtext + "</span>"
dmodel[hc][DM_DISP_TEXT] = newtext
def updated_codes(self):
@@ -920,15 +921,15 @@ elif stat == 'R':
text_renderer.set_property('foreground', gtklib.DRED)
elif stat == 'C':
- text_renderer.set_property('foreground', 'black')
+ text_renderer.set_property('foreground', gtklib.NORMAL)
elif stat == '!':
- text_renderer.set_property('foreground', 'red')
+ text_renderer.set_property('foreground', gtklib.RED)
elif stat == '?':
- text_renderer.set_property('foreground', '#AA5000')
+ text_renderer.set_property('foreground', gtklib.DORANGE)
elif stat == 'I':
- text_renderer.set_property('foreground', 'black')
+ text_renderer.set_property('foreground', gtklib.NORMAL)
else:
- text_renderer.set_property('foreground', 'black')
+ text_renderer.set_property('foreground', gtklib.NORMAL)
def rename_file(self, wfile):
@@ -1096,7 +1097,7 @@ else:
buf.create_tag('removed', foreground=gtklib.DRED)
buf.create_tag('added', foreground=gtklib.DGREEN)
- buf.create_tag('position', foreground='#FF8000')
+ buf.create_tag('position', foreground=gtklib.DORANGE)
buf.create_tag('header', foreground=gtklib.DBLUE)
bufiter = buf.get_start_iter()
|
|
|
@@ -11,7 +11,7 @@ import re
import urlparse
-from mercurial import hg, ui, util, url, filemerge, error
+from mercurial import hg, ui, util, url, filemerge, error, extensions
from tortoisehg.util.i18n import _
from tortoisehg.util import hglib, settings, paths
@@ -23,7 +23,8 @@
_pwfields = ('http_proxy.passwd', 'smtp.password')
-_tortoise_info = (
+INFO = (
+({'name': 'general', 'label': 'TortoiseHg', 'icon': 'thg_logo.ico'}, (
(_('Three-way Merge Tool'), 'ui.merge', [],
_('Graphical merge program for resolving merge conflicts. If left'
' unspecified, Mercurial will use the first applicable tool it finds'
@@ -62,9 +63,13 @@ ' process to run graphical dialogs. Default: True')),
(_('Full Path Title'), 'tortoisehg.fullpath', ['False', 'True'],
_('Show a full directory path of the repository in the dialog title'
- ' instead of just the root directory name. Default: False')))
+ ' instead of just the root directory name. Default: False')),
+ ) + (gtklib.hasspellcheck() and
+ (_('Spell Check Language'), 'tortoisehg.spellcheck', [],
+ _('Default language for spell check. System language is'
+ ' used if not specified. Examples: en, en_GB, en_US'),) or ())),
-_commit_info = (
+({'name': 'commit', 'label': _('Commit'), 'icon': 'menucommit.ico'}, (
(_('Username'), 'ui.username', [],
_('Name associated with commits')),
(_('Summary Line Length'), 'tortoisehg.summarylen', ['0', '70'],
@@ -88,10 +93,11 @@ (_('Auto Exclude List'), 'tortoisehg.ciexclude', [],
_('Comma separated list of files that are automatically unchecked'
' when the status, commit, and shelve dialogs are opened.'
- ' Default: None'))
- )
+ ' Default: None')),
+ )),
-_log_info = (
+({'name': 'log', 'label': _('Repository Explorer'),
+ 'icon': 'menulog.ico'}, (
(_('Author Coloring'), 'tortoisehg.authorcolor', ['False', 'True'],
_('Color changesets by author name. If not enabled,'
' the changes are colored green for merge, red for'
@@ -118,25 +124,27 @@ ' Default: None')),
(_('Hide Tags'), 'tortoisehg.hidetags', [],
_('Space separated list of tags that will not be shown.'
- ' Useful example: Specify "qbase qparent qtip" to hide the'
- ' standard tags inserted by the Mercurial Queues Extension.'
+ ' Useful example: Specify "qbase qparent qtip" to hide the'
+ ' standard tags inserted by the Mercurial Queues Extension.'
' Default: None')),
(_('Use Expander'), 'tortoisehg.changeset-expander', ['False', 'True'],
_('Show changeset details with an expander')),
(_('Toolbar Style'), 'tortoisehg.logtbarstyle',
['small', 'large', 'theme'],
_('Adjust the display of the main toolbar in the Repository'
- ' Explorer. Values: small, large, or theme. Default: theme')),
- )
+ ' Explorer. Values: small, large, or theme. Default: theme')),
+ )),
-_paths_info = (
+({'name': 'sync', 'label': _('Synchronize'), 'icon': 'menusynch.ico',
+ 'extra': True}, (
(_('After Pull Operation'), 'tortoisehg.postpull',
['none', 'update', 'fetch', 'rebase'],
_('Operation which is performed directly after a successful pull.'
- ' update equates to pull --update, fetch equates to the fetch'
- ' extension, rebase equates to pull --rebase. Default: none')),)
+ ' update equates to pull --update, fetch equates to the fetch'
+ ' extension, rebase equates to pull --rebase. Default: none')),
+ )),
-_web_info = (
+({'name': 'web', 'label': _('Web Server'), 'icon': 'proxy.ico'}, (
(_('Name'), 'web.name', ['unknown'],
_('Repository name to use in the web interface.'
' Default is the working directory.')),
@@ -179,9 +187,10 @@ ' (separated by whitespace or ",") is also denied. The contents'
' of the deny_push list are examined before the allow_push list.')),
(_('Encoding'), 'web.encoding', ['UTF-8'],
- _('Character encoding name')))
+ _('Character encoding name')),
+ )),
-_proxy_info = (
+({'name': 'proxy', 'label': _('Proxy'), 'icon': 'general.ico'}, (
(_('Host'), 'http_proxy.host', [],
_('Host name and (optional) port of proxy server, for'
' example "myproxy:8000"')),
@@ -189,29 +198,29 @@ _('Optional. Comma-separated list of host names that'
' should bypass the proxy')),
(_('User'), 'http_proxy.user', [],
- _('Optional. User name to authenticate with at the'
- ' proxy server')),
+ _('Optional. User name to authenticate with at the proxy server')),
(_('Password'), 'http_proxy.passwd', [],
- _('Optional. Password to authenticate with at the'
- ' proxy server')))
+ _('Optional. Password to authenticate with at the proxy server')),
+ )),
-_email_info = (
+({'name': 'email', 'label': _('Email'), 'icon': gtk.STOCK_GOTO_LAST}, (
(_('From'), 'email.from', [],
- _('Email address to use in the "From" header and for the SMTP envelope')),
+ _('Email address to use in the "From" header and for'
+ ' the SMTP envelope')),
(_('To'), 'email.to', [],
_('Comma-separated list of recipient email addresses')),
(_('Cc'), 'email.cc', [],
- _('Comma-separated list of carbon copy recipient email'
- ' addresses')),
+ _('Comma-separated list of carbon copy recipient email addresses')),
(_('Bcc'), 'email.bcc', [],
_('Comma-separated list of blind carbon copy recipient'
' email addresses')),
(_('method'), 'email.method', ['smtp'],
-_('Optional. Method to use to send email messages. If value is "smtp" (default),'
-' use SMTP (configured below). Otherwise, use as name of program to run that'
-' acts like sendmail (takes "-f" option for sender, list of recipients on'
-' command line, message on stdin). Normally, setting this to "sendmail" or'
-' "/usr/sbin/sendmail" is enough to use sendmail to send messages.')),
+ _('Optional. Method to use to send email messages. If value is'
+ ' "smtp" (default), use SMTP (configured below). Otherwise, use as'
+ ' name of program to run that acts like sendmail (takes "-f" option'
+ ' for sender, list of recipients on command line, message on stdin).'
+ ' Normally, setting this to "sendmail" or "/usr/sbin/sendmail"'
+ ' is enough to use sendmail to send messages.')),
(_('SMTP Host'), 'smtp.host', [], _('Host name of mail server')),
(_('SMTP Port'), 'smtp.port', ['25'],
_('Port to connect to on mail server.'
@@ -224,9 +233,11 @@ (_('SMTP Password'), 'smtp.password', [],
_('Password to authenticate to mail server with')),
(_('Local Hostname'), 'smtp.local_hostname', [],
- _('Hostname the sender can use to identify itself to the mail server.')))
+ _('Hostname the sender can use to identify itself to the'
+ ' mail server.')),
+ )),
-_diff_info = (
+({'name': 'diff', 'label': _('Diff'), 'icon': gtk.STOCK_JUSTIFY_FILL}, (
(_('Patch EOL'), 'patch.eol', ['strict', 'crlf', 'lf'],
_('Normalize file line endings during and after patch to lf or'
' crlf. Strict does no normalization.'
@@ -251,10 +262,12 @@ ' Default: False')),
(_('Coloring Style'), 'tortoisehg.diffcolorstyle',
['none', 'foreground', 'background'],
- _('Adjust the coloring style of diff lines in the changeset viewer.'
- ' Default: foreground')))
+ _('Adjust the coloring style of diff lines in the changeset'
+ ' viewer. Default: foreground')),
+ )),
-_font_info = (
+({'name': 'font', 'label': _('Font'), 'icon': gtk.STOCK_SELECT_FONT,
+ 'extra': True, 'width': 16}, (
(_('Commit Message'), 'gtools.fontcomment', [],
_('Font used in changeset viewer and commit log text.'
' Default: monospace 10')),
@@ -266,7 +279,11 @@ ' Default: sans 9')),
(_('Command Output'), 'gtools.fontlog', [],
_('Font used in command output window.'
- ' Default: monospace 10')))
+ ' Default: monospace 10')),
+ )),
+
+({'name': 'extensions', 'label': _('Extensions'), 'icon': gtk.STOCK_EXECUTE,
+ 'extra': True}, ()),)
_font_presets = {
'win-ja': (_('Japanese on Windows'), {
@@ -540,7 +557,7 @@CONF_REPO = 1
class ConfigDialog(gtk.Dialog):
- def __init__(self, configrepo=False):
+ def __init__(self, configrepo=False, focus=None):
""" Initialize the Dialog. """
gtk.Dialog.__init__(self, parent=None, flags=0,
buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK,
@@ -654,28 +671,11 @@ self.tooltips = gtk.Tooltips()
self.history = settings.Settings('thgconfig')
- # add spell ckeck entry if spell check is supported
- tortoise_info = _tortoise_info
- if gtklib.hasspellcheck():
- tortoise_info += ((
- _('Spell Check Language'), 'tortoisehg.spellcheck', [],
- _('Default language for spell check. '
- 'System language is used if not specified. '
- 'Examples: en, en_GB, en_US')),)
-
- # create pages for each section of configuration file
- self.add_page('TortoiseHg', 'general', tortoise_info, 'thg_logo.ico')
- self.add_page(_('Commit'), 'commit', _commit_info, 'menucommit.ico')
- self.add_page(_('Repository Explorer'), 'log', _log_info,
- 'menulog.ico')
- self.add_page(_('Synchronize'), 'sync', _paths_info, 'menusynch.ico',
- extra=True)
- self.add_page(_('Web Server'), 'web', _web_info, 'proxy.ico')
- self.add_page(_('Proxy'), 'proxy', _proxy_info, 'general.ico')
- self.add_page(_('Email'), 'email', _email_info, gtk.STOCK_GOTO_LAST)
- self.add_page(_('Diff'), 'diff', _diff_info, gtk.STOCK_JUSTIFY_FILL)
- self.add_page(_('Font'), 'font', _font_info, gtk.STOCK_SELECT_FONT,
- extra=True, width=20)
+ # add page items to treeview
+ for meta, info in INFO:
+ pixbuf = gtklib.get_icon_pixbuf(meta['icon'],
+ gtk.ICON_SIZE_LARGE_TOOLBAR)
+ self.confmodel.append((pixbuf, meta['label'], meta['name']))
# insert padding of between notebook and common desc frame
mainbox.pack_start(gtk.VBox(), False, False, 2)
@@ -699,9 +699,12 @@ self.dirty = False
combo.set_active(configrepo and CONF_REPO or CONF_GLOBAL)
- # activate first config page
- self.confview.set_cursor(self.confmodel[0].path)
- self.confview.grab_focus()
+ # focus 'general' page or specified field
+ if focus:
+ self.focus_field(focus)
+ else:
+ self.show_page('general')
+ self.confview.grab_focus()
def fileselect(self, combo):
'select another hgrc file'
@@ -721,58 +724,24 @@ self.refresh()
def refresh(self):
+ # determine target config file
if self.confcombo.get_active() == CONF_REPO:
repo = hg.repository(ui.ui(), self.root)
name = hglib.get_reponame(repo)
self.rcpath = [os.sep.join([repo.root, '.hg', 'hgrc'])]
- self.set_title(_('TortoiseHg Configure Repository - ') + hglib.toutf(name))
+ self.set_title(_('TortoiseHg Configure Repository - ') + \
+ hglib.toutf(name))
gtklib.set_tortoise_icon(self, 'settings_repo.ico')
else:
self.rcpath = util.user_rcpath()
self.set_title(_('TortoiseHg Configure User-Global Settings'))
gtklib.set_tortoise_icon(self, 'settings_user.ico')
+
+ # refresh config values
self.ini = self.load_config(self.rcpath)
self.refresh_vlist()
- # refresh sync frame
- self.pathdata.clear()
- if 'paths' in self.ini:
- for name in self.ini['paths']:
- path = self.ini['paths'][name]
- safepath = hglib.toutf(url.hidepassword(path))
- self.pathdata.append([hglib.toutf(name), safepath,
- hglib.toutf(path)])
- self.refresh_path_list()
-
- # refresh preset fonts combo
- model = self.presetcombo.get_model()
- cpaths = [info[1] for info in _font_info]
- defaulfonts = True
- for cpath in cpaths:
- value = self.get_ini_config(cpath)
- if value is not None:
- defaulfonts = False
- if defaulfonts:
- # theme default fonts
- self.defaultradio.set_active(True)
- self.presetcombo.set_active(0)
- else:
- for name, (label, preset) in _font_presets.items():
- for cpath in cpaths:
- if self.get_ini_config(cpath) != preset[cpath]:
- break
- else:
- # preset fonts
- rows = [row for row in model if row[0] == name]
- if rows:
- self.presetcombo.set_active_iter(rows[0].iter)
- self.presetradio.set_active(True)
- break
- else:
- # custom fonts
- self.customradio.set_active(True)
- self.presetcombo.set_active(0)
-
+ # clear modification status
self._btn_apply.set_sensitive(False)
self.dirty = False
@@ -821,21 +790,29 @@ if not path:
return
name = self.confmodel[path][2]
+ if not self.pages.has_key(name):
+ self.add_page(name)
page_num, info, vbox, widgets = self.pages[name]
self.notebook.set_current_page(page_num)
def show_page(self, name):
'''Show page by activating treeview item'''
- page_num = self.pages[name][0]
- path = self.confmodel[page_num].path
+ for row in self.confmodel:
+ if name == row[2]:
+ path = row.path
+ break
+ else:
+ return
self.confview.set_cursor(path)
def focus_field(self, focusfield):
'''Set page and focus to requested datum'''
- for name, (page_num, info, vbox, widgets) in self.pages.items():
+ for meta, info in INFO:
for n, (label, cpath, values, tip) in enumerate(info):
if cpath == focusfield:
+ name = meta['name']
self.show_page(name)
+ widgets = self.pages[name][3]
widgets[n].grab_focus()
return
@@ -865,104 +842,6 @@ self._btn_apply.set_sensitive(not self.readonly)
self.dirty = True
- def _add_path(self, *args):
- self.new_path('http://')
- self._edit_path(new=True)
-
- def _edit_path(self, *args, **opts):
- selection = self.pathtree.get_selection()
- if not selection.count_selected_rows():
- return
- model, path = selection.get_selected()
- dialog = PathEditDialog(model[path][2], model[path][0],
- [p[0] for p in self.pathdata if p[0] != model[path][0]])
- dialog.set_transient_for(self)
- dialog.run()
- if dialog.newpath:
- if model[path][0] != dialog.newalias:
- # remove existing path
- rows = [row for row in model if row[0] == dialog.newalias]
- if len(rows) > 0:
- del model[rows[0].iter]
- # update path info
- model[path][0] = dialog.newalias
- model[path][1] = url.hidepassword(dialog.newpath)
- model[path][2] = dialog.newpath
- self.dirty_event()
- elif opts.has_key('new') and opts['new'] == True:
- del self.pathdata[path]
- self.refresh_path_list()
- self.dirty_event()
-
- def _remove_path(self, *args):
- selection = self.pathtree.get_selection()
- if not selection.count_selected_rows():
- return
- model, path = selection.get_selected()
- next_iter = self.pathdata.iter_next(path)
- del self.pathdata[path]
- if next_iter:
- selection.select_iter(next_iter)
- elif len(self.pathdata):
- selection.select_path(len(self.pathdata) - 1)
- self.refresh_path_list()
- self.dirty_event()
-
- def _test_path(self, *args):
- selection = self.pathtree.get_selection()
- if not selection.count_selected_rows():
- return
- if not self.root:
- dialog.error_dialog(self, _('No Repository Found'),
- _('Path testing cannot work without a repository'))
- return
- model, path = selection.get_selected()
- testpath = hglib.fromutf(model[path][2])
- if not testpath:
- return
- if testpath[0] == '~':
- testpath = os.path.expanduser(testpath)
- cmdline = ['hg', 'incoming', '--verbose', testpath]
- dlg = hgcmd.CmdDialog(cmdline, text='hg incoming')
- dlg.run()
- dlg.hide()
-
- def _default_path(self, *args):
- selection = self.pathtree.get_selection()
- if not selection.count_selected_rows():
- return
- model, path = selection.get_selected()
- if model[path][0] == 'default':
- return
- # collect rows has 'default' alias
- rows = [row for row in model if row[0] == 'default']
- if len(rows) > 0:
- ret = gdialog.Confirm(_('Confirm Overwrite'), [], self,
- _("Overwrite existing '%s' path?") % 'default').run()
- if ret != gtk.RESPONSE_YES:
- return
- # remove old default path
- default_iter = rows[0].iter
- del model[default_iter]
- # set 'default' alias to selected path
- model[path][0] = 'default'
- self.refresh_path_list()
- self.dirty_event()
-
- def _pathtree_changed(self, sel):
- self.refresh_path_list()
-
- def _pathtree_pressed(self, widget, event):
- if event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS:
- x, y = int(event.x), int(event.y)
- pathinfo = self.pathtree.get_path_at_pos(x, y)
- if pathinfo is not None:
- self._edit_path()
- elif event.button == 1:
- selection = self.pathtree.get_selection()
- selection.unselect_all()
- self.refresh_path_list()
-
def refresh_path_list(self):
"""Update sensitivity of buttons"""
selection = self.pathtree.get_selection()
@@ -974,10 +853,10 @@ default_path = model[path][0] == 'default'
else:
default_path = False
- self._editpathbutton.set_sensitive(path_selected)
- self._delpathbutton.set_sensitive(path_selected)
- self._testpathbutton.set_sensitive(repo_available and path_selected)
- self._defaultpathbutton.set_sensitive(not default_path and path_selected)
+ self.editpathbtn.set_sensitive(path_selected)
+ self.delpathbtn.set_sensitive(path_selected)
+ self.testpathbtn.set_sensitive(repo_available and path_selected)
+ self.defaultpathbtn.set_sensitive(not default_path and path_selected)
def fill_sync_frame(self, parent, table):
# add table
@@ -1000,8 +879,6 @@ self.pathtree = gtk.TreeView(self.pathdata)
self.pathtree.set_enable_search(False)
self.pathtree.add_events(gtk.gdk.BUTTON_PRESS_MASK)
- self.pathtree.connect('cursor-changed', self._pathtree_changed)
- self.pathtree.connect('button-press-event', self._pathtree_pressed)
renderer = gtk.CellRendererText()
column = gtk.TreeViewColumn(_('Alias'), renderer, text=0)
@@ -1025,30 +902,138 @@ bottombox = gtk.HBox()
vbox.pack_start(bottombox, False, False, 4)
- self.addButton = gtk.Button(_('_Add'))
- self.addButton.set_use_underline(True)
- self.addButton.connect('clicked', self._add_path)
- bottombox.pack_start(self.addButton, True, True, 2)
+ addpathbtn = gtk.Button(_('_Add'))
+ addpathbtn.set_use_underline(True)
+ bottombox.pack_start(addpathbtn, True, True, 2)
- self._editpathbutton = gtk.Button(_('_Edit'))
- self._editpathbutton.set_use_underline(True)
- self._editpathbutton.connect('clicked', self._edit_path)
- bottombox.pack_start(self._editpathbutton, True, True, 2)
+ self.editpathbtn = gtk.Button(_('_Edit'))
+ self.editpathbtn.set_use_underline(True)
+ bottombox.pack_start(self.editpathbtn, True, True, 2)
- self._delpathbutton = gtk.Button(_('_Remove'))
- self._delpathbutton.set_use_underline(True)
- self._delpathbutton.connect('clicked', self._remove_path)
- bottombox.pack_start(self._delpathbutton, True, True, 2)
+ self.delpathbtn = gtk.Button(_('_Remove'))
+ self.delpathbtn.set_use_underline(True)
+ bottombox.pack_start(self.delpathbtn, True, True, 2)
- self._testpathbutton = gtk.Button(_('_Test'))
- self._testpathbutton.set_use_underline(True)
- self._testpathbutton.connect('clicked', self._test_path)
- bottombox.pack_start(self._testpathbutton, True, True, 2)
+ self.testpathbtn = gtk.Button(_('_Test'))
+ self.testpathbtn.set_use_underline(True)
+ bottombox.pack_start(self.testpathbtn, True, True, 2)
- self._defaultpathbutton = gtk.Button(_('Set as _default'))
- self._defaultpathbutton.set_use_underline(True)
- self._defaultpathbutton.connect('clicked', self._default_path)
- bottombox.pack_start(self._defaultpathbutton, True, True, 2)
+ self.defaultpathbtn = gtk.Button(_('Set as _default'))
+ self.defaultpathbtn.set_use_underline(True)
+ bottombox.pack_start(self.defaultpathbtn, True, True, 2)
+
+ # signal handlers
+ def pathtree_changed(sel):
+ self.refresh_path_list()
+ def pathtree_pressed(widget, event):
+ if event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS:
+ x, y = int(event.x), int(event.y)
+ pathinfo = self.pathtree.get_path_at_pos(x, y)
+ if pathinfo is not None:
+ edit_path()
+ elif event.button == 1:
+ selection = self.pathtree.get_selection()
+ selection.unselect_all()
+ self.refresh_path_list()
+ def edit_path(*args, **opts):
+ selection = self.pathtree.get_selection()
+ if not selection.count_selected_rows():
+ return
+ model, path = selection.get_selected()
+ dialog = PathEditDialog(model[path][2], model[path][0],
+ [p[0] for p in self.pathdata if p[0] != model[path][0]])
+ dialog.set_transient_for(self)
+ dialog.run()
+ if dialog.newpath:
+ if model[path][0] != dialog.newalias:
+ # remove existing path
+ rows = [row for row in model if row[0] == dialog.newalias]
+ if len(rows) > 0:
+ del model[rows[0].iter]
+ # update path info
+ model[path][0] = dialog.newalias
+ model[path][1] = url.hidepassword(dialog.newpath)
+ model[path][2] = dialog.newpath
+ self.dirty_event()
+ elif opts.has_key('new') and opts['new'] == True:
+ del self.pathdata[path]
+ self.refresh_path_list()
+ self.dirty_event()
+
+ def add_path(*args):
+ self.new_path('http://')
+ edit_path(new=True)
+ def remove_path(*args):
+ selection = self.pathtree.get_selection()
+ if not selection.count_selected_rows():
+ return
+ model, path = selection.get_selected()
+ next_iter = self.pathdata.iter_next(path)
+ del self.pathdata[path]
+ if next_iter:
+ selection.select_iter(next_iter)
+ elif len(self.pathdata):
+ selection.select_path(len(self.pathdata) - 1)
+ self.refresh_path_list()
+ self.dirty_event()
+ def test_path(*args):
+ selection = self.pathtree.get_selection()
+ if not selection.count_selected_rows():
+ return
+ if not self.root:
+ dialog.error_dialog(self, _('No Repository Found'),
+ _('Path testing cannot work without a repository'))
+ return
+ model, path = selection.get_selected()
+ testpath = hglib.fromutf(model[path][2])
+ if not testpath:
+ return
+ if testpath[0] == '~':
+ testpath = os.path.expanduser(testpath)
+ cmdline = ['hg', 'incoming', '--verbose', testpath]
+ dlg = hgcmd.CmdDialog(cmdline, text='hg incoming')
+ dlg.run()
+ dlg.hide()
+ def make_default(*args):
+ selection = self.pathtree.get_selection()
+ if not selection.count_selected_rows():
+ return
+ model, path = selection.get_selected()
+ if model[path][0] == 'default':
+ return
+ # collect rows has 'default' alias
+ rows = [row for row in model if row[0] == 'default']
+ if len(rows) > 0:
+ ret = gdialog.Confirm(_('Confirm Overwrite'), [], self,
+ _("Overwrite existing '%s' path?") % 'default').run()
+ if ret != gtk.RESPONSE_YES:
+ return
+ # remove old default path
+ default_iter = rows[0].iter
+ del model[default_iter]
+ # set 'default' alias to selected path
+ model[path][0] = 'default'
+ self.refresh_path_list()
+ self.dirty_event()
+
+ # connect handlers
+ self.pathtree.connect('cursor-changed', pathtree_changed)
+ self.pathtree.connect('button-press-event', pathtree_pressed)
+ addpathbtn.connect('clicked', add_path)
+ self.editpathbtn.connect('clicked', edit_path)
+ self.delpathbtn.connect('clicked', remove_path)
+ self.testpathbtn.connect('clicked', test_path)
+ self.defaultpathbtn.connect('clicked', make_default)
+
+ def refresh_sync_frame(self):
+ self.pathdata.clear()
+ if 'paths' in self.ini:
+ for name in self.ini['paths']:
+ path = self.ini['paths'][name]
+ safepath = hglib.toutf(url.hidepassword(path))
+ self.pathdata.append([hglib.toutf(name), safepath,
+ hglib.toutf(path)])
+ self.refresh_path_list()
def fill_font_frame(self, parent, table):
# layout table
@@ -1118,6 +1103,100 @@ # prepare to show
radio_activated(defaultradio, init=True)
+ def refresh_font_frame(self):
+ model = self.presetcombo.get_model()
+ cpaths = [info[1] for info in self.pages['font'][1]]
+ defaulfonts = True
+ for cpath in cpaths:
+ value = self.get_ini_config(cpath)
+ if value is not None:
+ defaulfonts = False
+ if defaulfonts:
+ # theme default fonts
+ self.defaultradio.set_active(True)
+ self.presetcombo.set_active(0)
+ else:
+ for name, (label, preset) in _font_presets.items():
+ for cpath in cpaths:
+ if self.get_ini_config(cpath) != preset[cpath]:
+ break
+ else:
+ # preset fonts
+ rows = [row for row in model if row[0] == name]
+ if rows:
+ self.presetcombo.set_active_iter(rows[0].iter)
+ self.presetradio.set_active(True)
+ break
+ else:
+ # custom fonts
+ self.customradio.set_active(True)
+ self.presetcombo.set_active(0)
+
+ def fill_extensions_frame(self, parent, table):
+ def allexts():
+ enabledexts, maxnamelen = extensions.enabled()
+ disabledexts, maxnamelen = extensions.disabled()
+ exts = disabledexts.copy()
+ exts.update(enabledexts)
+ return iter((name, exts[name])
+ for name in sorted(exts.iterkeys()))
+
+ vbox = gtk.VBox()
+ parent.pack_start(table, False, False)
+
+ self.extensionschecks = {}
+ for name, shortdesc in allexts():
+ ck = gtk.CheckButton(name)
+ ck.connect('toggled', self.dirty_event)
+ ck.connect('focus-in-event', self.set_help, shortdesc)
+ table.add_row(ck, padding=False)
+ self.tooltips.set_tip(ck, shortdesc)
+ self.extensionschecks[name] = ck
+
+ def refresh_extensions_frame(self):
+ enabledexts, namemaxlen = extensions.enabled()
+ def getinival(name):
+ for cand in (name, 'hgext.%s' % name, 'hgext/%s' % name):
+ try:
+ return self.ini['extensions'][cand]
+ except KeyError:
+ pass
+
+ def changable(name):
+ curval = getinival(name)
+ if curval not in ('', None):
+ # enabled or unspecified, official extensions only
+ return False
+ elif name in enabledexts and curval is None:
+ # re-disabling ext is not supported
+ return False
+ else:
+ return True
+
+ for name, ck in self.extensionschecks.iteritems():
+ ck.set_active(name in enabledexts)
+ ck.set_sensitive(changable(name))
+
+ def apply_extensions_changes(self):
+ enabledexts, namemaxlen = extensions.enabled()
+ for name, ck in self.extensionschecks.iteritems():
+ if ck.get_active() == (name in enabledexts):
+ continue # unchanged
+
+ if 'extensions' not in self.ini:
+ new_namespace = getattr(self.ini, '_new_namespace',
+ self.ini.new_namespace)
+ new_namespace('extensions')
+
+ if ck.get_active():
+ self.ini['extensions'][name] = ''
+ else:
+ for cand in (name, 'hgext.%s' % name, 'hgext/%s' % name):
+ try:
+ del self.ini['extensions'][cand]
+ except KeyError:
+ pass
+
def set_help(self, widget, event, tooltip):
text = ' '.join(tooltip.splitlines())
self.descbuffer.set_text(text)
@@ -1153,8 +1232,19 @@
return vbox, table, widgets
- def refresh_vlist(self):
- for page_num, info, vbox, widgets in self.pages.values():
+ def refresh_vlist(self, pagename=None):
+ # sotre modification status
+ prev_dirty = self.dirty
+
+ # update configured values
+ if pagename is None:
+ pages = self.pages.values()
+ pages = [(key,) + data for key, data in self.pages.items()]
+ else:
+ pages = ((pagename,) + self.pages[pagename],)
+ for name, page_num, info, vbox, widgets in pages:
+
+ # standard configs
for row, (label, cpath, values, tooltip) in enumerate(info):
ispw = cpath in _pwfields
combo = widgets[row]
@@ -1166,9 +1256,9 @@
if cpath == 'tortoisehg.vdiff':
tools = hglib.difftools(self.ui)
- for name in tools.keys():
- if name not in values:
- values.append(name)
+ for key in tools.keys():
+ if key not in values:
+ values.append(key)
elif cpath == 'ui.merge':
# Special case, add [merge-tools] to possible values
hglib.mergetools(self.ui, values)
@@ -1200,8 +1290,26 @@ elif currow:
combo.set_active(currow)
- def add_page(self, label, name, info, icon=None, extra=False, width=32):
- # setup page
+ # extra configs
+ func_name = 'refresh_%s_frame' % name
+ if hasattr(self, func_name):
+ getattr(self, func_name)()
+
+ # clear modification status forcibly if need
+ if self.dirty != prev_dirty:
+ self._btn_apply.set_sensitive(False)
+ self.dirty = False
+
+ def add_page(self, name):
+ for data in INFO:
+ if name == data[0]['name']:
+ meta, info = data
+ break
+ else:
+ return
+ extra, width = meta.get('extra', False), meta.get('width', 32)
+
+ # setup frame and content
frame = gtk.VBox()
frame.show()
@@ -1215,11 +1323,9 @@ pagenum = self.notebook.append_page(frame)
self.pages[name] = (pagenum, info, vbox, widgets)
- # add treeview item
- pixbuf = gtklib.get_icon_pixbuf(icon, gtk.ICON_SIZE_LARGE_TOOLBAR)
- self.confmodel.append((pixbuf, label, name))
-
- return frame
+ # prepare to show
+ self.refresh_vlist(name)
+ frame.show_all()
def get_ini_config(self, cpath):
'''Retrieve a value from the parsed config file'''
@@ -1307,24 +1413,29 @@ self.history.read()
# flush changes on paths page
- if len(self.pathdata):
- refreshlist = []
- for row in self.pathdata:
- name = hglib.fromutf(row[0])
- path = hglib.fromutf(row[2])
- if not name:
- gdialog.Prompt(_('Invalid path'),
- _('Skipped saving path with no alias'), self).run()
- continue
- cpath = '.'.join(['paths', name])
- self.record_new_value(cpath, path, False)
- refreshlist.append(name)
- for name in self.ini.paths:
- if name not in refreshlist:
+ if self.pages.has_key('sync'):
+ if len(self.pathdata):
+ refreshlist = []
+ for row in self.pathdata:
+ name = hglib.fromutf(row[0])
+ path = hglib.fromutf(row[2])
+ if not name:
+ gdialog.Prompt(_('Invalid path'),
+ _('Skipped saving path with no alias'),
+ self).run()
+ continue
+ cpath = '.'.join(['paths', name])
+ self.record_new_value(cpath, path, False)
+ refreshlist.append(name)
+ for name in self.ini.paths:
+ if name not in refreshlist:
+ del self.ini['paths'][name]
+ elif 'paths' in list(self.ini):
+ for name in list(self.ini.paths):
del self.ini['paths'][name]
- elif 'paths' in list(self.ini):
- for name in list(self.ini.paths):
- del self.ini['paths'][name]
+
+ if 'extensions' in self.pages:
+ self.apply_extensions_changes()
# Flush changes on all pages
for page_num, info, vbox, widgets in self.pages.values():
@@ -1348,7 +1459,6 @@ return 0
def run(ui, *pats, **opts):
- dlg = ConfigDialog(opts.get('alias') == 'repoconfig')
- if opts.get('focus'):
- dlg.focus_field(opts['focus'])
+ dlg = ConfigDialog(opts.get('alias') == 'repoconfig',
+ focus=opts.get('focus'))
return dlg
|
@@ -721,11 +721,11 @@
stat = row[MQ_STATUS]
if stat == 'A':
- cell.set_property('foreground', 'blue')
+ cell.set_property('foreground', gtklib.BLUE)
elif stat == 'U':
- cell.set_property('foreground', '#909090')
+ cell.set_property('foreground', gtklib.GREY)
else:
- cell.set_property('foreground', 'black')
+ cell.set_property('foreground', gtklib.NORMAL)
patchname = row[MQ_NAME]
if self.is_qtip(patchname):
|
This file's diff was not loaded because this changeset is very large. Load changes Loading... |
Loading...