by
Changes to 23 files · Browse files at cb9edf30b6f5 Showing diff from parent bc079921d972 f6b8c31da4da Diff from another changeset...
|
|
@@ -22,6 +22,7 @@ from mercurial import context, patch, revlog
from gdialog import *
from hgcmd import CmdDialog
+from hglib import toutf, fromutf
class ChangeSet(GDialog):
@@ -106,7 +107,8 @@ def _fill_buffer(self, buf, rev, ctx, filelist):
def title_line(title, text, tag):
pad = ' ' * (12 - len(title))
- buf.insert_with_tags_by_name(eob, title + pad + text, tag)
+ utext = toutf(title + pad + text)
+ buf.insert_with_tags_by_name(eob, utext, tag)
buf.insert(eob, "\n")
# TODO: Add toggle for gmtime/localtime
@@ -124,7 +126,7 @@ for p in parents:
pctx = self.repo.changectx(p)
summary = pctx.description().splitlines()[0]
- summary = unicode(summary, 'latin-1', 'replace')
+ summary = toutf(summary)
change = str(p) + ':' + short(self.repo.changelog.node(p))
title = 'parent:'
title += ' ' * (12 - len(title))
@@ -135,7 +137,7 @@ for n in self.repo.changelog.children(ctx.node()):
cctx = self.repo.changectx(n)
summary = cctx.description().splitlines()[0]
- summary = unicode(summary, 'latin-1', 'replace')
+ summary = toutf(summary)
childrev = self.repo.changelog.rev(n)
change = str(childrev) + ':' + short(n)
title = 'child:'
@@ -148,7 +150,7 @@ childrev = self.repo.changelog.rev(n)
if tags: title_line('tags:', tags, 'tag')
- log = util.fromlocal(ctx.description())
+ log = toutf(ctx.description())
buf.insert(eob, '\n' + log + '\n\n')
if self.parent_toggle.get_active():
@@ -176,7 +178,7 @@ except StopIteration:
return False
- lines = unicode(txt, 'latin-1', 'replace').splitlines()
+ lines = txt.splitlines()
eob = buf.get_end_iter()
offset = eob.get_offset()
fileoffs, tags, lines, statmax = self.prepare_diff(lines, offset, file)
@@ -195,7 +197,7 @@ pos = buf.get_iter_at_offset(offset)
mark = 'mark_%d' % offset
buf.create_mark(mark, pos)
- filelist.append((status, file, mark, True, stats))
+ filelist.append((status, toutf(file), mark, True, stats))
sob, eob = buf.get_bounds()
buf.apply_tag_by_name("mono", pos, eob)
return True
@@ -373,9 +375,10 @@ tags.append( [name, offset, offset+length] )
stats = [0,0]
statmax = 0
- for i,l in enumerate(difflines):
+ for i,l1 in enumerate(difflines):
+ l = toutf(l1)
if l.startswith("diff"):
- txt = DIFFHDR % fname
+ txt = toutf(DIFFHDR % fname)
addtag( "greybg", offset, len(txt) )
outlines.append(txt)
markname = "file%d" % idx
@@ -383,7 +386,7 @@ statmax = max( statmax, stats[0]+stats[1] )
stats = [0,0]
filespos.append(( markname, offset, stats ))
- offset += len(txt)
+ offset += len(txt.decode('utf-8'))
continue
elif l.startswith("+++"):
continue
@@ -400,7 +403,7 @@ else:
tag = "black"
l = l+"\n"
- length = len(l)
+ length = len(l.decode('utf-8'))
addtag( tag, offset, length )
outlines.append( l )
offset += length
@@ -488,10 +491,10 @@
self._filelist = gtk.ListStore(
gobject.TYPE_STRING, # MAR status
- gobject.TYPE_STRING, # filename
+ gobject.TYPE_STRING, # filename (utf-8 encoded)
gobject.TYPE_PYOBJECT, # mark
gobject.TYPE_PYOBJECT, # give cmenu
- gobject.TYPE_PYOBJECT # diffstats
+ gobject.TYPE_PYOBJECT, # diffstats
)
filelist_tree.set_model(self._filelist)
column = gtk.TreeViewColumn('Stat', gtk.CellRendererText(), text=0)
@@ -561,7 +564,7 @@ mark = self._buffer.get_mark(model[iter][2])
self.textview.scroll_to_mark(mark, 0.0, True, 0.0, 0.0)
if model[iter][3]:
- self.curfile = model[iter][1]
+ self.curfile = fromutf(model[iter][1])
else:
self.curfile = None
|
@@ -50,7 +50,7 @@ self._create()
def _create(self):
- self.set_default_size(400, 180)
+ self.set_default_size(520, 180)
self.connect('destroy', gtk.main_quit)
ewidth = 16
@@ -166,11 +166,18 @@ self._opt_update = gtk.CheckButton("do not update the new working directory")
self._opt_pull = gtk.CheckButton("use pull protocol to copy metadata")
self._opt_uncomp = gtk.CheckButton("use uncompressed transfer")
+ self._opt_proxy = gtk.CheckButton("use proxy server")
option_box.pack_start(self._opt_update, False, False)
option_box.pack_start(self._opt_pull, False, False)
option_box.pack_start(self._opt_uncomp, False, False)
+ option_box.pack_start(self._opt_proxy, False, False)
vbox.pack_start(option_box, False, False, 15)
+ if ui.ui().config('http_proxy', 'host', ''):
+ self._opt_proxy.set_active(True)
+ else:
+ self._opt_proxy.set_sensitive(False)
+
# remote cmd
lbl = gtk.Label("Remote Cmd:")
lbl.set_alignment(0, 0.5)
@@ -266,7 +273,7 @@
# verify input
if src == "":
- error_dialog("Source path is empty", "Please enter")
+ error_dialog(self, "Source path is empty", "Please enter")
self._src_input.grab_focus()
return False
@@ -279,6 +286,9 @@ cmdline.append('--uncompressed')
if self._opt_pull.get_active():
cmdline.append('--pull')
+ if not (self._opt_proxy.get_active() and
+ ui.ui().config('http_proxy', 'host', '')):
+ cmdline += ["--config", "http_proxy.host="]
if remotecmd:
cmdline.append('--remotecmd')
cmdline.append(remotecmd)
@@ -297,11 +307,11 @@ dlg.run()
dlg.hide()
except util.Abort, inst:
- error_dialog("Clone aborted", str(inst))
+ error_dialog(self, "Clone aborted", str(inst))
return False
except:
import traceback
- error_dialog("Clone error", traceback.format_exc())
+ error_dialog(self, "Clone error", traceback.format_exc())
return False
self._add_src_to_recent(src)
|
|
@@ -91,6 +91,7 @@ self._commit_clicked, tip='commit'))
return tbbuttons
+
def changed_cb(self, combobox):
model = combobox.get_model()
index = combobox.get_active()
@@ -181,23 +182,56 @@ live = True
return live
+
+ def reload_status(self):
+ success = GStatus.reload_status(self)
+ self._check_merge()
+ return success
+
+
### End of overridable methods ###
+ def _check_merge(self):
+ # disable the checkboxes on the filelist if repo in merging state
+ merged = len(self.repo.workingctx().parents()) > 1
+ cbcell = self.tree.get_column(0).get_cell_renderers()[0]
+ cbcell.set_property("activatable", not merged)
+
+ self.get_toolbutton('Re_vert').set_sensitive(not merged)
+ self.get_toolbutton('_Add').set_sensitive(not merged)
+ self.get_toolbutton('_Remove').set_sensitive(not merged)
+ self.get_toolbutton('_Select').set_sensitive(not merged)
+ self.get_toolbutton('_Deselect').set_sensitive(not merged)
+
+ if merged:
+ # select all changes if repo is merged
+ for entry in self.model:
+ if entry[1] in 'MARD':
+ entry[0] = True
+
+ # pre-fill commit message
+ self.text.get_buffer().set_text('merge')
+
def _commit_clicked(self, toolbutton, data=None):
if not self._ready_message():
return True
- commitable = 'MAR'
- addremove_list = self._relevant_files('?!')
- if len(addremove_list) and self._should_addremove(addremove_list):
- commitable += '?!'
+ if len(self.repo.workingctx().parents()) > 1:
+ # as of Mercurial 1.0, merges must be committed without
+ # specifying file list.
+ self._hg_commit([])
+ else:
+ commitable = 'MAR'
+ addremove_list = self._relevant_files('?!')
+ if len(addremove_list) and self._should_addremove(addremove_list):
+ commitable += '?!'
- commit_list = self._relevant_files(commitable)
- if len(commit_list) > 0:
- self._hg_commit(commit_list)
- else:
- Prompt('Nothing Commited', 'No committable files selected', self).run()
+ commit_list = self._relevant_files(commitable)
+ if len(commit_list) > 0:
+ self._hg_commit(commit_list)
+ else:
+ Prompt('Nothing Commited', 'No committable files selected', self).run()
return True
@@ -268,6 +302,13 @@ u = ui.ui()
u.updateopts(debug=False, traceback=False)
repo = hg.repository(u, path=root)
+
+ # move cwd to repo root if repo is merged, so we can show
+ # all the changed files
+ if len(repo.workingctx().parents()) > 1 and repo.root != cwd:
+ cwd = repo.root
+ repo = hg.repository(u, path=cwd)
+ files = [cwd]
ct = repo.ui.config('tortoisehg', 'commit', 'internal')
if ct != 'internal':
@@ -304,6 +345,9 @@
if __name__ == "__main__":
import sys
+ from hglib import rootpath
+
opts = {}
- opts['root'] = len(sys.argv) > 1 and sys.argv[1] or ''
+ opts['cwd'] = len(sys.argv) > 1 and sys.argv[1] or os.getcwd()
+ opts['root'] = rootpath(opts['cwd'])
run(**opts)
|
@@ -12,7 +12,7 @@ import threading, thread2
import time
from mercurial import hg, ui, util, revlog
-from hglib import hgcmd_toq
+from hglib import hgcmd_toq, toutf, fromutf
from gdialog import *
from vis import treemodel
from vis.colormap import AnnotateColorMap, AnnotateColorSaturation
@@ -315,7 +315,7 @@ except ValueError:
continue
tip, user = self.get_rev_desc(long(revid))
- model.append((revid, text, tip, path))
+ model.append((revid, toutf(text), tip, toutf(path)))
if thread.isAlive():
return True
else:
@@ -336,8 +336,8 @@ if path is not None and model is not None:
iter = model.get_iter(path)
self.currev = model[iter][self.COL_REVID]
- self.curpath = model[iter][self.COL_PATH]
- self.stbar.set_status_text(model[iter][self.COL_TOOLTIP])
+ self.curpath = fromutf(model[iter][self.COL_PATH])
+ self.stbar.set_status_text(toutf(model[iter][self.COL_TOOLTIP]))
def _stop_search(self, button, widget):
num = self.notebook.get_current_page()
@@ -462,14 +462,14 @@ frame.show_all()
hbox = gtk.HBox()
- lbl = gtk.Label(os.path.basename(path) + '@' + revid)
+ 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(path + '@' + revid))
+ hbox, gtk.Label(toutf(path + '@' + revid)))
if hasattr(self.notebook, 'set_tab_reorderable'):
self.notebook.set_tab_reorderable(frame, True)
@@ -498,7 +498,7 @@ if info:
(rpath, node) = info
frev = self.repo.file(rpath).linkrev(node)
- button.set_label('%s@%s' % (rpath, frev))
+ button.set_label(toutf('%s@%s' % (rpath, frev)))
button.show()
button.set_sensitive(True)
label.set_text('Follow Rename:')
@@ -553,10 +553,10 @@
model.clear()
self.stbar.begin()
- self.stbar.set_status_text('hg ' + ' '.join(args[2:]))
+ self.stbar.set_status_text(toutf('hg ' + ' '.join(args[2:])))
hbox = gtk.HBox()
- lbl = gtk.Label(os.path.basename(path) + '@' + str(rev))
+ 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)
@@ -582,7 +582,8 @@ tip, user = self.get_rev_desc(rowrev)
ctx = self.repo.changectx(rowrev)
color = colormap.get_color(ctx, curdate)
- model.append((revid, text, tip, path.strip(), color, user))
+ model.append((revid, toutf(text), tip, toutf(path.strip()),
+ color, toutf(user)))
if thread.isAlive():
return True
else:
|
@@ -22,12 +22,13 @@
import gtk
import gtk.glade
+from gtklib import MessageDialog
def about():
raise "About dialog currently under construction"
-def _message_dialog(type, primary, secondary, buttons=gtk.BUTTONS_OK,
+def _message_dialog(parent, type, primary, secondary, buttons=gtk.BUTTONS_OK,
title="TortoiseHg"):
""" Display a given type of MessageDialog with the given message.
@@ -35,7 +36,7 @@
:param message: the message you want to display.
"""
- dialog = gtk.MessageDialog(flags=gtk.DIALOG_MODAL, type=type,
+ dialog = MessageDialog(parent, flags=gtk.DIALOG_MODAL, type=type,
buttons=buttons)
dialog.set_title(title)
dialog.set_markup('<big><b>' + primary + '</b></big>')
@@ -45,7 +46,7 @@ dialog.destroy()
return response
-def entry_dialog(msg, visible=True, default='', respfunc=None):
+def entry_dialog(parent, msg, visible=True, default='', respfunc=None):
""" Allow a user to enter a text string (username/password)
:param message: the message you want to display.
:param visible: should reponse be visible to user
@@ -53,7 +54,7 @@ :param respfunc: callback function for when dialog exits
:returns if respfunc returns dialog, else return response text
"""
- dialog = gtk.Dialog(flags=gtk.DIALOG_MODAL,
+ dialog = gtk.Dialog(parent=parent, flags=gtk.DIALOG_MODAL,
buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK))
dialog.set_title('TortoiseHg Prompt')
entry = gtk.Entry()
@@ -77,18 +78,19 @@ dialog.destroy()
return text
-def error_dialog(primary, secondary):
+def error_dialog(parent, primary, secondary):
""" Display an error dialog with the given message. """
- return _message_dialog(gtk.MESSAGE_ERROR, primary, secondary)
+ return _message_dialog(parent, gtk.MESSAGE_ERROR, primary, secondary)
-def info_dialog(primary, secondary):
+def info_dialog(parent, primary, secondary):
""" Display an info dialog with the given message. """
- return _message_dialog(gtk.MESSAGE_INFO, primary, secondary)
+ return _message_dialog(parent, gtk.MESSAGE_INFO, primary, secondary)
-def warning_dialog(primary, secondary):
+def warning_dialog(parent, primary, secondary):
""" Display a warning dialog with the given message. """
- return _message_dialog(gtk.MESSAGE_WARNING, primary, secondary)
+ return _message_dialog(parent, gtk.MESSAGE_WARNING, primary, secondary)
-def question_dialog(primary, secondary):
+def question_dialog(parent, primary, secondary):
""" Display a dialog with the given question. """
- return _message_dialog(gtk.MESSAGE_QUESTION, primary, secondary, gtk.BUTTONS_YES_NO)
+ return _message_dialog(parent, gtk.MESSAGE_QUESTION, primary, secondary,
+ gtk.BUTTONS_YES_NO)
|
@@ -29,27 +29,28 @@ from hgext import extdiff
from shlib import shell_notify, set_tortoise_icon, Settings
from thgconfig import ConfigDialog
+from gtklib import MessageDialog
-class SimpleMessage(gtk.MessageDialog):
+
+class SimpleMessage(MessageDialog):
def run(self):
- response = gtk.MessageDialog.run(self)
+ response = MessageDialog.run(self)
self.destroy()
return response
class Prompt(SimpleMessage):
def __init__(self, title, message, parent):
- gtk.MessageDialog.__init__(self, parent, gtk.DIALOG_MODAL,
+ SimpleMessage.__init__(self, parent, gtk.DIALOG_MODAL,
gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE)
self.set_title(title)
self.set_markup('<b>' + message + '</b>')
-
class Confirm(SimpleMessage):
"""Dialog returns gtk.RESPONSE_YES or gtk.RESPONSE_NO
"""
def __init__(self, title, files, parent, primary=None):
- gtk.MessageDialog.__init__(self, parent, gtk.DIALOG_MODAL,
+ SimpleMessage.__init__(self, parent, gtk.DIALOG_MODAL,
gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO)
self.set_title('Confirm ' + title)
if primary is None:
@@ -97,6 +98,7 @@ self.opts = opts
self.main = main
self.tmproot = None
+ self.toolbuttons = {}
self.settings = Settings(self.__class__.__name__)
### Following methods are meant to be overridden by subclasses ###
@@ -171,9 +173,9 @@
def _parse_config(self):
# defaults
- self.fontcomment = 'courier 10'
- self.fontdiff = 'courier 10'
- self.fontlist = 'courier 9'
+ self.fontcomment = 'monospace 10'
+ self.fontdiff = 'monospace 10'
+ self.fontlist = 'monospace 9'
self.diffopts = ''
self.diffcmd = ''
self.diffbottom = ''
@@ -249,9 +251,14 @@ tbutton.set_use_underline(True)
tbutton.set_label(label)
tbutton.connect('clicked', handler, userdata)
+ self.toolbuttons[label] = tbutton
return tbutton
+ def get_toolbutton(self, label):
+ return self.toolbuttons[label]
+
+
def _setup_gtk(self):
self.set_title(self.get_title())
set_tortoise_icon(self, self.get_icon())
|
@@ -53,3 +53,66 @@ def set_pulse_step(self, val):
self.pbar.set_pulse_step(val)
+class MessageDialog(gtk.Dialog):
+ button_map = {
+ gtk.BUTTONS_NONE: None,
+ gtk.BUTTONS_OK: (gtk.STOCK_OK, gtk.RESPONSE_OK),
+ gtk.BUTTONS_CLOSE : (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE),
+ gtk.BUTTONS_CANCEL: (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
+ gtk.BUTTONS_YES_NO : (gtk.STOCK_YES, gtk.RESPONSE_YES,
+ gtk.STOCK_NO, gtk.RESPONSE_NO),
+ gtk.BUTTONS_OK_CANCEL: (gtk.STOCK_OK, gtk.RESPONSE_OK,
+ gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
+ }
+ image_map = {
+ gtk.MESSAGE_INFO : gtk.STOCK_DIALOG_INFO,
+ gtk.MESSAGE_WARNING : gtk.STOCK_DIALOG_WARNING,
+ gtk.MESSAGE_QUESTION : gtk.STOCK_DIALOG_QUESTION,
+ gtk.MESSAGE_ERROR : gtk.STOCK_DIALOG_ERROR,
+ }
+
+ def __init__(self, parent=None, flags=0, type=gtk.MESSAGE_INFO,
+ buttons=gtk.BUTTONS_NONE, message_format=None):
+ gtk.Dialog.__init__(self,
+ parent=parent,
+ flags=flags | gtk.DIALOG_NO_SEPARATOR,
+ buttons=MessageDialog.button_map[buttons])
+ self.set_resizable(False)
+
+ hbox = gtk.HBox()
+ self._image_frame = gtk.Frame()
+ self._image_frame.set_shadow_type(gtk.SHADOW_NONE)
+ self._image = gtk.Image()
+ self._image.set_from_stock(MessageDialog.image_map[type],
+ gtk.ICON_SIZE_DIALOG)
+ self._image_frame.add(self._image)
+ hbox.pack_start(self._image_frame, padding=5)
+
+ lblbox = gtk.VBox(spacing=10)
+ self._primary = gtk.Label("")
+ self._primary.set_alignment(0.0, 0.5)
+ self._primary.set_line_wrap(True)
+ lblbox.pack_start(self._primary)
+
+ self._secondary = gtk.Label()
+ lblbox.pack_end(self._secondary)
+ self._secondary.set_line_wrap(True)
+ hbox.pack_start(lblbox, padding=5)
+
+ self.vbox.pack_start(hbox, False, False, 10)
+ self.show_all()
+
+ def set_markup(self, s):
+ self._primary.set_markup(s)
+
+ def format_secondary_markup(self, message_format):
+ self._secondary.set_markup(message_format)
+
+ def format_secondary_text(self, message_format):
+ self._secondary.set_text(message_format)
+
+ def set_image(self, image):
+ self._image_frame.remove(self._image)
+ self._image = image
+ self._image_frame.add(self._image)
+ self._image.show()
|
@@ -13,7 +13,7 @@ import os
import threading
import Queue
-from hglib import HgThread, hgcmd_toq
+from hglib import HgThread, hgcmd_toq, toutf
from shlib import set_tortoise_icon, get_system_times
class CmdDialog(gtk.Dialog):
@@ -31,11 +31,15 @@
# 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_end(self._button_ok)
-
+ self.action_area.pack_start(self._button_ok)
+
self.connect('delete-event', self._delete)
self.connect('response', self._response)
@@ -82,6 +86,9 @@ """ Ok button clicked handler. """
self.response(gtk.RESPONSE_ACCEPT)
+ def _on_stop_clicked(self, button):
+ self.hgthread.terminate()
+
def _delete(self, widget, event):
return True
@@ -93,10 +100,11 @@ self.hgthread = HgThread(self.cmdline[1:])
self.hgthread.start()
self._button_ok.set_sensitive(False)
+ self._button_stop.set_sensitive(True)
gobject.timeout_add(10, self.process_queue)
def write(self, msg, append=True):
- msg = unicode(msg, 'iso-8859-1')
+ msg = toutf(msg, 'iso-8859-1')
if append:
enditer = self.textbuffer.get_end_iter()
self.textbuffer.insert(enditer, msg)
@@ -112,14 +120,17 @@ while self.hgthread.getqueue().qsize():
try:
msg = self.hgthread.getqueue().get(0)
- msg = unicode(msg, 'iso-8859-1')
- self.textbuffer.insert(enditer, msg)
+ 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("[command interrupted]")
return False # Stop polling this function
else:
return True
|
@@ -207,7 +207,7 @@ if name == 'patchbomb':
break
else:
- error_dialog('Email not enabled',
+ error_dialog(self, 'Email not enabled',
'You must enable the patchbomb extension to use this tool')
self.response(gtk.RESPONSE_CANCEL)
@@ -261,11 +261,11 @@ subjtext = self._subjbox.child.get_text()
if not totext:
- info_dialog('Info required', 'You must specify a recipient')
+ info_dialog(self, 'Info required', 'You must specify a recipient')
self._tobox.grab_focus()
return
if not fromtext:
- info_dialog('Info required', 'You must specify a sender address')
+ info_dialog(self, 'Info required', 'You must specify a sender address')
self._frombox.grab_focus()
return
if not self.repo:
@@ -273,7 +273,7 @@
if self.repo.ui.config('email', 'method', 'smtp') == 'smtp':
if not self.repo.ui.config('smtp', 'host'):
- info_dialog('Info required', 'You must configure SMTP')
+ info_dialog(self, 'Info required', 'You must configure SMTP')
dlg = ConfigDialog(self.root, False)
dlg.show_all()
dlg.focus_field('smtp.host')
|
@@ -2,7 +2,7 @@ import os.path
import sys
import traceback
-import threading
+import threading, thread2
import Queue
from mercurial import hg, ui, util, extensions, commands, hook
from mercurial.repo import RepoError
@@ -33,6 +33,32 @@finally:
demandimport.enable()
+def toutf(s):
+ """
+ Convert a string to UTF-8 encoding
+
+ Based on mercurial.util.tolocal()
+ """
+ for e in ('utf-8', util._encoding):
+ try:
+ return s.decode(e, 'strict').encode('utf-8')
+ except UnicodeDecodeError:
+ pass
+ return s.decode(util._fallbackencoding, 'replace').encode('utf-8')
+
+def fromutf(s):
+ """
+ Convert UTF-8 encoded string to local.
+
+ It's primarily used on strings converted to UTF-8 by toutf().
+ """
+ try:
+ return s.decode('utf-8').encode(util._encoding)
+ except UnicodeDecodeError:
+ pass
+ except UnicodeEncodeError:
+ pass
+ return s.decode('utf-8').encode(util._fallbackencoding)
def rootpath(path=None):
""" find Mercurial's repo root of path """
@@ -110,14 +136,14 @@ traceback.print_exc()
return True
-class HgThread(threading.Thread):
+class HgThread(thread2.Thread):
'''
Run an hg command in a background thread, implies output is being
sent to a rendered text buffer interactively and requests for
feedback from Mercurial can be handled by the user via dialog
windows.
'''
- def __init__(self, args=[], postfunc=None):
+ def __init__(self, args=[], postfunc=None, parent=None):
self.outputq = Queue.Queue()
self.dialogq = Queue.Queue()
self.responseq = Queue.Queue()
@@ -125,7 +151,8 @@ self.args = args
self.ret = None
self.postfunc = postfunc
- threading.Thread.__init__(self)
+ self.parent = parent
+ thread2.Thread.__init__(self)
def getqueue(self):
return self.outputq
@@ -142,7 +169,7 @@ '''Polled every 10ms to serve dialogs for the background thread'''
try:
(prompt, visible, default) = self.dialogq.get_nowait()
- self.dlg = entry_dialog(prompt, visible, default,
+ self.dlg = entry_dialog(self.parent, prompt, visible, default,
self.dialog_response)
except Queue.Empty:
pass
|
@@ -22,6 +22,7 @@ from merge import MergeDialog
from vis import treemodel
from vis.treeview import TreeView
+from hglib import toutf
import gtklib
|
@@ -182,11 +182,11 @@ while q.qsize(): out += q.get(0)
self.hgout = out
except util.Abort, inst:
- error_dialog("Error in %s command" % cmd, "abort: %s" % inst)
+ error_dialog(self, "Error in %s command" % cmd, "abort: %s" % inst)
return False
except:
import traceback
- error_dialog("Error in %s command" % cmd,
+ error_dialog(self, "Error in %s command" % cmd,
"Traceback:\n%s" % traceback.format_exc())
return False
return True
|
@@ -202,10 +202,10 @@ rev = self._rev_input.get_text()
if not rev:
- error_dialog("Can't unmerge", "please select revision to unmerge")
+ error_dialog(self, "Can't unmerge", "please select revision to unmerge")
return
- response = question_dialog("Undo merge",
+ response = question_dialog(self, "Undo merge",
"and checkout revision %s?" % rev)
if response != gtk.RESPONSE_YES:
return
@@ -224,10 +224,10 @@ force = self._chbox_force.get_active()
if not rev:
- error_dialog("Can't merge", "please enter revision to merge")
+ error_dialog(self, "Can't merge", "please enter revision to merge")
return
- response = question_dialog("Really want to merge?",
+ response = question_dialog(self, "Really want to merge?",
"with revision %s" % rev)
if response != gtk.RESPONSE_YES:
return
|
|
@@ -21,7 +21,7 @@ from mercurial.repo import RepoError
from mercurial.node import *
from dialog import error_dialog, question_dialog
-from hglib import HgThread
+from hglib import HgThread, toutf
from shlib import set_tortoise_icon, shell_notify
import gtklib
@@ -34,6 +34,7 @@ self.root = root
self.cwd = cwd
self.selected_path = None
+ self.hgthread = None
self.connect('delete-event', self._delete)
self.set_default_size(600, 400)
@@ -44,6 +45,9 @@ # toolbar
self.tbar = gtk.Toolbar()
self.tips = gtk.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',
@@ -66,6 +70,8 @@ self._verify_clicked,
tip='Validate repository consistency'),
gtk.SeparatorToolItem(),
+ self._stop_button,
+ gtk.SeparatorToolItem(),
]
for btn in tbuttons:
self.tbar.insert(btn, -1)
@@ -96,14 +102,15 @@ vbox.pack_start(self.stbar, False, False, 2)
def _close_clicked(self, *args):
- if threading.activeCount() != 1:
- error_dialog("Can't close now", "command is running")
- else:
- gtk.main_quit()
+ self._do_close()
def _delete(self, widget, event):
- if threading.activeCount() != 1:
- return True
+ self._do_close()
+ return True
+
+ def _do_close(self):
+ if self._cmd_running():
+ error_dialog(self, "Can't close now", "command is running")
else:
gtk.main_quit()
@@ -122,7 +129,7 @@ return tbutton
def _clean_clicked(self, toolbutton, data=None):
- response = question_dialog("Clean repository",
+ response = question_dialog(self, "Clean repository",
"%s ?" % os.path.basename(self.root))
if not response == gtk.RESPONSE_YES:
return
@@ -141,7 +148,7 @@ shell_notify([self.cwd])
def _rollback_clicked(self, toolbutton, data=None):
- response = question_dialog("Rollback repository",
+ response = question_dialog(self, "Rollback repository",
"%s ?" % os.path.basename(self.root))
if not response == gtk.RESPONSE_YES:
return
@@ -156,7 +163,18 @@ cmd = ['verify']
self._exec_cmd(cmd)
- def _exec_cmd(self, cmd, postfunc=None):
+ def _stop_clicked(self, toolbutton, data=None):
+ if self.hgthread and self.hgthread.isAlive():
+ self.hgthread.terminate()
+ self._stop_button.set_sensitive(False)
+
+ def _exec_cmd(self, cmd, postfunc=None):
+ if self._cmd_running():
+ error_dialog(self, "Can't run now",
+ "Pleas try again after the previous command is completed")
+ return
+
+ self._stop_button.set_sensitive(True)
cmdline = cmd
cmdline.append('--verbose')
cmdline.append('--repository')
@@ -172,8 +190,14 @@ self.stbar.begin()
self.stbar.set_status_text('hg ' + ' '.join(cmdline))
+ def _cmd_running(self):
+ if self.hgthread and self.hgthread.isAlive():
+ return True
+ else:
+ return False
+
def write(self, msg, append=True):
- msg = unicode(msg, 'iso-8859-1')
+ msg = toutf(msg)
if append:
enditer = self.textbuffer.get_end_iter()
self.textbuffer.insert(enditer, msg)
@@ -191,11 +215,14 @@ self.write(msg)
except Queue.Empty:
pass
- if threading.activeCount() == 1:
+ if self._cmd_running():
+ return True
+ else:
self.stbar.end()
+ self._stop_button.set_sensitive(False)
+ if self.hgthread.return_code() is None:
+ self.write("[command interrupted]")
return False # Stop polling this function
- else:
- return True
def run(cwd='', root='', **opts):
dialog = RecoveryDialog(cwd, root)
|
@@ -157,7 +157,7 @@ check if server is running, or to terminate if running
'''
if gservice and not gservice.stopped:
- if question_dialog("Really Exit?",
+ if question_dialog(self, "Really Exit?",
"Server process is still running\n" +
"Exiting will stop the server.") != gtk.RESPONSE_YES:
return False
@@ -223,7 +223,7 @@ except:
try: port = int(self.defport)
except: port = 8000
- error_dialog("Invalid port 2048..65535", "Defaulting to " +
+ error_dialog(self, "Invalid port 2048..65535", "Defaulting to " +
self.defport)
global gservice
@@ -250,7 +250,7 @@ self._queue.put(msg)
def _write(self, msg, append=True):
- msg = unicode(msg, 'iso-8859-1')
+ msg = hglib.toutf(msg)
if append:
enditer = self.textbuffer.get_end_iter()
self.textbuffer.insert(enditer, msg)
|
@@ -26,6 +26,7 @@ from mercurial import cmdutil, util, ui, hg, commands, patch
from hgext import extdiff
from shlib import shell_notify
+from hglib import toutf
from gdialog import *
class GStatus(GDialog):
@@ -182,7 +183,7 @@ self._menus['I'] = ignored_menu
self._menus['!'] = deleted_menu
- self.model = gtk.ListStore(bool, str, str)
+ self.model = gtk.ListStore(bool, str, str, str)
self.model.set_sort_func(1001, self._sort_by_stat)
self.model.set_default_sort_func(self._sort_by_stat)
@@ -344,7 +345,7 @@ if self.test_opt(ct[0])] or changetypes) :
for file in changes:
file = util.localpath(file)
- self.model.append([file in recheck, char, file])
+ self.model.append([file in recheck, char, toutf(file), file])
selection = self.tree.get_selection()
selected = False
@@ -472,7 +473,7 @@ difftext.seek(0)
iter = buffer.get_start_iter()
for line in difftext:
- line = util.fromlocal(line)
+ line = toutf(line)
if line.startswith('---') or line.startswith('+++'):
buffer.insert_with_tags_by_name(iter, line, 'header')
elif line.startswith('-'):
@@ -489,7 +490,7 @@ difftext.close()
if self.showdiff_toggle.get_active():
- files = [self.model[iter][2] for iter in self.tree.get_selection().get_selected_rows()[1]]
+ files = [self.model[iter][3] for iter in self.tree.get_selection().get_selected_rows()[1]]
if force or files != self._last_files:
self._last_files = files
self._hg_call_wrapper('Diff', dohgdiff)
@@ -668,7 +669,7 @@
def _relevant_files(self, stats):
- return [item[2] for item in self.model if item[0] and item[1] in stats]
+ return [item[3] for item in self.model if item[0] and item[1] in stats]
def _context_menu_act(self, menuitem, handler):
|
|
|
@@ -19,8 +19,8 @@ import threading
from mercurial import hg, ui, util, extensions
from mercurial.repo import RepoError
-from dialog import error_dialog, question_dialog
-from hglib import HgThread
+from dialog import error_dialog, question_dialog, info_dialog
+from hglib import HgThread, toutf
import shlib
import gtklib
@@ -33,6 +33,7 @@ self.root = root
self.cwd = cwd
self.selected_path = None
+ self.hgthread = None
# persistent app data
self._settings = shlib.Settings('synch')
@@ -54,6 +55,9 @@ # toolbar
self.tbar = gtk.Toolbar()
self.tips = gtk.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',
@@ -83,6 +87,8 @@ tip='Email local outgoing changes to'
' one or more recipients'),
gtk.SeparatorToolItem(),
+ self._stop_button,
+ gtk.SeparatorToolItem(),
self._toolbutton(gtk.STOCK_PREFERENCES,
'Configure',
self._conf_clicked,
@@ -250,7 +256,7 @@ flags = ['--clean']
msg = 'Lose all changes in your working directory?'
warning += ', requires clean checkout'
- if question_dialog(msg, warning) != gtk.RESPONSE_YES:
+ if question_dialog(self, msg, warning) != gtk.RESPONSE_YES:
return
self.write("", False)
@@ -271,6 +277,10 @@ self._pull_update = gtk.CheckMenuItem("Update to new tip")
menu.append(self._pull_update)
+ # restore states from previous session
+ st = self._settings.get_value('_pull_update_state', False)
+ self._pull_update.set_active(st)
+
menu.show_all()
return menu
@@ -306,18 +316,24 @@ dialog.destroy()
def _close_clicked(self, toolbutton, data=None):
- if threading.activeCount() != 1:
- error_dialog("Can't close now", "command is running")
+ self._do_close()
+
+ def _do_close(self):
+ if self._cmd_running():
+ error_dialog(self, "Can't close now", "command is running")
else:
+ self._save_settings()
gtk.main_quit()
+ def _save_settings(self):
+ self._settings.set_value('_pull_update_state',
+ self._pull_update.get_active())
+ self._settings.write()
+
def _delete(self, widget, event):
- if threading.activeCount() != 1:
- error_dialog("Can't close now", "command is running")
- return True
- else:
- gtk.main_quit()
-
+ self._do_close()
+ return True
+
def _toolbutton(self, stock, label, handler,
menu=None, userdata=None, tip=None):
if menu:
@@ -372,7 +388,7 @@ def _email_clicked(self, toolbutton, data=None):
path = self._pathtext.get_text()
if not path:
- info_dialog('No repository selected',
+ info_dialog(self, 'No repository selected',
'Select a peer repository to compare with')
self._pathbox.grab_focus()
return
@@ -407,7 +423,19 @@ cmd.append('--newest-first')
self._exec_cmd(cmd)
+ def _stop_clicked(self, toolbutton, data=None):
+ if self._cmd_running():
+ self.hgthread.terminate()
+ self._stop_button.set_sensitive(False)
+
def _exec_cmd(self, cmd):
+ if self._cmd_running():
+ error_dialog(self, "Can't run now",
+ "Pleas try again after the previous command is completed")
+ return
+
+ self._stop_button.set_sensitive(True)
+
proxy_host = ui.ui().config('http_proxy', 'host', '')
use_proxy = self._use_proxy.get_active()
text_entry = self._pathbox.get_child()
@@ -424,13 +452,19 @@
# execute command and show output on text widget
gobject.timeout_add(10, self.process_queue)
- self.hgthread = HgThread(cmdline)
+ self.hgthread = HgThread(cmdline, parent=self)
self.hgthread.start()
self.stbar.begin()
self.stbar.set_status_text('hg ' + ' '.join(cmd + [remote_path]))
self._add_src_to_recent(remote_path)
+ def _cmd_running(self):
+ if self.hgthread and self.hgthread.isAlive():
+ return True
+ else:
+ return False
+
def _add_src_to_recent(self, src):
if os.path.exists(src):
src = os.path.abspath(src)
@@ -448,10 +482,11 @@ self.pathlist.append([p])
def write(self, msg, append=True):
- msg = unicode(msg, 'iso-8859-1')
+ 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)
@@ -467,13 +502,16 @@ except Queue.Empty:
pass
- if threading.activeCount() == 1:
+ if self._cmd_running():
+ return True
+ else:
# Update button states
self.update_buttons()
self.stbar.end()
+ self._stop_button.set_sensitive(False)
+ if self.hgthread.return_code() is None:
+ self.write("[command interrupted]")
return False # Stop polling this function
- else:
- return True
def run(cwd='', root='', files=[], **opts):
dialog = SynchDialog(cwd, root, files)
|
@@ -176,25 +176,26 @@
# verify input
if name == "":
- error_dialog("Tag input is empty", "Please enter tag name")
+ error_dialog(self, "Tag input is empty", "Please enter tag name")
self._tag_input.grab_focus()
return False
if use_msg and not message:
- error_dialog("Custom commit message is empty", "Please enter commit message")
+ error_dialog(self, "Custom commit message is empty",
+ "Please enter commit message")
self._commit_message.grab_focus()
return False
# add tag to repo
try:
self._add_hg_tag(name, rev, message, is_local, force=force)
- info_dialog("Tagging completed", "Tag '%s' has been added" % name)
+ info_dialog(self, "Tagging completed", "Tag '%s' has been added" % name)
self._refresh()
except util.Abort, inst:
- error_dialog("Error in tagging", str(inst))
+ error_dialog(self, "Error in tagging", str(inst))
return False
except:
import traceback
- error_dialog("Error in tagging", traceback.format_exc())
+ error_dialog(self, "Error in tagging", traceback.format_exc())
return False
def _do_rm_tag(self):
@@ -206,7 +207,7 @@
# verify input
if name == "":
- error_dialog("Tag name is empty", "Please select tag name to remove")
+ error_dialog(self, "Tag name is empty", "Please select tag name to remove")
self._tag_input.grab_focus()
return False
@@ -217,14 +218,14 @@
try:
self._rm_hg_tag(name, message, is_local)
- info_dialog("Tagging completed", "Tag '%s' has been removed" % name)
+ info_dialog(self, "Tagging completed", "Tag '%s' has been removed" % name)
self._refresh()
except util.Abort, inst:
- error_dialog("Error in tagging", str(inst))
+ error_dialog(self, "Error in tagging", str(inst))
return False
except:
import traceback
- error_dialog("Error in tagging", traceback.format_exc())
+ error_dialog(self, "Error in tagging", traceback.format_exc())
return False
|
@@ -33,7 +33,7 @@ except RepoError:
repo = None
if configrepo:
- error_dialog('No repository found', 'no repo at ' + root)
+ error_dialog(self, 'No repository found', 'no repo at ' + root)
self.response(gtk.RESPONSE_CANCEL)
# Catch close events
@@ -301,7 +301,7 @@
def _response(self, widget, response_id):
if self.dirty:
- if question_dialog('Quit without saving?',
+ if question_dialog(self, 'Quit without saving?',
'Yes to abandon changes, No to continue') != gtk.RESPONSE_YES:
widget.emit_stop_by_name('response')
@@ -584,7 +584,7 @@ f.write(str(self.ini))
f.close()
except IOError, e:
- error_dialog('Unable to write back configuration file', str(e))
+ error_dialog(self, 'Unable to write back configuration file', str(e))
self._btn_apply.set_sensitive(False)
self.dirty = False
|
@@ -13,6 +13,8 @@ import Queue
import win32trace
+from hglib import toutf
+
class TraceLog():
def __init__(self):
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
@@ -111,7 +113,7 @@ self.queue.put(msg)
def write(self, msg, append=True):
- msg = unicode(msg, 'iso-8859-1')
+ msg = toutf(msg)
if append:
enditer = self.textbuffer.get_end_iter()
self.textbuffer.insert(enditer, msg)
|
@@ -172,10 +172,10 @@ overwrite = self._overwrite.get_active()
if not rev:
- error_dialog("Can't update", "please enter revision to update to")
+ error_dialog(self, "Can't update", "please enter revision to update to")
return
- response = question_dialog("Really want to update?",
+ response = question_dialog(self, "Really want to update?",
"to revision %s" % rev)
if response != gtk.RESPONSE_YES:
return
|
@@ -29,6 +29,24 @@ MARKED = 12
FGCOLOR = 13
+# FIXME:
+# this function is a copy of hglib.touft(), but I've
+# trouble importing hglib (resides one dir level above )
+# into this module.
+#
+# Note: Python 2.5's new import syntax causes problem
+# when importing this module from command line.
+def toutf(s):
+ """
+ Convert a string to UTF-8 encoding
+ """
+ for e in ('utf-8', util._encoding):
+ try:
+ return s.decode(e, 'strict').encode('utf-8')
+ except UnicodeDecodeError:
+ pass
+ return s.decode(util._fallbackencoding, 'replace').encode('utf-8')
+
class TreeModel(gtk.GenericTreeModel):
def __init__ (self, repo, graphdata, color_func):
@@ -85,15 +103,15 @@ ctx = self.repo.changectx(revid)
summary = ctx.description().replace('\0', '')
- summary = unicode(summary.split('\n')[0], 'latin-1', 'replace')
- summary = gobject.markup_escape_text(summary)
+ summary = summary.split('\n')[0]
+ summary = gobject.markup_escape_text(toutf(summary))
node = self.repo.lookup(revid)
- tags = ', '.join(self.repo.nodetags(node))
+ tags = toutf(', '.join(self.repo.nodetags(node)))
if '<' in ctx.user():
- author = self.author_re.sub('', ctx.user()).strip(' ')
+ author = toutf(self.author_re.sub('', ctx.user()).strip(' '))
else:
- author = util.shortuser(ctx.user())
+ author = toutf(util.shortuser(ctx.user()))
date = strftime("%Y-%m-%d %H:%M:%S", gmtime(ctx.date()[0]))
|
@@ -14,6 +14,7 @@ import re
from graphcell import CellRendererGraph
from revgraph import *
+from mercurial.node import hex
class TreeView(gtk.ScrolledWindow):
@@ -89,6 +90,11 @@ Case insensitive
"""
key = key.lower()
+
+ node = hex(model.get_value(iter, treemodel.REVISION)[treemodel.NODE])
+ if node.startswith(key):
+ return False
+
for col in (treemodel.REVID, treemodel.TAGS, treemodel.COMMITER,
treemodel.MESSAGE):
if key in model.get_value(iter, col).lower():
|
Loading...