Commits

Peter Arrenbrecht  committed 12d443a Merge

merge with default

  • Participants
  • Parent commits bd649f9, 3bbe0ec
  • Branches hg-crew-tip

Comments (0)

Files changed (45)

-syntax: glob
-
-*.orig
-*.rej
-*.pyc
-tortoise/__version__.py
-build/
-dist/
-Output/
-.*.swp
-Thumbs.db
+syntax: glob
+
+*.orig
+*.rej
+*.pyc
+tortoise/__version__.py
+build/
+dist/
+Output/
+.*.swp
+Thumbs.db
 5a9d20cfcb2911b5a35234f38a7897c9c654c9d5 0.4rc1
 dc4f96864ea7d0a48d831a05695b80001e226db5 0.4rc2
 e677decc9814e94fe3b325ec13077a01e1ccbb87 0.4rc2
+e2211f1985b01b1edd3fc1abe0b7c97fb37fd9d1 0.4rc3
+864497951b6b801cfacbac16eec5b7edb4f1be3c 0.4rc4
+f627244263631682216716cde477d05bebc0d934 0.4
+491a94666fc3498827066b8aa65aab34d3a3e623 0.4.1
 
   The precise terms and conditions for copying, distribution and
 modification follow.
-
+
 		    GNU GENERAL PUBLIC LICENSE
    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 
     License.  (Exception: if the Program itself is interactive but
     does not normally print such an announcement, your work based on
     the Program is not required to print an announcement.)
-
+
 These requirements apply to the modified work as a whole.  If
 identifiable sections of that work are not derived from the Program,
 and can be reasonably considered independent and separate works in
 access to copy the source code from the same place counts as
 distribution of the source code, even though third parties are not
 compelled to copy the source along with the object code.
-
+
   4. You may not copy, modify, sublicense, or distribute the Program
 except as expressly provided under this License.  Any attempt
 otherwise to copy, modify, sublicense or distribute the Program is
 
 This section is intended to make thoroughly clear what is believed to
 be a consequence of the rest of this License.
-
+
   8. If the distribution and/or use of the Program is restricted in
 certain countries either by patents or by copyrighted interfaces, the
 original copyright holder who places the Program under this License
 POSSIBILITY OF SUCH DAMAGES.
 
 		     END OF TERMS AND CONDITIONS
-
+
 	    How to Apply These Terms to Your New Programs
 
   If you develop a new program, and you want it to be of the greatest

File ReleaseNotes.txt

-                    Release Notes for TortoiseHg
-
-This file contains last minute notes to users about the releases, which may not
-be included in the documentation or README files included with the distribution
-kits.  It also contains change information, for users who are interested in
-what bugs have been fixed, and what features have been added in the current
-version.
-
-
-New features in 0.4
-    
-  * Added user config 'tortoisehg.overlayicons' [True|False|localdisks],
-    to enable/disable overlay icons in selected repos. The 'localdisks' 
-    global option disables overlay icons for repos reside on network drives.
-
-  * Changeset viewer shows 'MAR' file status and uses background threads
-    to load changeset diffs. File list has been moved to the left hand
-    side.
-
-  * Added 'strip' and 'backout' functions to history browser.
-
-  * Two convenience functions added to Synchronize dialog: 'View Pulled
-    Changes', and 'Update to Tip'. 
-    
-  * Added support for Fetch extension to Synchronize dialog [ 1914855 ].
-
-  * Grep searches in Datamine dialog can now be interrupted.
-
-  * Recall recently committed messages in native Commit dialog
-
-  * Recall recently accessed source and destination paths in Synchronize
-    and Clone dialogs
-
-  * Add column for user names on annotate pages of Datamine dialog.
-
-  * Hgk ('Revision Graph') is officially replaced by TortoiseHg's 
-    history browser.
-
-  * Installer now requires admin priviledges in order to prevent an
-    upgrade from requiring two reboots. 
-
-  * New TortoiseHg logo in About dialog, contributed by Peer Sommerlund.
-
-  * Updated Hg icon (on context menu and dialogs) to new droplet design 
-    from Mercurial 1.0
-
-  * Several minor bugfixes and improvements.
-
-Bug fixes in 0.4:
-
-  * TortoiseHg program groups now read 'hgproc' with hg.ico.
-    In earlier versions, it used 'Python' with python.ico
-  * Fixed random crashes on web server.
-  * Fixed addremove behavior in Commit dialog
-  * [ 1884919 ] Change Log hscroller
-  * [ 1925985 ] HTTP port field not effective
-  * [ 1914859 ] Global options should show up more often
-  * [ 1914550 ] Changelog: Problems with german umlaut characters
-  * [ 1902446 ] Commit claims file not under root while kdiff is open.
-  * [ 1895443 ] Overlay: ThreadingModel registry setting
-  * [ 1892791 ] Windows Explorer painfully slow for network drives
-
-Changes and bug fixes since 0.4RC1:
-
-  * Added buttons to stop command execution in Synchronize, Recovery,
-    as well as any dialogs that use hgcmd dialog, including Update and 
-    Clone dialogs.
-  * Show progress on status bar when updating changeset viewer.
-  * Support Mercurial's HGENCODING environment variable.
-  * [ Feature 1944469 ] Save and recall pull-update option in Synchronize
-    dialog across sessions.
-  * [ Bug 1939794 ] Unable to Merge changes with builtin commit UI.
-  * [ Bug 1941545 ] Clone log window doesn't scroll.
-  * [ Bug 1943382 ] hgproc.bat not executable without "installer"
-  * [ Bug 1941368 ] Configure Repository "Test" button results broken.
-  * [ Bug 1939911 ] Modal Dialogs aren't staying on top on application switch
-  * [ Bug 1941376 ] hgtk with no parameters gives no help.
-  * [ Bug 1937966 ] Changelog: utf8 messages handled incorrectly
-  * [ Bug 1942777 ] National characters are not handled correctly.
-
-Fixes in Mercurial since 0.3:
-
-  * qimport fixed on Windows
-  * new built-in filemerge system replaces hgmerge patches
-  * many fixes for keyword extension
-  * new -U (context lines) argument for diff and qdiff commands
-
-New features in 0.3
-
-  * Major improvements to changelog browser.  It is now good enough to
-    deprecate both hgk and hgview.  Neither are bundled with the 0.3
-    binary installer, but both can be added by the user if they wish.
-    Support for external revision log viewers will be dropped in 0.4.
-
-  * The new changelog browser supports filtering by file pattern,
-    keywords, dates, and branches.  It is capable of graphing both the
-    repository changelog and individual filelogs.  Changeset coloring by
-    author is optional (tortoisehg.authorcolor).  All changeset graphing
-    is done incrementally in batches (tortoisehg.graphlimit: 500)
-
-  * New DataMine application for searching history (hg grep) and
-    inspecting file histories (hg annotate).  This new application is
-    tabbed to facilitate debugging sessions where search results and
-    annotations can be grouped together for easy cross-reference.
-
-  * New changeset browser, supports multiple parents intrinsically and
-    supports a number of file-revision features (view at revision, save
-    at revision, annotate at revision, revert to revision, etc).  The
-    new changeset browser is also integrated into the changelog browser.
-
-  * Standardized window layouts.  Close buttons have been moved to the
-    toolbar.  Dialogs that use progress bars now use a standard status
-    bar/progress bar widget.  Tooltips have been added.
-
-  * Hgtk wrapper application for launching TortoiseHg dialogs from the
-    command line
-
-  * Support for an external visual editor: tortoisehg.editor.  Takes
-    precedence over ui.editor when viewing files with TortoiseHg
-
-  * Performance improvements in Mercurial itself (cset 0973501e5f4a)
-
-  * New installer bitmap from Peer Sommerlund
-
-  * Misc: The Synchronize dialog has been improved.  The Web Serve
-    dialog no longer requires a subprocess to run the web server.  The
-    configuration dialog has a number of bug fixes for the paths tab,
-    and now has separators in the drop-down boxes for the varying value
-    types (current, suggested, history). Http authentication has been
-    fixed.  The hg integration library has seen major cleanups.
-
-Bug Fixes in 0.3:
-
-  * [ 1863086 ] "Revision Graph" fail on UNC path
-    Fixed by removing hgk from base install.  Integrated log viewer
-    is UNC path safe.
-  * [ 1851395 ] Total Commander problem
-  * [ 1882074 ] global name 'p' is not defined
-  * [ 1854443 ] View changelog fails
-
-New features in 0.2
-
-  * Gtools has been integrated into TortoiseHg proper. It is no longer
-    bundled as a Mercurial extension. The graphlog extension is now enabled
-    again by default (only usable from the CLI, however).
-      
-  * Context menu icons, application window icons. The context menu has been
-    simplified.
-      
-  * The changelog browser has a number of new features (filters and context
-    menu options). The tag browser and changelog tagging features have been
-    merged into this tool.
-      
-  * Hgview is now the default history viewer, hgk is being deprecated.
-   
-  * An email dialog for interfacing with the patchbomb extension. It can be
-    reached from the synchronize dialog and from the changelog browser.
-     
-  * A new configuration tool (replacing hg-config dialogs) that allows you
-    to configure TortoiseHg and Mercurial.
-      
-  * Most dialogs now use HgThread and GtkUI to run hg commands. These 
-    classes run the command in a background thread and provide GUI prompts
-    for when user interaction is necessary (http web auth, etc). For some 
-    commands, it also provides a progress bar.
-      
-  * A preview of the new Mercurial merge back end. The python hgmerge.py 
-    script is being integrated into Mercurial, and this installer has a
-    preview of how that will work. You need to unset any ui.merge in your
-    Mercurial.ini file in order for it to work properly. If you don't 
-    configure anything it will use simplemerge to automatically perform 
-    merges. If conflicts are found it falls back to kdiff3 to resolve 
-    them interactively.
-      
-  * Slight improvement on speed of overlay icons display.
-    
-  * A new 'about' dialog.
-
-Bugs fixed in 0.2
-
-  * [SF Bug #1851395] Overlay icons and context menus are no longer 
-    restricted to MS-Explorer. So other file managers, such as Total 
-    Commander, should be supported.
-      
-  * [SF Bug #1844722] Users can now create repositories inside repository
-     via the context menu.
-
-Changes since 0.2rc1
-
-  - N/A -
-
-
+                    Release Notes for TortoiseHg
+
+This file contains last minute notes to users about the releases, which may not
+be included in the documentation or README files included with the distribution
+kits.  It also contains change information, for users who are interested in
+what bugs have been fixed, and what features have been added in the current
+version.
+
+New features and improvement in 0.4.1
+
+  * Installer-only release to link with Mercurial 1.0.2
+
+New features and improvement in 0.4
+
+  * Updated to work, and link, with Mercurial 1.0.1
+
+  * Explorer shell extensions:
+    - Added user config option 'tortoisehg.overlayicons' to enable/disable
+      display of overlay icons in selected repos.
+
+      Available options:
+        True:
+          Show overlay icons
+        False:
+          Don't show overlay icons
+        localdisks:
+          [global (user) setting only]
+          Don't show overlay icons for repos reside on network drives.
+
+    - Create .hgignore file automatically when initializing new repo
+      via 'Initialize new repo' context menu.
+
+  * Hgk ('Revision Graph' on Explorer's context menu), better known as
+    'hg view', is officially replaced by TortoiseHg's changelog viewer
+    ('View Changelog').
+
+    Note: Hgk may be reinstated by user, if necessary. Though it would
+          need some work to setup.
+
+  * Changelog (History) Viewer:
+    - Added 'strip' and 'backout' functions to file context menu.
+    - Loading of changeset data (file list of diff chunks) is done in
+      background to improve response.
+    - Changeset window shows 'MAR' file status.
+    - File list has been moved to the left hand side.
+
+  * Synchronize dialog:
+    - Added 'Stop' button to abort command executions.
+    - Added support for Fetch extension, as Pull's 'Do fetch' option [ 1914855 ].
+    - Added buttons to 'View Pulled Changes' and 'Update to Tip'.
+    - Recall source and destination paths accessed in recent sessions.
+    - Recall Pull's 'Update to new tip' option setting from previous session
+      [ 1944469 ].
+
+  * Datamine dialog:
+    - Added 'Stop' button to abort grep searches.
+    - Added column for user names on annotate pages.
+
+  * Commit dialog (internal, _not_ Qct):
+    - Recall commit messages of recent commits.
+    - Fixed handlng of merged repo per new Hg behavior (must commit all
+      files in a merged repo)
+
+  * Clone dialog:
+    - Recall source and destination paths accessed in recent sessions.
+    - Cloning can now be aborted with the new 'Stop' button in HgCmd dialog.
+
+  * Recovery dialog:
+    - Added 'Stop' button to abort command executions.
+
+  * Added 'Stop' button to abort command executions in HgCmd dialog.
+    This applies to including Update, Clone and Commit dialogs, which
+    utilize HgCmd dialog to perform respective operations.
+
+  * Unicode handling:
+    - Improved handling of UTF strings in Mercurial's metadata (commit
+      message, author, etc).
+    - Support Mercurial's HGENCODING environment variable.
+
+  * Hgtk:
+    - Simplified installation on Unix/Linux systems.
+    - Confirm presence of critical Python modules, i.e. PyGTK and Mercurial.
+
+  * Logos and icons:
+    - Updated Hg icon (on context menu and dialogs) to new droplet design
+      introduced in Mercurial 1.0
+    - New TortoiseHg logo (in About dialog) by Peer Sommerlund.
+    - Several new menu icons by Peer Sommerlund, with better Windows
+      integration. The corresponding SVG source is also available in
+      TortoiseHg source tree.
+
+  * Several other bugfixes and UI improvements.
+
+Bug fixes in 0.4:
+
+  * Explorer shell extensions:
+    - Register context menu and overlay icon extensions onto the Explorer's
+      approved list.
+    - Fixed ThreadingModel registry setting per MS doc [ 1895443 ]
+  * TortoiseHg program groups now read 'hgproc' with hg.ico (in earlier
+    versions, it used 'Python' with python.ico)
+  * Make modal dialogs stay on top of their respective parent application
+    (issue triggered by a bug in PyGTK).
+  * Fixed random crashes in web server.
+  * Fixed addremove behavior in Commit dialog.
+  * Activated target revision option in Synchronize window that had been
+    dormant so far (as reported by Doug Philips).
+  * Terminate all backgrounded searches in Datamine window upon exit, so
+    the associated Python process may terminate immediately too.
+  * [ 1884919 ] Change Log hscroller
+  * [ 1925985 ] HTTP port field not effective
+  * [ 1914859 ] Global options should show up more often
+  * [ 1914550 ] Changelog: Problems with german umlaut characters
+  * [ 1902446 ] Commit claims file not under root while kdiff is open.
+  * [ 1892791 ] Windows Explorer painfully slow for network drives
+
+Changes and bug fixes since 0.4RC4:
+
+  * Fixed traceback when revert file in changeset or log windows.
+  * Fixed traceback when testing paths in Configure window.
+
+Changes and bug fixes since 0.4RC3:
+
+  * Activated target revision option in Synchronize window that had been
+    dormant so far (as reported by Doug Philips).
+  * Terminate all backgrounded searches in Datamine window upon exit, so
+    the associated Python process may terminate immediately too.
+  * New icons by Peer Sommerlund for configuration windows to represent
+    repo and user config respectively.
+  * Theme improvement in the Configuration windows (by Peter Ruibal).
+  * Detect PyGtk and Mercurial installation more accurately in Hgtk
+  * Removed 'square-boxes' in license window (of About window) caused by
+    extra form-feed characters.
+
+Changes and bug fixes since 0.4RC2:
+
+  * Fixed traceback in tracelog, which was broken in 0.4RC2.
+  * Right-click to diff/visual-diff to selected changeset, which replaced
+    the earlier diff-to-marked function.
+  * Create .hgignore file automatically when initializing new repo.
+  * Fix traceback when users try to enable internal commit dialog with
+    an empty 'commit' in mercurial.ini's 'tortoisehg' section.
+  * Handle empty cmd.differ entries in hgrc like hg does
+  * Register context menu and overlay icon extension onto the Explorer's
+    Approved list.
+  * Fixed UTF-8 encoding errors in hgcmd and several error message dialogs.
+  * New transparent TortoiseHg logo in About dialog, again by Peer Sommerlund.
+  * New 32x32 icons for dialogs to provide nicer icons when navigating
+    through the applications with Alt-Tab on Windows.
+  * Minor improvement/fixes on hgtk to simplify installation on *nix systems.
+
+Changes and bug fixes since 0.4RC1:
+
+  * Added buttons to stop command execution in Synchronize, Recovery,
+    as well as any dialogs that use hgcmd dialog, including Update and
+    Clone dialogs.
+  * Show progress on status bar when updating changeset viewer.
+  * Support Mercurial's HGENCODING environment variable.
+  * [ Feature 1944469 ] Save and recall pull-update option in Synchronize
+    dialog across sessions.
+  * [ Bug 1939794 ] Unable to Merge changes with builtin commit UI.
+  * [ Bug 1941545 ] Clone log window doesn't scroll.
+  * [ Bug 1943382 ] hgproc.bat not executable without "installer"
+  * [ Bug 1941368 ] Configure Repository "Test" button results broken.
+  * [ Bug 1939911 ] Modal Dialogs aren't staying on top on application switch
+  * [ Bug 1941376 ] hgtk with no parameters gives no help.
+  * [ Bug 1937966 ] Changelog: utf8 messages handled incorrectly
+  * [ Bug 1942777 ] National characters are not handled correctly.
+
+Fixes in Mercurial since 0.3:
+
+  * qimport fixed on Windows
+  * new built-in filemerge system replaces hgmerge patches
+  * many fixes for keyword extension
+  * new -U (context lines) argument for diff and qdiff commands
+
+New features in 0.3
+
+  * Major improvements to changelog browser.  It is now good enough to
+    deprecate both hgk and hgview.  Neither are bundled with the 0.3
+    binary installer, but both can be added by the user if they wish.
+    Support for external revision log viewers will be dropped in 0.4.
+
+  * The new changelog browser supports filtering by file pattern,
+    keywords, dates, and branches.  It is capable of graphing both the
+    repository changelog and individual filelogs.  Changeset coloring by
+    author is optional (tortoisehg.authorcolor).  All changeset graphing
+    is done incrementally in batches (tortoisehg.graphlimit: 500)
+
+  * New DataMine application for searching history (hg grep) and
+    inspecting file histories (hg annotate).  This new application is
+    tabbed to facilitate debugging sessions where search results and
+    annotations can be grouped together for easy cross-reference.
+
+  * New changeset browser, supports multiple parents intrinsically and
+    supports a number of file-revision features (view at revision, save
+    at revision, annotate at revision, revert to revision, etc).  The
+    new changeset browser is also integrated into the changelog browser.
+
+  * Standardized window layouts.  Close buttons have been moved to the
+    toolbar.  Dialogs that use progress bars now use a standard status
+    bar/progress bar widget.  Tooltips have been added.
+
+  * Hgtk wrapper application for launching TortoiseHg dialogs from the
+    command line
+
+  * Support for an external visual editor: tortoisehg.editor.  Takes
+    precedence over ui.editor when viewing files with TortoiseHg
+
+  * Performance improvements in Mercurial itself (cset 0973501e5f4a)
+
+  * New installer bitmap from Peer Sommerlund
+
+  * Misc: The Synchronize dialog has been improved.  The Web Serve
+    dialog no longer requires a subprocess to run the web server.  The
+    configuration dialog has a number of bug fixes for the paths tab,
+    and now has separators in the drop-down boxes for the varying value
+    types (current, suggested, history). Http authentication has been
+    fixed.  The hg integration library has seen major cleanups.
+
+Bug Fixes in 0.3:
+
+  * [ 1863086 ] "Revision Graph" fail on UNC path
+    Fixed by removing hgk from base install.  Integrated log viewer
+    is UNC path safe.
+  * [ 1851395 ] Total Commander problem
+  * [ 1882074 ] global name 'p' is not defined
+  * [ 1854443 ] View changelog fails
+
+New features in 0.2
+
+  * Gtools has been integrated into TortoiseHg proper. It is no longer
+    bundled as a Mercurial extension. The graphlog extension is now enabled
+    again by default (only usable from the CLI, however).
+
+  * Context menu icons, application window icons. The context menu has been
+    simplified.
+
+  * The changelog browser has a number of new features (filters and context
+    menu options). The tag browser and changelog tagging features have been
+    merged into this tool.
+
+  * Hgview is now the default history viewer, hgk is being deprecated.
+
+  * An email dialog for interfacing with the patchbomb extension. It can be
+    reached from the synchronize dialog and from the changelog browser.
+
+  * A new configuration tool (replacing hg-config dialogs) that allows you
+    to configure TortoiseHg and Mercurial.
+
+  * Most dialogs now use HgThread and GtkUI to run hg commands. These
+    classes run the command in a background thread and provide GUI prompts
+    for when user interaction is necessary (http web auth, etc). For some
+    commands, it also provides a progress bar.
+
+  * A preview of the new Mercurial merge back end. The python hgmerge.py
+    script is being integrated into Mercurial, and this installer has a
+    preview of how that will work. You need to unset any ui.merge in your
+    Mercurial.ini file in order for it to work properly. If you don't
+    configure anything it will use simplemerge to automatically perform
+    merges. If conflicts are found it falls back to kdiff3 to resolve
+    them interactively.
+
+  * Slight improvement on speed of overlay icons display.
+
+  * A new 'about' dialog.
+
+Bugs fixed in 0.2
+
+  * [SF Bug #1851395] Overlay icons and context menus are no longer
+    restricted to MS-Explorer. So other file managers, such as Total
+    Commander, should be supported.
+
+  * [SF Bug #1844722] Users can now create repositories inside repository
+     via the context menu.
+
+Changes since 0.2rc1
+
+  - N/A -
+
+
-#!/usr/bin/env python
-#
-# mercurial - scalable distributed SCM
-#
-# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
-#
-# This software may be used and distributed according to the terms
-# of the GNU General Public License, incorporated herein by reference.
-
-# enable importing on demand to reduce startup time
-from mercurial import demandimport; demandimport.enable()
-
-import mercurial.dispatch
-mercurial.dispatch.run()
+#!/usr/bin/env python
+#
+# mercurial - scalable distributed SCM
+#
+# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+# enable importing on demand to reduce startup time
+from mercurial import demandimport; demandimport.enable()
+
+import mercurial.dispatch
+mercurial.dispatch.run()

File contrib/hgtk

 #!/usr/bin/env python
 #
 # front-end script for TortoiseHg dialogs
+#
 # Copyright (C) 2008 Steve Borho <steve@borho.org>
-#
-# Modify this line to the location of your tortoisehg repository
-# or set TORTOISEHG_PATH in your environment
+# Copyright (C) 2008 TK Soh <teekaysoh@gmail.com>
+
+# set TORTOISEHG_PATH in your environment to point the location
+# of your tortoisehg repository, or modify 'tortoisehg_dir' below:
 tortoisehg_dir = '~/tools/tortoisehg-dev'
 
 import os
 import sys
+import traceback
+import pygtk
+pygtk.require('2.0')
+import gtk
+import shlex
+from mercurial.i18n import _
+from mercurial import hg, util, fancyopts, commands, cmdutil
+from mercurial.repo import RepoError
+import mercurial.ui as _ui
 
-dialogs = '''log synch status clone merge update userconfig repoconfig
-serve recovery commit datamine about'''
+class ParseError(Exception):
+    """Exception raised on errors in parsing the command line."""
 
-nonrepo_commands = 'clone about'
+nonrepo_commands = 'userconfig clone about help'
 
-def help():
-    print 'TortoiseHg Dialog Wrapper\n'
-    print 'hgtk [DIALOG]'
-    print '    dialogs:', dialogs
+def dispatch(args):
+    "run the command specified in args"
+    try:
+        u = _ui.ui(traceback='--traceback' in args)
+    except util.Abort, inst:
+        sys.stderr.write(_("abort: %s\n") % inst)
+        return -1
+    return _runcatch(u, args)
 
-def main(command):
-    dlist = dialogs.split()
-    l = []
-    for d in dlist:
-        if d.startswith(command):
-            l.append(d)
-    if not l:
-        print 'dialog', command, 'not recognized'
-        help()
-        sys.exit(1)
-    if len(l) > 1:
-        print 'dialog', command, 'is ambiguous'
-        print '\tcould be one of', ' '.join(l)
-        sys.exit(1)
-    command = l[0]
+def _parse(ui, args):
+    options = {}
+    cmdoptions = {}
+
+    try:
+        args = fancyopts.fancyopts(args, globalopts, options)
+    except fancyopts.getopt.GetoptError, inst:
+        raise ParseError(None, inst)
+
+    if args:
+        cmd, args = args[0], args[1:]
+        aliases, i = cmdutil.findcmd(ui, cmd, table)
+        cmd = aliases[0]
+        c = list(i[1])
+    else:
+        cmd = None
+        c = []
+
+    # combine global options into local
+    for o in globalopts:
+        c.append((o[0], o[1], options[o[1]], o[3]))
+
+    try:
+        args = fancyopts.fancyopts(args, c, cmdoptions)
+    except fancyopts.getopt.GetoptError, inst:
+        raise ParseError(cmd, inst)
+
+    # separate global options back out
+    for o in globalopts:
+        n = o[1]
+        options[n] = cmdoptions[n]
+        del cmdoptions[n]
+
+    return (cmd, cmd and i[0] or None, args, options, cmdoptions)
+
+def _runcatch(ui, args):
+    try:
+        try:
+            return runcommand(ui, args)
+        finally:
+            ui.flush()
+    except ParseError, inst:
+        if inst.args[0]:
+            ui.warn(_("hgtk %s: %s\n") % (inst.args[0], inst.args[1]))
+            help_(ui, inst.args[0])
+        else:
+            ui.warn(_("hgtk: %s\n") % inst.args[1])
+            help_('shortlist')
+    except cmdutil.AmbiguousCommand, inst:
+        ui.warn(_("hgtk: command '%s' is ambiguous:\n    %s\n") %
+                (inst.args[0], " ".join(inst.args[1])))
+    except cmdutil.UnknownCommand, inst:
+        ui.warn(_("hgtk: unknown command '%s'\n") % inst.args[0])
+        help_(ui, 'shortlist')
+    except RepoError, inst:
+        ui.warn(_("abort: %s!\n") % inst)
+    except util.Abort, inst:
+        ui.warn(_("abort: %s\n") % inst)
+        
+    return -1
+
+def runcommand(ui, args):
+    fullargs = args
+    cmd, func, args, options, cmdoptions = _parse(ui, args)
+    ui.updateopts(options["verbose"])
+
+    if options['help']:
+        return help_(ui, cmd)
+    elif not cmd:
+        return help_(ui, 'shortlist')
 
     if hasattr(sys, "frozen"):
         # Py2exe environment
         try:
             # assuming TortoiseHg source layout, with hgtk in contrib
             path = os.path.dirname(os.path.realpath(__file__))
-            norm = os.path.normpath(os.path.join(path, '..'))
-            if norm not in sys.path:
-                sys.path.append(norm)
-        except NameError: # __file__ is not always available
-            pass
+        except NameError:
+            # __file__ not available in pdb mode
+            path = os.path.dirname(sys.argv[0])
+        norm = os.path.normpath(os.path.join(path, '..'))
+        if norm not in sys.path:
+            sys.path.append(norm)
 
     try:
         from hggtk import hglib
-    except ImportError:
-        # fix "tortoisehg_dir" at the top of this script, or ...
-        print 'Please set TORTOISEHG_PATH to location of your ' \
-                'tortoisehg repository'
-        sys.exit(1)
+    except ImportError, inst:
+        m = str(inst).split()[-1]
+        if m in "hglib hggtk".split():
+            # fix "tortoisehg_dir" at the top of this script, or ...
+            raise util.Abort(_('Please set TORTOISEHG_PATH to location '
+                    'of your tortoisehg repository'))
+        else:
+            raise util.Abort(_('could not import module %s!\n' % m))
+    except:
+        raise
 
-    cwd = os.getcwd()
-    root = hglib.rootpath(cwd)
-    opts = { 'root' : root, 'cwd' : cwd }
+    path = hglib.rootpath(os.getcwd())
+    if path:
+        try:
+            lui = _ui.ui(parentui=ui)
+            lui.readconfig(os.path.join(path, ".hg", "hgrc"))
+        except IOError:
+            pass
+    else:
+        lui = ui
+    if options['repository']:
+        path = lui.expandpath(options['repository'])
 
-    if not root and command not in nonrepo_commands:
-        print 'No repository found, and', command, 'requires one.'
-        sys.exit(1)
+    if cmd not in nonrepo_commands.split():
+        try:
+            repo = hg.repository(ui, path=path)
+        except RepoError, inst:
+            # try to guess the repo from first of file args
+            root = None
+            if args:
+                path = hglib.rootpath(args[0])
+            if path:
+                repo = hg.repository(ui, path=path)
+            else:
+                raise RepoError(_("There is no Mercurial repository here"
+                        " (.hg not found)"))
+        cmdoptions['root'] = os.path.abspath(path)
 
-    # add aliases to taste (and to commands at top of file)
-    if command in ('log'):
-        from hggtk.history import run
-        opts['files'] = [root]
-    elif command in ('datamine'):
-        from hggtk.datamine import run
-    elif command in ('synch'):
-        from hggtk.synch import run
-    elif command in ('status'):
-        from hggtk.status import run
-    elif command in ('clone'):
-        from hggtk.clone import run
-    elif command in ('merge'):
-        from hggtk.merge import run
-    elif command in ('update'):
-        from hggtk.update import run
-    elif command in ('serve'):
-        from hggtk.serve import run
-    elif command in ('recovery'):
-        from hggtk.recovery import run
-    elif command in ('commit'):
-        from hggtk.commit import run
-    elif command in ('repoconfig'):
-        from hggtk.thgconfig import run
-        opts['files'] = [root]
-    elif command in ('userconfig'):
-        from hggtk.thgconfig import run
-    elif command in ('about'):
-        from hggtk.about import run
+    try:
+        return func(ui, *args, **cmdoptions)
+    except TypeError, inst:
+        # was this an argument error?
+        tb = traceback.extract_tb(sys.exc_info()[2])
+        if len(tb) != 1: # no
+            raise
+        raise ParseError(cmd, _("invalid arguments"))
+
+def about(ui, **opts):
+    """about TortoiseHg"""
+    from hggtk.about import run
     run(**opts)
 
+def clone(ui, source=None, dest=None, **opts):
+    """clone tool"""
+    from hggtk.clone import run
+    opts['files'] = [os.path.abspath(x) for x in (source, dest) if x]
+    run(**opts)
+
+def commit(ui, *pats, **opts):
+    """commit tool"""
+    from hggtk.commit import run
+    opts['files'] = [os.path.abspath(x) for x in pats]
+    run(**opts)
+
+def userconfig(ui, **opts):
+    """user configuration editor"""
+    from hggtk.thgconfig import run
+    run(**opts)
+
+def repoconfig(ui, *pats, **opts):
+    """repository configuration editor"""
+    from hggtk.thgconfig import run
+    opts['files'] = opts['root']
+    run(**opts)
+
+def datamine(ui, *pats, **opts):
+    """repository search and annotate tool"""
+    from hggtk.datamine import run
+    run(**opts)
+
+def log(ui, *pats, **opts):
+    """changelog viewer"""
+    from hggtk.history import run
+    opts['files'] = [os.path.abspath(x) for x in pats]
+    run(**opts)
+
+def merge(ui, node=None, rev=None, **opts):
+    """merge tool """
+    from hggtk.merge import run
+    run(**opts)
+
+def recovery(ui, *pats, **opts):
+    """recover, rollback & verify"""
+    from hggtk.recovery import run
+    run(**opts)
+
+def serve(ui, **opts):
+    """web server"""
+    from hggtk.serve import run
+    run(**opts)
+
+def status(ui, *pats, **opts):
+    """file status viewer
+
+    Also do add, remove and revert.
+    """
+
+    from hggtk.status import run
+    opts['files'] = [os.path.abspath(x) for x in pats]
+    run(**opts)
+
+def synch(ui, **opts):
+    """repository synchronization tool"""
+    from hggtk.synch import run
+    run(**opts)
+
+def update(ui, **opts):
+    """update/checkout tool"""
+    from hggtk.update import run
+    run(**opts)
+
+### help management, adapted from mercurial.commands.help_()
+def help_(ui, name=None, with_version=False):
+    """show help for a command, extension, or list of commands
+
+    With no arguments, print a list of commands and short help.
+
+    Given a command name, print help for that command.
+
+    Given an extension name, print help for that extension, and the
+    commands it provides."""
+    option_lists = []
+
+    def addglobalopts(aliases):
+        if ui.verbose:
+            option_lists.append((_("global options:"), globalopts))
+            if name == 'shortlist':
+                option_lists.append((_('use "hgtk help" for the full list '
+                                       'of commands'), ()))
+        else:
+            if name == 'shortlist':
+                msg = _('use "hgtk help" for the full list of commands '
+                        'or "hgtk -v" for details')
+            elif aliases:
+                msg = _('use "hgtk -v help%s" to show aliases and '
+                        'global options') % (name and " " + name or "")
+            else:
+                msg = _('use "hgtk -v help %s" to show global options') % name
+            option_lists.append((msg, ()))
+
+    def helpcmd(name):
+        if with_version:
+            version_(ui)
+            ui.write('\n')
+        aliases, i = cmdutil.findcmd(ui, name, table)
+        # synopsis
+        ui.write("%s\n" % i[2])
+
+        # aliases
+        if not ui.quiet and len(aliases) > 1:
+            ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
+
+        # description
+        doc = i[0].__doc__
+        if not doc:
+            doc = _("(No help text available)")
+        if ui.quiet:
+            doc = doc.splitlines(0)[0]
+        ui.write("\n%s\n" % doc.rstrip())
+
+        if not ui.quiet:
+            # options
+            if i[1]:
+                option_lists.append((_("options:\n"), i[1]))
+
+            addglobalopts(False)
+
+    def helplist(header, select=None):
+        h = {}
+        cmds = {}
+        for c, e in table.items():
+            f = c.split("|", 1)[0]
+            if select and not select(f):
+                continue
+            if name == "shortlist" and not f.startswith("^"):
+                continue
+            f = f.lstrip("^")
+            if not ui.debugflag and f.startswith("debug"):
+                continue
+            doc = e[0].__doc__
+            if not doc:
+                doc = _("(No help text available)")
+            h[f] = doc.splitlines(0)[0].rstrip()
+            cmds[f] = c.lstrip("^")
+
+        if not h:
+            ui.status(_('no commands defined\n'))
+            return
+
+        ui.status(header)
+        fns = h.keys()
+        fns.sort()
+        m = max(map(len, fns))
+        for f in fns:
+            if ui.verbose:
+                commands = cmds[f].replace("|",", ")
+                ui.write(" %s:\n      %s\n"%(commands, h[f]))
+            else:
+                ui.write(' %-*s   %s\n' % (m, f, h[f]))
+
+        if not ui.quiet:
+            addglobalopts(True)
+
+    def helptopic(name):
+        v = None
+        for i in help.helptable:
+            l = i.split('|')
+            if name in l:
+                v = i
+                header = l[-1]
+        if not v:
+            raise cmdutil.UnknownCommand(name)
+
+        # description
+        doc = help.helptable[v]
+        if not doc:
+            doc = _("(No help text available)")
+        if callable(doc):
+            doc = doc()
+
+        ui.write("%s\n" % header)
+        ui.write("%s\n" % doc.rstrip())
+
+    def helpext(name):
+        try:
+            mod = extensions.find(name)
+        except KeyError:
+            raise cmdutil.UnknownCommand(name)
+
+        doc = (mod.__doc__ or _('No help text available')).splitlines(0)
+        ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
+        for d in doc[1:]:
+            ui.write(d, '\n')
+
+        ui.status('\n')
+
+        try:
+            ct = mod.cmdtable
+        except AttributeError:
+            ct = {}
+
+        modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
+        helplist(_('list of commands:\n\n'), modcmds.has_key)
+
+    if name and name != 'shortlist':
+        i = None
+        for f in (helpcmd, helptopic, helpext):
+            try:
+                f(name)
+                i = None
+                break
+            except cmdutil.UnknownCommand, inst:
+                i = inst
+        if i:
+            raise i
+
+    else:
+        # program name
+        if ui.verbose or with_version:
+            version_(ui)
+        else:
+            ui.status(_("Hgtk - TortoiseHg's GUI tools for Mercurial SCM (Hg)\n"))
+        ui.status('\n')
+
+        # list of commands
+        if name == "shortlist":
+            header = _('basic commands:\n\n')
+        else:
+            header = _('list of commands:\n\n')
+
+        helplist(header)
+
+    # list all option lists
+    opt_output = []
+    for title, options in option_lists:
+        opt_output.append(("\n%s" % title, None))
+        for shortopt, longopt, default, desc in options:
+            if "DEPRECATED" in desc and not ui.verbose: continue
+            opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
+                                          longopt and " --%s" % longopt),
+                               "%s%s" % (desc,
+                                         default
+                                         and _(" (default: %s)") % default
+                                         or "")))
+
+    if opt_output:
+        opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
+        for first, second in opt_output:
+            if second:
+                ui.write(" %-*s  %s\n" % (opts_len, first, second))
+            else:
+                ui.write("%s\n" % first)
+
+def version_(ui):
+    """output version and copyright information"""
+    pass
+
+globalopts = [
+    ('R', 'repository', '',
+     _('repository root directory or symbolic path name')),
+    ('v', 'verbose', None, _('enable additional output')),
+    ('h', 'help', None, _('display help and exit')),
+]
+
+table = {
+    "^about": (about, [], _('hgtk about')),
+    "^clone": (clone, [],  _('hgtk clone SOURCE [DEST]')),
+    "^commit|ci": (commit, [], _('hgtk commit [FILE]...')),
+    "^datamine": (datamine, [], _('hgtk datamine')),
+    "^log|history": (log, [], _('hgtk log [FILE]')),
+    "^merge": (merge, [], _('hgtk merge')),
+    "^recovery": (recovery, [], _('hgtk recovery')),
+    "^synch": (synch, [], _('hgtk synch')),
+    "^status": (status, [], _('hgtk status [FILE]...')),
+    "^userconfig": (userconfig, [], _('hgtk userconfig')),
+    "^repoconfig": (repoconfig, [], _('hgtk repoconfig')),
+    "^serve": (serve, [], _('hgtk serve')),
+    "^update|checkout|co": (update, [], _('hgtk update')),
+    "help": (help_, [], _('hgtk help [COMMAND]')),
+}
 
 if __name__=='__main__':
-    if len(sys.argv) != 2:
-        help()
-    else:
-        main(sys.argv[1])
-    sys.exit(0)
+    sys.exit(dispatch(sys.argv[1:]))

File contrib/nautilus-thg.py

         repo = self.get_repo_for_path(path)
         cwd = os.path.isdir(path) and path or os.path.dirname(path)
 
+        if repo is not None:
+            root = repo.root
+        else:
+            root = cwd
+
         cmdopts  = [sys.executable, self.hgproc]
-        cmdopts += ['--root', repo.root]
+        cmdopts += ['--root', root]
         cmdopts += ['--cwd', cwd]
         cmdopts += ['--command', hgcmd]
 

File hggtk/about.py

-#
-# TortoiseHg About dialog
-#
-# Copyright (C) 2007 TK Soh <teekaysoh@gmail.com>
-#
-
-import os
-import sys
-
-import pygtk
-pygtk.require('2.0')
-import gtk
-import gobject
-import pango
-import shlib
-
-import tortoise.version
-import mercurial.version
-
-def browse_url(url):
-    import threading
-    def start_browser():
-        if os.name == 'nt':
-            import win32api, win32con
-            win32api.ShellExecute(0, "open", url, None, "", 
-                win32con.SW_SHOW)
-        else:
-            import gconf
-            client = gconf.client_get_default()
-            browser = client.get_string(
-                    '/desktop/gnome/url-handlers/http/command') + '&'
-            os.system(browser % url)
-    threading.Thread(target=start_browser).start()
-
-def url_handler(dialog, link, user_data):
-	browse_url(link)
-    
-gtk.about_dialog_set_url_hook(url_handler, None)
-
-def make_version(tuple):
-    vers = ".".join([str(x) for x in tuple])
-    return vers
-    
-class AboutDialog(gtk.AboutDialog):
-    def __init__(self):
-        super(AboutDialog, self).__init__()
-
-        lib_versions = ', '.join([
-                "Mercurial-%s" % mercurial.version.get_version(),
-                "Python-%s" % make_version(sys.version_info[0:3]),
-                "PyGTK-%s" % make_version(gtk.pygtk_version),
-                "GTK-%s" % make_version(gtk.gtk_version),
-            ])
-        
-        comment = "Several icons are courtesy of the TortoiseSVN project"
-
-        self.set_website("http://tortoisehg.sourceforge.net/")
-        self.set_name("TortoiseHg")
-        self.set_version("(version %s)" % tortoise.version.get_version())
-        if hasattr(self, 'set_wrap_license'):
-            self.set_wrap_license(True)
-        self.set_copyright("Copyright 2008 TK Soh and others")
-
-        hg_icon = os.path.normpath(shlib.get_tortoise_icon('thg_logo_92x50.png'))
-        prog_root = os.path.dirname(os.path.dirname(os.path.dirname(hg_icon)))
-        license_file = os.path.join(prog_root, "COPYING.txt")
-
-        self.set_license(file(license_file).read())
-        self.set_comments("with " + lib_versions + "\n\n" + comment)
-        self.set_logo(gtk.gdk.pixbuf_new_from_file(hg_icon))      
-        self.set_icon_from_file(hg_icon)
-        
-        # somehow clicking on the Close button doesn't automatically
-        # close the About dialog...
-        self.connect('response', gtk.main_quit)
-
-def run(*args, **opts):
-    dialog = AboutDialog()
-    dialog.show_all()
-    gtk.gdk.threads_init()
-    gtk.gdk.threads_enter()
-    gtk.main()
-    gtk.gdk.threads_leave()
-
-if __name__ == "__main__":
-    run()
+#
+# TortoiseHg About dialog
+#
+# Copyright (C) 2007 TK Soh <teekaysoh@gmail.com>
+#
+
+import os
+import sys
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import gobject
+import pango
+import shlib
+
+import tortoise.version
+import mercurial.version
+
+def browse_url(url):
+    import threading
+    def start_browser():
+        if os.name == 'nt':
+            import win32api, win32con
+            win32api.ShellExecute(0, "open", url, None, "", 
+                win32con.SW_SHOW)
+        else:
+            import gconf
+            client = gconf.client_get_default()
+            browser = client.get_string(
+                    '/desktop/gnome/url-handlers/http/command') + '&'
+            os.system(browser % url)
+    threading.Thread(target=start_browser).start()
+
+def url_handler(dialog, link, user_data):
+	browse_url(link)
+    
+gtk.about_dialog_set_url_hook(url_handler, None)
+
+def make_version(tuple):
+    vers = ".".join([str(x) for x in tuple])
+    return vers
+    
+class AboutDialog(gtk.AboutDialog):
+    def __init__(self):
+        super(AboutDialog, self).__init__()
+
+        lib_versions = ', '.join([
+                "Mercurial-%s" % mercurial.version.get_version(),
+                "Python-%s" % make_version(sys.version_info[0:3]),
+                "PyGTK-%s" % make_version(gtk.pygtk_version),
+                "GTK-%s" % make_version(gtk.gtk_version),
+            ])
+        
+        comment = "Several icons are courtesy of the TortoiseSVN project"
+
+        self.set_website("http://tortoisehg.sourceforge.net/")
+        self.set_name("TortoiseHg")
+        self.set_version("(version %s)" % tortoise.version.get_version())
+        if hasattr(self, 'set_wrap_license'):
+            self.set_wrap_license(True)
+        self.set_copyright("Copyright 2008 TK Soh and others")
+
+        thg_logo = os.path.normpath(shlib.get_tortoise_icon('thg_logo_92x50.png'))
+        thg_icon = os.path.normpath(shlib.get_tortoise_icon('thg_logo.ico'))
+        prog_root = os.path.dirname(os.path.dirname(os.path.dirname(thg_icon)))
+        license_file = os.path.join(prog_root, "COPYING.txt")
+
+        self.set_license(file(license_file).read())
+        self.set_comments("with " + lib_versions + "\n\n" + comment)
+        self.set_logo(gtk.gdk.pixbuf_new_from_file(thg_logo))
+        self.set_icon_from_file(thg_icon)
+        
+        # somehow clicking on the Close button doesn't automatically
+        # close the About dialog...
+        self.connect('response', gtk.main_quit)
+
+def run(*args, **opts):
+    dialog = AboutDialog()
+    dialog.show_all()
+    gtk.gdk.threads_init()
+    gtk.gdk.threads_enter()
+    gtk.main()
+    gtk.gdk.threads_leave()
+
+if __name__ == "__main__":
+    run()

File hggtk/addremove.py

-#
-# Add/Remove dialog for TortoiseHg
-#
-# Copyright (C) 2007 TK Soh <teekaysoh@gmail.com>
-#
-
-try:
-    import pygtk
-    pygtk.require("2.0")
-except:
-    pass
-
-import gtk
-import gobject
-from mercurial import ui, util, hg
-from mercurial.i18n import _
-from status import GStatus
-
-def run(hgcmd='add', root='', cwd='', files=[], **opts):
-    u = ui.ui()
-    u.updateopts(debug=False, traceback=False)
-    repo = hg.repository(u, path=root)
-
-    cmdoptions = {
-        'all':False, 'clean':False, 'ignored':False, 'modified':False,
-        'added':True, 'removed':True, 'deleted':True, 'unknown':False, 'rev':[],
-        'exclude':[], 'include':[], 'debug':True,'verbose':True
-    }
-    
-    if hgcmd == 'add':
-        cmdoptions['unknown'] = True        
-    elif hgcmd == 'remove':
-        cmdoptions['clean'] = True
-    else:
-        raise "Invalid command '%s'" % hgcmd
-        
-    dialog = GStatus(u, repo, cwd, files, cmdoptions, True)
-
-    gtk.gdk.threads_init()
-    gtk.gdk.threads_enter()
-    dialog.display()
-    gtk.main()
-    gtk.gdk.threads_leave()
-    
-if __name__ == "__main__":
-    import sys
-    opts = {}
-    opts['hgcmd'] = 'adda'
-    opts['root'] = len(sys.argv) > 1 and sys.argv[1] or ''
-    run(**opts)
+#
+# Add/Remove dialog for TortoiseHg
+#
+# Copyright (C) 2007 TK Soh <teekaysoh@gmail.com>
+#
+
+try:
+    import pygtk
+    pygtk.require("2.0")
+except:
+    pass
+
+import gtk
+import gobject
+from mercurial import ui, util, hg
+from mercurial.i18n import _
+from status import GStatus
+
+def run(hgcmd='add', root='', cwd='', files=[], **opts):
+    u = ui.ui()
+    u.updateopts(debug=False, traceback=False)
+    repo = hg.repository(u, path=root)
+
+    cmdoptions = {
+        'all':False, 'clean':False, 'ignored':False, 'modified':False,
+        'added':True, 'removed':True, 'deleted':True, 'unknown':False, 'rev':[],
+        'exclude':[], 'include':[], 'debug':True,'verbose':True
+    }
+    
+    if hgcmd == 'add':
+        cmdoptions['unknown'] = True        
+    elif hgcmd == 'remove':
+        cmdoptions['clean'] = True
+    else:
+        raise "Invalid command '%s'" % hgcmd
+        
+    dialog = GStatus(u, repo, cwd, files, cmdoptions, True)
+
+    gtk.gdk.threads_init()
+    gtk.gdk.threads_enter()
+    dialog.display()
+    gtk.main()
+    gtk.gdk.threads_leave()
+    
+if __name__ == "__main__":
+    import sys
+    opts = {}
+    opts['hgcmd'] = 'adda'
+    opts['root'] = len(sys.argv) > 1 and sys.argv[1] or ''
+    run(**opts)

File hggtk/backout.py

-#
-# backout.py - TortoiseHg's dialog for backing out changeset
-#
-# Copyright (C) 2008 Steve Borho <steve@borho.org>
-# Copyright (C) 2007 TK Soh <teekaysoh@gmail.com>
-#
-
-import os
-import sys
-import gtk
-import pango
-from dialog import *
-from hgcmd import CmdDialog
-import histselect
-
-class BackoutDialog(gtk.Window):
-    """ Backout effect of a changeset """
-    def __init__(self, root='', rev=''):
-        """ Initialize the Dialog """
-        gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
-
-        self.root = root
-        self.set_title('Backout changeset - ' + rev)
-        self.set_default_size(600, 400)
-        self.notify_func = None
-        
-        self.tbar = gtk.Toolbar()
-        self.tips = gtk.Tooltips()
-
-        sep = gtk.SeparatorToolItem()
-        sep.set_expand(True)
-        sep.set_draw(False)
-
-        tbuttons = [
-                self._toolbutton(gtk.STOCK_GO_BACK, 'Backout',
-                                 self._backout_clicked,
-                                 'Backout selected changeset'),
-                sep,
-                self._toolbutton(gtk.STOCK_CLOSE, 'Close',
-                                 self._close_clicked,
-                                 'Close Window')
-            ]
-        for btn in tbuttons:
-            self.tbar.insert(btn, -1)
-        vbox = gtk.VBox()
-        self.add(vbox)
-        vbox.pack_start(self.tbar, False, False, 2)
-
-        # From: combo box
-        self.reventry = gtk.Entry()
-        self.reventry.set_text(rev)
-        self.browse = gtk.Button("Browse...")
-        self.browse.connect('clicked', self._btn_rev_clicked)
-
-        hbox = gtk.HBox()
-        hbox.pack_start(gtk.Label('Revision to backout:'), False, False, 4)
-        hbox.pack_start(self.reventry, True, True, 4)
-        hbox.pack_start(self.browse, False, False, 4)
-        vbox.pack_start(hbox, False, False, 4)
-
-        self.logview = gtk.TextView(buffer=None)
-        self.logview.set_editable(True)
-        self.logview.modify_font(pango.FontDescription("Monospace"))
-        buffer = self.logview.get_buffer()
-        buffer.set_text('Backed out changeset: ' + rev)
-        scrolledwindow = gtk.ScrolledWindow()
-        scrolledwindow.set_shadow_type(gtk.SHADOW_ETCHED_IN)
-        scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
-        scrolledwindow.add(self.logview)
-        scrolledwindow.set_border_width(4)
-        frame = gtk.Frame('Backout commit message')
-        frame.set_border_width(4)
-        frame.add(scrolledwindow)
-        self.tips.set_tip(frame, 
-                'Commit message text for new changeset that reverses the'
-                '  effect of the change being backed out.')
-        vbox.pack_start(frame, True, True, 4)
-
-    def _close_clicked(self, toolbutton, data=None):
-        self.destroy()
-
-    def set_notify_func(self, func, *args):
-        self.notify_func = func
-        self.notify_args = args
-
-    def _btn_rev_clicked(self, button):
-        """ select revision from history dialog """
-        rev = histselect.select(self.root)
-        if rev is not None:
-            self.reventry.set_text(rev)
-            buffer = self.logview.get_buffer()
-            buffer.set_text('Backed out changeset: ' + rev)
-
-    def _toolbutton(self, stock, label, handler, tip):
-        tbutton = gtk.ToolButton(stock)
-        tbutton.set_label(label)
-        tbutton.set_tooltip(self.tips, tip)
-        tbutton.connect('clicked', handler)
-        return tbutton
-        
-    def _backout_clicked(self, button):
-        buffer = self.logview.get_buffer()
-        start, end = buffer.get_bounds()
-        cmdline = ['hg', 'backout', '--rev', self.reventry.get_text(),
-            '--message', buffer.get_text(start, end)]
-        dlg = CmdDialog(cmdline)
-        dlg.show_all()
-        dlg.run()
-        dlg.hide()
-        if self.notify_func:
-            self.notify_func(self.notify_args)
-
-def run(root='', **opts):
-    # This dialog is intended to be launched by the changelog browser
-    # It's not expected to be used from hgproc or the command line.  I
-    # leave this path in place for testing purposes.
-    dialog = BackoutDialog(root, 'tip')
-    dialog.show_all()
-    dialog.connect('destroy', gtk.main_quit)
-    gtk.gdk.threads_init()
-    gtk.gdk.threads_enter()
-    gtk.main()
-    gtk.gdk.threads_leave()
-
-if __name__ == "__main__":
-    import sys
-    opts = {}
-    opts['root'] = len(sys.argv) > 1 and sys.argv[1] or os.getcwd()
-    run(**opts)
+#
+# backout.py - TortoiseHg's dialog for backing out changeset
+#
+# Copyright (C) 2008 Steve Borho <steve@borho.org>
+# Copyright (C) 2007 TK Soh <teekaysoh@gmail.com>
+#
+
+import os
+import sys
+import gtk
+import pango
+from dialog import *
+from hgcmd import CmdDialog
+import histselect
+
+class BackoutDialog(gtk.Window):
+    """ Backout effect of a changeset """
+    def __init__(self, root='', rev=''):
+        """ Initialize the Dialog """
+        gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
+
+        self.root = root
+        self.set_title('Backout changeset - ' + rev)
+        self.set_default_size(600, 400)
+        self.notify_func = None
+        
+        self.tbar = gtk.Toolbar()
+        self.tips = gtk.Tooltips()
+
+        sep = gtk.SeparatorToolItem()
+        sep.set_expand(True)
+        sep.set_draw(False)
+
+        tbuttons = [
+                self._toolbutton(gtk.STOCK_GO_BACK, 'Backout',
+                                 self._backout_clicked,
+                                 'Backout selected changeset'),
+                sep,
+                self._toolbutton(gtk.STOCK_CLOSE, 'Close',
+                                 self._close_clicked,
+                                 'Close Window')
+            ]
+        for btn in tbuttons:
+            self.tbar.insert(btn, -1)
+        vbox = gtk.VBox()
+        self.add(vbox)
+        vbox.pack_start(self.tbar, False, False, 2)
+
+        # From: combo box
+        self.reventry = gtk.Entry()
+        self.reventry.set_text(rev)
+        self.browse = gtk.Button("Browse...")
+        self.browse.connect('clicked', self._btn_rev_clicked)
+
+        hbox = gtk.HBox()
+        hbox.pack_start(gtk.Label('Revision to backout:'), False, False, 4)
+        hbox.pack_start(self.reventry, True, True, 4)
+        hbox.pack_start(self.browse, False, False, 4)
+        vbox.pack_start(hbox, False, False, 4)
+
+        self.logview = gtk.TextView(buffer=None)
+        self.logview.set_editable(True)
+        self.logview.modify_font(pango.FontDescription("Monospace"))
+        buffer = self.logview.get_buffer()
+        buffer.set_text('Backed out changeset: ' + rev)
+        scrolledwindow = gtk.ScrolledWindow()
+        scrolledwindow.set_shadow_type(gtk.SHADOW_ETCHED_IN)
+        scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+        scrolledwindow.add(self.logview)
+        scrolledwindow.set_border_width(4)
+        frame = gtk.Frame('Backout commit message')
+        frame.set_border_width(4)
+        frame.add(scrolledwindow)
+        self.tips.set_tip(frame, 
+                'Commit message text for new changeset that reverses the'
+                '  effect of the change being backed out.')
+        vbox.pack_start(frame, True, True, 4)
+
+    def _close_clicked(self, toolbutton, data=None):
+        self.destroy()
+
+    def set_notify_func(self, func, *args):
+        self.notify_func = func
+        self.notify_args = args
+
+    def _btn_rev_clicked(self, button):
+        """ select revision from history dialog """
+        rev = histselect.select(self.root)
+        if rev is not None:
+            self.reventry.set_text(rev)
+            buffer = self.logview.get_buffer()
+            buffer.set_text('Backed out changeset: ' + rev)
+
+    def _toolbutton(self, stock, label, handler, tip):
+        tbutton = gtk.ToolButton(stock)
+        tbutton.set_label(label)
+        tbutton.set_tooltip(self.tips, tip)
+        tbutton.connect('clicked', handler)
+        return tbutton
+        
+    def _backout_clicked(self, button):
+        buffer = self.logview.get_buffer()
+        start, end = buffer.get_bounds()
+        cmdline = ['hg', 'backout', '--rev', self.reventry.get_text(),
+            '--message', buffer.get_text(start, end)]
+        dlg = CmdDialog(cmdline)
+        dlg.show_all()
+        dlg.run()
+        dlg.hide()
+        if self.notify_func:
+            self.notify_func(self.notify_args)
+
+def run(root='', **opts):
+    # This dialog is intended to be launched by the changelog browser
+    # It's not expected to be used from hgproc or the command line.  I
+    # leave this path in place for testing purposes.
+    dialog = BackoutDialog(root, 'tip')
+    dialog.show_all()
+    dialog.connect('destroy', gtk.main_quit)
+    gtk.gdk.threads_init()
+    gtk.gdk.threads_enter()
+    gtk.main()
+    gtk.gdk.threads_leave()
+
+if __name__ == "__main__":
+    import sys
+    opts = {}
+    opts['root'] = len(sys.argv) > 1 and sys.argv[1] or os.getcwd()
+    run(**opts)

File hggtk/changeset.py

         if dialog.run() == gtk.RESPONSE_NO:
             return
         cmdline = ['hg', 'revert', '--verbose', '--rev', str(rev), self.curfile]
-        self.restore_cwd()
         dlg = CmdDialog(cmdline)
         dlg.run()
         dlg.hide()

File hggtk/clone.py

-#
-# TortoiseHg dialog to clone a repo
-#
-# Copyright (C) 2007 TK Soh <teekaysoh@gmail.com>
-#
-
-try:
-    import pygtk
-    pygtk.require("2.0")
-except:
-    pass
-
-import os
-import sys
-import gtk
-import pango
-from dialog import question_dialog, error_dialog, info_dialog
-from mercurial import hg, ui, cmdutil, util
-from mercurial.i18n import _
-from mercurial.node import *
-import shlib
-
-class CloneDialog(gtk.Window):
-    """ Dialog to add tag to Mercurial repo """
-    def __init__(self, cwd='', repos=[]):
-        """ Initialize the Dialog """
-        gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
-
-        shlib.set_tortoise_icon(self, 'menuclone.ico')
-        if cwd: os.chdir(cwd)
-        
-        # set dialog title
-        title = "hg clone "
-        title += " - %s" % (os.getcwd())
-        self.set_title(title)
-
-        self._src_path = ''
-        self._dest_path = ''
-        self._settings = shlib.Settings('clone')
-        self._recent_src = self._settings.mrul('src_paths')
-        self._recent_dest = self._settings.mrul('dest_paths')
-
-        try:
-            self._src_path = repos[0]
-            self._dest_path = repos[1]
-        except:
-            pass
-            
-        # build dialog
-        self._create()
-
-    def _create(self):
-        self.set_default_size(520, 180)
-        self.connect('destroy', gtk.main_quit)
-        ewidth = 16
-        
-        # add toolbar with tooltips
-        self.tbar = gtk.Toolbar()
-        self.tips = gtk.Tooltips()
-        
-        self._btn_clone = self._toolbutton(
-                gtk.STOCK_COPY,
-                'clone', 
-                self._btn_clone_clicked,
-                tip='Clone a repository')
-        tbuttons = [
-                self._btn_clone,
-            ]
-        for btn in tbuttons:
-            self.tbar.insert(btn, -1)
-        sep = gtk.SeparatorToolItem()
-        sep.set_expand(True)
-        sep.set_draw(False)
-        self.tbar.insert(sep, -1)
-        button = self._toolbutton(gtk.STOCK_CLOSE, 'Close',
-                self._close_clicked, tip='Close Application')
-        self.tbar.insert(button, -1)
-        vbox = gtk.VBox()
-        self.add(vbox)
-        vbox.pack_start(self.tbar, False, False, 2)
-
-        # clone source
-        srcbox = gtk.HBox()
-        lbl = gtk.Label("Source Path:")
-        lbl.set_property("width-chars", ewidth)
-        lbl.set_alignment(0, 0.5)
-
-        # create drop-down list for source paths
-        self._srclist = gtk.ListStore(str)
-        self._srclistbox = gtk.ComboBoxEntry(self._srclist, 0)
-        self._src_input = self._srclistbox.get_child()
-        self._src_input.set_text(self._src_path)
-        self._src_input.set_position(-1)
-
-        # replace the drop-down widget so we can modify it's properties
-        self._srclistbox.clear()
-        cell = gtk.CellRendererText()
-        cell.set_property('ellipsize', pango.ELLIPSIZE_MIDDLE)
-        self._srclistbox.pack_start(cell)
-        self._srclistbox.add_attribute(cell, 'text', 0)
-
-        self._btn_src_browse = gtk.Button("Browse...")
-        self._btn_src_browse.connect('clicked', self._btn_src_clicked)
-        srcbox.pack_start(lbl, False, False)
-        srcbox.pack_start(self._srclistbox, True, True)
-        srcbox.pack_end(self._btn_src_browse, False, False, 5)
-        vbox.pack_start(srcbox, False, False, 2)
-        
-        # add pre-defined src paths to pull-down list
-        sympaths = [x[1] for x in ui.ui().configitems('paths')]
-        paths = list(set(sympaths + [x for x in self._recent_src]))
-        paths.sort()
-        for p in paths:
-            self._srclist.append([p])
-
-        # clone destination
-        destbox = gtk.HBox()
-        lbl = gtk.Label("Destination Path:")
-        lbl.set_property("width-chars", ewidth)
-        lbl.set_alignment(0, 0.5)
-        self._destlist = gtk.ListStore(str)
-        self._destlistbox = gtk.ComboBoxEntry(self._destlist, 0)
-        self._dest_input = self._destlistbox.get_child()
-        self._dest_input.set_text(self._dest_path)
-        self._dest_input.set_position(-1)
-
-        # replace the drop-down widget so we can modify it's properties
-        self._destlistbox.clear()
-        cell = gtk.CellRendererText()
-        cell.set_property('ellipsize', pango.ELLIPSIZE_MIDDLE)
-        self._destlistbox.pack_start(cell)
-        self._destlistbox.add_attribute(cell, 'text', 0)
-        
-        self._btn_dest_browse = gtk.Button("Browse...")
-        self._btn_dest_browse.connect('clicked', self._btn_dest_clicked)
-        destbox.pack_start(lbl, False, False)
-        destbox.pack_start(self._destlistbox, True, True)
-        destbox.pack_end(self._btn_dest_browse, False, False, 5)
-        vbox.pack_start(destbox, False, False, 2)
-        
-        # add most-recent dest paths to pull-down list
-        paths = list(self._recent_dest)
-        paths.sort()
-        for p in paths:
-            self._destlist.append([p])
-
-        # revision input
-        revbox = gtk.HBox()
-        lbl = gtk.Label("Clone To Revision:")
-        lbl.set_property("width-chars", ewidth)
-        lbl.set_alignment(0, 0.5)
-        self._rev_input = gtk.Entry()
-        self._rev_input.set_text("")
-        self._opt_allrev = gtk.CheckButton("Clone all revisions")
-        self._opt_allrev.set_active(True)
-        self._btn_rev_browse = gtk.Button("Select...")
-        self._btn_rev_browse.connect('clicked', self._btn_rev_clicked)
-        revbox.pack_start(lbl, False, False)
-        revbox.pack_start(self._rev_input, False, False)
-        #revbox.pack_start(self._btn_rev_browse, False, False, 5)
-        revbox.pack_start(self._opt_allrev, False, False)
-        vbox.pack_start(revbox, False, False, 2)
-
-        # options
-        option_box = gtk.VBox()
-        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)
-        self._remote_cmd = gtk.Entry()
-        vbox.pack_end(self._remote_cmd, False, False, 1)
-        vbox.pack_end(lbl, False, False, 1)
-
-    def _close_clicked(self, toolbutton, data=None):
-        gtk.main_quit()
-
-    def _toolbutton(self, stock, label, handler,
-                    menu=None, userdata=None, tip=None):
-        if menu:
-            tbutton = gtk.MenuToolButton(stock)
-            tbutton.set_menu(menu)
-        else:
-            tbutton = gtk.ToolButton(stock)
-            
-        tbutton.set_label(label)
-        if tip:
-            tbutton.set_tooltip(self.tips, tip)
-        tbutton.connect('clicked', handler, userdata)
-        return tbutton
-
-    def _btn_dest_clicked(self, button):
-        """ select folder as clone destination """
-        dialog = gtk.FileChooserDialog(title=None,
-                action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
-                buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,
-                         gtk.STOCK_OPEN,gtk.RESPONSE_OK))
-        dialog.set_default_response(gtk.RESPONSE_OK)
-        response = dialog.run()
-        if response == gtk.RESPONSE_OK:
-            self._dest_input.set_text(dialog.get_filename())
-        dialog.destroy()
-        
-    def _btn_src_clicked(self, button):
-        """ select source folder to clone """
-        dialog = gtk.FileChooserDialog(title=None,
-                action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
-                buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,
-                         gtk.STOCK_OPEN,gtk.RESPONSE_OK))
-        dialog.set_default_response(gtk.RESPONSE_OK)
-        response = dialog.run()
-        if response == gtk.RESPONSE_OK:
-            self._src_input.set_text(dialog.get_filename())
-        dialog.destroy()
-
-    def _btn_rev_clicked(self, button):
-        """ select revision from history dialog """
-        import histselect
-        rev = histselect.select(self.root)
-        if rev is not None:
-            self._rev_input.set_text(rev)
-
-    def _add_src_to_recent(self, src):
-        if os.path.exists(src):
-            src = os.path.abspath(src)
-
-        # save path to recent list in history
-        self._recent_src.add(src)
-        self._settings.write()
-
-        # update drop-down list
-        self._srclist.clear()
-        sympaths = [x[1] for x in ui.ui().configitems('paths')]
-        paths = list(set(sympaths + [x for x in self._recent_src]))
-        paths.sort()
-        for p in paths:
-            self._srclist.append([p])
-
-    def _add_dest_to_recent(self, dest):
-        if os.path.exists(dest):
-            dest = os.path.abspath(dest)
-
-        # save path to recent list in history
-        self._recent_dest.add(dest)
-        self._settings.write()
-        
-        # update drop down list
-        paths = list(self._recent_dest)
-        paths.sort()
-        self._destlist.clear()
-        for p in paths:
-            self._destlist.append([p])
- 
-    def _btn_clone_clicked(self, toolbutton, data=None):
-        # gather input data
-        src = self._src_input.get_text()
-        dest = self._dest_input.get_text() or os.path.basename(src)
-        remotecmd = self._remote_cmd.get_text()
-        rev = self._rev_input.get_text()
-        
-        # verify input
-        if src == "":
-            error_dialog(self, "Source path is empty", "Please enter")
-            self._src_input.grab_focus()
-            return False
-        
-        # start cloning        
-        try:            
-            cmdline = ['hg', 'clone']
-            if self._opt_update.get_active():
-                cmdline.append('--noupdate')
-            if self._opt_uncomp.get_active():
-                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)
-            if not self._opt_allrev.get_active() and rev:   
-                cmdline.append('--rev')
-                cmdline.append(rev)
-
-            cmdline.append('--verbose')
-            cmdline.append(src)
-            if dest:
-                cmdline.append(dest)
-
-            print "cmdline: ", ' '.join(cmdline)
-            from hgcmd import CmdDialog
-            dlg = CmdDialog(cmdline)
-            dlg.run()
-            dlg.hide()
-        except util.Abort, inst:
-            error_dialog(self, "Clone aborted", str(inst))
-            return False
-        except:
-            import traceback
-            error_dialog(self, "Clone error", traceback.format_exc())
-            return False
-
-        self._add_src_to_recent(src)
-        self._add_dest_to_recent(dest)
-
-def run(cwd='', files=[], **opts):
-    dialog = CloneDialog(cwd, repos=files)
-    dialog.show_all()
-    gtk.gdk.threads_init()
-    gtk.gdk.threads_enter()
-    gtk.main()
-    gtk.gdk.threads_leave()
-    
-if __name__ == "__main__":
-    import sys
-    opts = {}
-    opts['cwd'] = os.getcwd()
-    opts['files'] = sys.argv[1:]
-    run(**opts)
+#
+# TortoiseHg dialog to clone a repo
+#
+# Copyright (C) 2007 TK Soh <teekaysoh@gmail.com>
+#
+
+try:
+    import pygtk
+    pygtk.require("2.0")
+except:
+    pass
+
+import os
+import sys
+import gtk
+import pango
+from dialog import question_dialog, error_dialog, info_dialog
+from mercurial import hg, ui, cmdutil, util
+from mercurial.i18n import _
+from mercurial.node import *
+import shlib
+
+class CloneDialog(gtk.Window):
+    """ Dialog to add tag to Mercurial repo """
+    def __init__(self, cwd='', repos=[]):
+        """ Initialize the Dialog """
+        gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
+
+        shlib.set_tortoise_icon(self, 'menuclone.ico')
+        if cwd: os.chdir(cwd)
+        
+        # set dialog title
+        title = "hg clone "
+        title += " - %s" % (os.getcwd())
+        self.set_title(title)
+
+        self._src_path = ''
+        self._dest_path = ''
+        self._settings = shlib.Settings('clone')
+        self._recent_src = self._settings.mrul('src_paths')
+        self._recent_dest = self._settings.mrul('dest_paths')
+
+        try:
+            self._src_path = repos[0]
+            self._dest_path = repos[1]
+        except:
+            pass
+            
+        # build dialog
+        self._create()
+
+    def _create(self):
+        self.set_default_size(520, 180)
+        self.connect('destroy', gtk.main_quit)
+        ewidth = 16
+        
+        # add toolbar with tooltips
+        self.tbar = gtk.Toolbar()
+        self.tips = gtk.Tooltips()
+        
+        self._btn_clone = self._toolbutton(
+                gtk.STOCK_COPY,
+                'clone', 
+                self._btn_clone_clicked,
+                tip='Clone a repository')
+        tbuttons = [
+                self._btn_clone,
+            ]
+        for btn in tbuttons:
+            self.tbar.insert(btn, -1)
+        sep = gtk.SeparatorToolItem()
+        sep.set_expand(True)
+        sep.set_draw(False)
+        self.tbar.insert(sep, -1)
+        button = self._toolbutton(gtk.STOCK_CLOSE, 'Close',
+                self._close_clicked, tip='Close Application')
+        self.tbar.insert(button, -1)
+        vbox = gtk.VBox()
+        self.add(vbox)
+        vbox.pack_start(self.tbar, False, False, 2)
+
+        # clone source
+        srcbox = gtk.HBox()
+        lbl = gtk.Label("Source Path:")
+        lbl.set_property("width-chars", ewidth)
+        lbl.set_alignment(0, 0.5)
+
+        # create drop-down list for source paths
+        self._srclist = gtk.ListStore(str)
+        self._srclistbox = gtk.ComboBoxEntry(self._srclist, 0)
+        self._src_input = self._srclistbox.get_child()
+        self._src_input.set_text(self._src_path)
+        self._src_input.set_position(-1)
+
+        # replace the drop-down widget so we can modify it's properties
+        self._srclistbox.clear()
+        cell = gtk.CellRendererText()
+        cell.set_property('ellipsize', pango.ELLIPSIZE_MIDDLE)
+        self._srclistbox.pack_start(cell)
+        self._srclistbox.add_attribute(cell, 'text', 0)
+
+        self._btn_src_browse = gtk.Button("Browse...")
+        self._btn_src_browse.connect('clicked', self._btn_src_clicked)
+        srcbox.pack_start(lbl, False, False)
+        srcbox.pack_start(self._srclistbox, True, True)
+        srcbox.pack_end(self._btn_src_browse, False, False, 5)
+        vbox.pack_start(srcbox, False, False, 2)
+        
+        # add pre-defined src paths to pull-down list
+        sympaths = [x[1] for x in ui.ui().configitems('paths')]
+        paths = list(set(sympaths + [x for x in self._recent_src]))
+        paths.sort()
+        for p in paths:
+            self._srclist.append([p])
+
+        # clone destination
+        destbox = gtk.HBox()
+        lbl = gtk.Label("Destination Path:")