Anonymous avatar Anonymous committed 9935bc5

convert all text files to Unix format

Comments (0)

Files changed (32)

-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
-                    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 -
-
-
+                    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()
-#
-# 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()
+#
+# 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()

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)
-#
-# 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)

hggtk/changeset.py

-#
-# changeset.py - Changeset dialog for TortoiseHg
-#
-# Copyright 2008 Steve Borho <steve@borho.org>
-#
-
-import os
-import subprocess
-import sys
-import time
-
-import pygtk
-pygtk.require('2.0')
-import gtk
-import gobject
-import pango
-import StringIO
-
-from mercurial.i18n import _
-from mercurial.node import *
-from mercurial import cmdutil, util, ui, hg, commands
-from mercurial import context, patch, revlog
-from gdialog import *
-from hgcmd import CmdDialog
-from hglib import toutf, fromutf
-from gtklib import StatusBar
-
-
-class ChangeSet(GDialog):
-    """GTK+ based dialog for displaying repository logs
-    """
-    def __init__(self, ui, repo, cwd, pats, opts, main, stbar=None):
-        GDialog.__init__(self, ui, repo, cwd, pats, opts, main)
-        self.stbar = stbar
-
-    def get_title(self):
-        title = os.path.basename(self.repo.root) + ' changeset '
-        title += self.opts['rev'][0]
-        return title
-
-    def get_icon(self):
-        return 'menushowchanged.ico'
-
-    def get_tbbuttons(self):
-        self.parent_toggle = gtk.ToggleToolButton(gtk.STOCK_UNDO)
-        self.parent_toggle.set_use_underline(True)
-        self.parent_toggle.set_label('_other parent')
-        self.parent_toggle.set_tooltip(self.tooltips, 'diff other parent')
-        self.parent_toggle.set_sensitive(False)
-        self.parent_toggle.set_active(False)
-        self.parent_toggle.connect('toggled', self._parent_toggled)
-        return [self.parent_toggle]
-
-    def _parent_toggled(self, button):
-        self.load_details(self.currev)
-
-    def prepare_display(self):
-        self.currow = None
-        self.graphview = None
-        self.glog_parent = None
-        node0, node1 = cmdutil.revpair(self.repo, self.opts.get('rev'))
-        self.load_details(self.repo.changelog.rev(node0))
-
-    def save_settings(self):
-        settings = GDialog.save_settings(self)
-        settings['changeset'] = self._hpaned.get_position()
-        return settings
-
-    def load_settings(self, settings):
-        GDialog.load_settings(self, settings)
-        if settings and 'changeset' in settings:
-            self._setting_hpos = settings['changeset']
-        else:
-            self._setting_hpos = -1
-
-    def load_details(self, rev):
-        '''Load selected changeset details into buffer and filelist'''
-        self.currev = rev
-        self._buffer.set_text('')
-        self._filelist.clear()
-
-        parents = [x for x in self.repo.changelog.parentrevs(rev) \
-                if x != nullrev]
-        self.parents = parents
-        title = self.get_title()
-        if len(parents) == 2:
-            self.parent_toggle.set_sensitive(True)
-            if self.parent_toggle.get_active():
-                title += ':' + str(self.parents[1])
-            else:
-                title += ':' + str(self.parents[0])
-        else:
-            self.parent_toggle.set_sensitive(False)
-            if self.parent_toggle.get_active():
-                # Parent button must be pushed out, but this
-                # will cause load_details to be called again
-                # so we exit out to prevent recursion.
-                self.parent_toggle.set_active(False)
-                return
-
-        ctx = self.repo.changectx(rev)
-        if not ctx:
-            self._last_rev = None
-            return False
-        self.set_title(title)
-        self.textview.freeze_child_notify()
-        try:
-            self._fill_buffer(self._buffer, rev, ctx, self._filelist)
-        finally:
-            self.textview.thaw_child_notify()
-
-    def _fill_buffer(self, buf, rev, ctx, filelist):
-        self.stbar.begin('Retrieving changeset data...')
-        
-        def title_line(title, text, tag):
-            pad = ' ' * (12 - len(title))
-            utext = toutf(title + pad + text)
-            buf.insert_with_tags_by_name(eob, utext, tag)
-            buf.insert(eob, "\n")
-
-        # TODO: Add toggle for gmtime/localtime
-        eob = buf.get_end_iter()
-        date = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(ctx.date()[0]))
-        if self.clipboard:
-            self.clipboard.set_text(short(ctx.node()))
-        change = str(rev) + ':' + short(ctx.node())
-        tags = ' '.join(ctx.tags())
-        parents = self.parents
-
-        title_line('changeset:', change, 'changeset')
-        if ctx.branch() != 'default':
-            title_line('branch:', ctx.branch(), 'greybg')
-        title_line('user/date:', ctx.user() + '\t' + date, 'changeset')
-        for p in parents:
-            pctx = self.repo.changectx(p)
-            summary = pctx.description().splitlines()[0]
-            summary = toutf(summary)
-            change = str(p) + ':' + short(self.repo.changelog.node(p))
-            title = 'parent:'
-            title += ' ' * (12 - len(title))
-            buf.insert_with_tags_by_name(eob, title, 'parent')
-            buf.insert_with_tags_by_name(eob, change, 'link')
-            buf.insert_with_tags_by_name(eob, ' ' + summary, 'parent')
-            buf.insert(eob, "\n")
-        for n in self.repo.changelog.children(ctx.node()):
-            cctx = self.repo.changectx(n)
-            summary = cctx.description().splitlines()[0]
-            summary = toutf(summary)
-            childrev = self.repo.changelog.rev(n)
-            change = str(childrev) + ':' + short(n)
-            title = 'child:'
-            title += ' ' * (12 - len(title))
-            buf.insert_with_tags_by_name(eob, title, 'parent')
-            buf.insert_with_tags_by_name(eob, change, 'link')
-            buf.insert_with_tags_by_name(eob, ' ' + summary, 'parent')
-            buf.insert(eob, "\n")
-        for n in self.repo.changelog.children(ctx.node()):
-            childrev = self.repo.changelog.rev(n)
-        if tags: title_line('tags:', tags, 'tag')
-
-        log = toutf(ctx.description())
-        buf.insert(eob, '\n' + log + '\n\n')
-
-        if self.parent_toggle.get_active():
-            parent = self.repo.changelog.node(parents[1])
-        elif parents:
-            parent = self.repo.changelog.node(parents[0])
-        else:
-            parent = nullid
-
-        buf.create_mark('begmark', buf.get_start_iter())
-        filelist.append(('*', '[Description]', 'begmark', False, ()))
-        pctx = self.repo.changectx(parent)
-
-        nodes = parent, ctx.node()
-        iterator = self.diff_generator(*nodes)
-        gobject.idle_add(self.get_diffs, iterator, nodes, pctx, buf, filelist)
-        self.curnodes = nodes
-
-    def get_diffs(self, iterator, nodes, pctx, buf, filelist):
-        if self.curnodes != nodes:
-            return False
-
-        try:
-            status, file, txt = iterator.next()
-        except StopIteration:
-            self.stbar.end()
-            return False
-
-        lines = txt.splitlines()
-        eob = buf.get_end_iter()
-        offset = eob.get_offset()
-        fileoffs, tags, lines, statmax = self.prepare_diff(lines, offset, file)
-        for l in lines:
-            buf.insert(eob, l)
-
-        # inserts the tags
-        for name, p0, p1 in tags:
-            i0 = buf.get_iter_at_offset(p0)
-            i1 = buf.get_iter_at_offset(p1)
-            txt = buf.get_text(i0, i1)
-            buf.apply_tag_by_name(name, i0, i1)
-            
-        # inserts the marks
-        for mark, offset, stats in fileoffs:
-            pos = buf.get_iter_at_offset(offset)
-            mark = 'mark_%d' % offset
-            buf.create_mark(mark, pos)
-            filelist.append((status, toutf(file), mark, True, stats))
-        sob, eob = buf.get_bounds()
-        buf.apply_tag_by_name("mono", pos, eob)
-        return True
-
-    # Hacked up version of mercurial.patch.diff()
-    # Use git mode by default (to show copies, renames, permissions) but
-    # never show binary diffs.  It operates as a generator, so it can be
-    # called iteratively to get file diffs from a changeset
-    def diff_generator(self, node1, node2):
-        repo = self.repo
-
-        ccache = {}
-        def getctx(r):
-            if r not in ccache:
-                ccache[r] = context.changectx(repo, r)
-            return ccache[r]
-
-        flcache = {}
-        def getfilectx(f, ctx):
-            flctx = ctx.filectx(f, filelog=flcache.get(f))
-            if f not in flcache:
-                flcache[f] = flctx._filelog
-            return flctx
-
-        ctx1 = context.changectx(repo, node1) # parent
-        ctx2 = context.changectx(repo, node2) # current
-
-        if node1 == repo.changelog.parents(node2)[0]:
-            filelist = ctx2.files()
-        else:
-            changes = repo.status(node1, node2, None)[:5]
-            modified, added, removed, deleted, unknown = changes
-            filelist = modified + added + removed
-
-
-        # force manifest reading
-        man1 = ctx1.manifest()
-        date1 = util.datestr(ctx1.date())
-
-        execf2 = ctx2.manifest().execf
-        linkf2 = ctx2.manifest().linkf
-
-        # returns False if there was no rename between ctx1 and ctx2
-        # returns None if the file was created between ctx1 and ctx2
-        # returns the (file, node) present in ctx1 that was renamed to f in ctx2
-        # This will only really work if c1 is the Nth 1st parent of c2.
-        def renamed(c1, c2, man, f):
-            startrev = c1.rev()
-            c = c2
-            crev = c.rev()
-            if crev is None:
-                crev = repo.changelog.count()
-            orig = f
-            files = (f,)
-            while crev > startrev:
-                if f in files:
-                    try:
-                        src = getfilectx(f, c).renamed()
-                    except revlog.LookupError:
-                        return None
-                    if src:
-                        f = src[0]
-                crev = c.parents()[0].rev()
-                # try to reuse
-                c = getctx(crev)
-                files = c.files()
-            if f not in man:
-                return None
-            if f == orig:
-                return False
-            return f
-
-        status = {}
-        def filestatus(f):
-            if f in status:
-                return status[f]
-            try:
-                # Determine file status by presence in manifests
-                s = 'R'
-                ctx2.filectx(f)
-                s = 'A'
-                ctx1.filectx(f)
-                s = 'M'
-            except revlog.LookupError:
-                pass
-            status[f] = s
-            return s
-
-        copied = {}
-        for f in filelist:
-            src = renamed(ctx1, ctx2, man1, f)
-            if src:
-                copied[f] = src
-
-        srcs = [x[1] for x in copied.iteritems() if filestatus(x[0]) == 'A']
-
-        gone = {}
-        for f in filelist:
-            s = filestatus(f)
-            to = None
-            tn = None
-            dodiff = True
-            header = []
-            if f in man1:
-                to = getfilectx(f, ctx1).data()
-            if s != 'R':
-                tn = getfilectx(f, ctx2).data()
-            a, b = f, f
-            def gitmode(x, l):
-                return l and '120000' or (x and '100755' or '100644')
-            def addmodehdr(header, omode, nmode):
-                if omode != nmode:
-                    header.append('old mode %s\n' % omode)
-                    header.append('new mode %s\n' % nmode)
-
-            if s == 'A':
-                mode = gitmode(execf2(f), linkf2(f))
-                if f in copied:
-                    a = copied[f]
-                    omode = gitmode(man1.execf(a), man1.linkf(a))
-                    addmodehdr(header, omode, mode)
-                    if filestatus(a) == 'R' and a not in gone:
-                        op = 'rename'
-                        gone[a] = 1
-                    else:
-                        op = 'copy'
-                    header.append('%s from %s\n' % (op, a))
-                    header.append('%s to %s\n' % (op, f))
-                    to = getfilectx(a, ctx1).data()
-                else:
-                    header.append('new file mode %s\n' % mode)
-                if util.binary(tn):
-                    dodiff = 'binary'
-            elif s == 'R':
-                if f in srcs:
-                    dodiff = False
-                else:
-                    mode = gitmode(man1.execf(f), man1.linkf(f))
-                    header.append('deleted file mode %s\n' % mode)
-            else:
-                omode = gitmode(man1.execf(f), man1.linkf(f))
-                nmode = gitmode(execf2(f), linkf2(f))
-                addmodehdr(header, omode, nmode)
-                if util.binary(to) or util.binary(tn):
-                    dodiff = 'binary'
-            header.insert(0, 'diff --git a/%s b/%s\n' % (a, b))
-            if dodiff == 'binary':
-                text = 'binary file has changed.\n'
-            elif dodiff:
-                try:
-                    text = patch.mdiff.unidiff(to, date1,
-                                    tn, util.datestr(ctx2.date()),
-                                    fn1=a, fn2=b, r=None,
-                                    opts=patch.mdiff.defaultopts)
-                except TypeError:
-                    # hg-0.9.5 and before
-                    text = patch.mdiff.unidiff(to, date1,
-                                    tn, util.datestr(ctx2.date()),
-                                    f, None, opts=patch.mdiff.defaultopts)
-            else:
-                text = ''
-            if header or text: yield (s, f, ''.join(header) + text)
-
-    def prepare_diff(self, difflines, offset, fname):
-        '''Borrowed from hgview; parses changeset diffs'''
-        DIFFHDR = "=== %s ===\n"
-        idx = 0
-        outlines = []
-        tags = []
-        filespos = []
-        def addtag( name, offset, length ):
-            if tags and tags[-1][0] == name and tags[-1][2]==offset:
-                tags[-1][2] += length
-            else:
-                tags.append( [name, offset, offset+length] )
-        stats = [0,0]
-        statmax = 0
-        for i,l1 in enumerate(difflines):
-            l = toutf(l1)
-            if l.startswith("diff"):
-                txt = toutf(DIFFHDR % fname)
-                addtag( "greybg", offset, len(txt) )
-                outlines.append(txt)
-                markname = "file%d" % idx
-                idx += 1
-                statmax = max( statmax, stats[0]+stats[1] )
-                stats = [0,0]
-                filespos.append(( markname, offset, stats ))
-                offset += len(txt.decode('utf-8'))
-                continue
-            elif l.startswith("+++"):
-                continue
-            elif l.startswith("---"):
-                continue
-            elif l.startswith("+"):
-                tag = "green"
-                stats[0] += 1
-            elif l.startswith("-"):
-                stats[1] += 1
-                tag = "red"
-            elif l.startswith("@@"):
-                tag = "blue"
-            else:
-                tag = "black"
-            l = l+"\n"
-            length = len(l.decode('utf-8'))
-            addtag( tag, offset, length )
-            outlines.append( l )
-            offset += length
-        statmax = max( statmax, stats[0]+stats[1] )
-        return filespos, tags, outlines, statmax
-
-    def link_event(self, tag, widget, event, iter):
-        if event.type != gtk.gdk.BUTTON_RELEASE:
-            return
-        text = self.get_link_text(tag, widget, iter)
-        if not text:
-            return
-        linkrev = long(text.split(':')[0])
-        if self.graphview:
-            self.graphview.set_revision_id(linkrev)
-            self.graphview.scroll_to_revision(linkrev)
-        else:
-            self.load_details(linkrev)
-
-    def get_link_text(self, tag, widget, iter):
-        """handle clicking on a link in a textview"""
-        text_buffer = widget.get_buffer()
-        beg = iter.copy()
-        while not beg.begins_tag(tag):
-            beg.backward_char()
-        end = iter.copy()
-        while not end.ends_tag(tag):
-            end.forward_char()
-        text = text_buffer.get_text(beg, end)
-        return text
-        
-    def file_context_menu(self):
-        def create_menu(label, callback):
-            menuitem = gtk.MenuItem(label, True)
-            menuitem.connect('activate', callback)
-            menuitem.set_border_width(1)
-            return menuitem
-            
-        _menu = gtk.Menu()
-        _menu.append(create_menu('_view at revision', self._view_file_rev))
-        self._save_menu = create_menu('_save at revision', self._save_file_rev)
-        _menu.append(self._save_menu)
-        _menu.append(create_menu('_file history', self._file_history))
-        self._ann_menu = create_menu('_annotate file', self._ann_file)
-        _menu.append(self._ann_menu)
-        _menu.append(create_menu('_revert file contents', self._revert_file))
-        self._file_diff_to_mark_menu = create_menu('_diff file to mark',
-                self._diff_file_to_mark)
-        self._file_diff_from_mark_menu = create_menu('diff file _from mark',
-                self._diff_file_from_mark)
-        _menu.append(self._file_diff_to_mark_menu)
-        _menu.append(self._file_diff_from_mark_menu)
-        _menu.show_all()
-        return _menu
-
-    def get_body(self):
-        if self.repo.ui.configbool('tortoisehg', 'copyhash'):
-            sel = (os.name == 'nt') and 'CLIPBOARD' or 'PRIMARY'
-            self.clipboard = gtk.Clipboard(selection=sel)
-        else:
-            self.clipboard = None
-        self._filemenu = self.file_context_menu()
-
-        details_frame = gtk.Frame()
-        details_frame.set_shadow_type(gtk.SHADOW_ETCHED_IN)
-        scroller = gtk.ScrolledWindow()
-        scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
-        details_frame.add(scroller)
-        
-        details_text = gtk.TextView()
-        details_text.set_wrap_mode(gtk.WRAP_NONE)
-        details_text.set_editable(False)
-        details_text.modify_font(pango.FontDescription(self.fontcomment))
-        scroller.add(details_text)
-
-        self._buffer = gtk.TextBuffer()
-        self.setup_tags()
-        details_text.set_buffer(self._buffer)
-        self.textview = details_text
-
-        filelist_tree = gtk.TreeView()
-        filesel = filelist_tree.get_selection()
-        filesel.connect("changed", self._filelist_rowchanged)
-        filelist_tree.connect('button-release-event',
-                self._file_button_release)
-        filelist_tree.connect('popup-menu', self._file_popup_menu)
-        filelist_tree.connect('row-activated', self._file_row_act)
-
-        self._filelist = gtk.ListStore(
-                gobject.TYPE_STRING,   # MAR status
-                gobject.TYPE_STRING,   # filename (utf-8 encoded)
-                gobject.TYPE_PYOBJECT, # mark
-                gobject.TYPE_PYOBJECT, # give cmenu
-                gobject.TYPE_PYOBJECT, # diffstats
-                )
-        filelist_tree.set_model(self._filelist)
-        column = gtk.TreeViewColumn('Stat', gtk.CellRendererText(), text=0)
-        filelist_tree.append_column(column)
-        column = gtk.TreeViewColumn('Files', gtk.CellRendererText(), text=1)
-        filelist_tree.append_column(column)
-
-        list_frame = gtk.Frame()
-        list_frame.set_shadow_type(gtk.SHADOW_ETCHED_IN)
-        scroller = gtk.ScrolledWindow()
-        scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
-        scroller.add(filelist_tree)
-        list_frame.add(scroller)
-
-        self._hpaned = gtk.HPaned()
-        self._hpaned.pack1(list_frame, True, True)
-        self._hpaned.pack2(details_frame, True, True)
-        self._hpaned.set_position(self._setting_hpos)
-
-        if self.stbar:
-            # embedded by changelog browser
-            return self._hpaned
-        else:
-            # add status bar for main app
-            vbox = gtk.VBox()
-            vbox.pack_start(self._hpaned, True, True)
-            self.stbar = StatusBar()
-            self.stbar.show()
-            vbox.pack_start(gtk.HSeparator(), False, False)
-            vbox.pack_start(self.stbar, False, False)
-            return vbox
-
-    def setup_tags(self):
-        """Creates the tags to be used inside the TextView"""
-        def make_texttag( name, **kwargs ):
-            """Helper function generating a TextTag"""
-            tag = gtk.TextTag(name)
-            for key, value in kwargs.iteritems():
-                key = key.replace("_","-")
-                try:
-                    tag.set_property( key, value )
-                except TypeError:
-                    print "Warning the property %s is unsupported in" % key
-                    print "this version of pygtk"
-            return tag
-
-        tag_table = self._buffer.get_tag_table()
-
-        tag_table.add( make_texttag('changeset', foreground='#000090',
-                paragraph_background='#F0F0F0'))
-        tag_table.add(make_texttag('date', foreground='#000090',
-                paragraph_background='#F0F0F0'))
-        tag_table.add(make_texttag('tag', foreground='#000090',
-                paragraph_background='#F0F0F0'))
-        tag_table.add(make_texttag('files', foreground='#5C5C5C',
-                paragraph_background='#F0F0F0'))
-        tag_table.add(make_texttag('parent', foreground='#000090',
-                paragraph_background='#F0F0F0'))
-
-        tag_table.add( make_texttag( "mono", family="Monospace" ))
-        tag_table.add( make_texttag( "blue", foreground='blue' ))
-        tag_table.add( make_texttag( "red", foreground='red' ))
-        tag_table.add( make_texttag( "green", foreground='darkgreen' ))
-        tag_table.add( make_texttag( "black", foreground='black' ))
-        tag_table.add( make_texttag( "greybg",
-                                     paragraph_background='grey',
-                                     weight=pango.WEIGHT_BOLD ))
-        tag_table.add( make_texttag( "yellowbg", background='yellow' ))
-        link_tag = make_texttag( "link", foreground="blue",
-                                 underline=pango.UNDERLINE_SINGLE )
-        link_tag.connect("event", self.link_event )
-        tag_table.add( link_tag )
-
-    def _filelist_rowchanged(self, sel):
-        model, iter = sel.get_selected()
-        if not iter:
-            return
-        # scroll to file in details window
-        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 = fromutf(model[iter][1])
-        else:
-            self.curfile = None
-
-    def _file_button_release(self, widget, event):
-        if event.button == 3 and not (event.state & (gtk.gdk.SHIFT_MASK |
-            gtk.gdk.CONTROL_MASK)):
-            self._file_popup_menu(widget, event.button, event.time)
-        return False
-
-    def _file_popup_menu(self, treeview, button=0, time=0):
-        if self.curfile is None:
-            return
-        if self.graphview:
-            is_mark = self.graphview.get_mark_rev() is not None
-        else:
-            is_mark = False
-        self._file_diff_to_mark_menu.set_sensitive(is_mark)
-        self._file_diff_from_mark_menu.set_sensitive(is_mark)
-        self._filemenu.popup(None, None, None, button, time)
-
-        # If the filelog entry this changeset references does not link
-        # back to this changeset, it means this changeset did not
-        # actually change the contents of this file, and thus the file
-        # cannot be annotated at this revision (since this changeset
-        # does not appear in the filelog)
-        ctx = self.repo.changectx(self.currev)
-        try:
-            fctx = ctx.filectx(self.curfile)
-            has_filelog = fctx.filelog().linkrev(fctx.filenode()) == ctx.rev()
-        except revlog.LookupError:
-            has_filelog = False
-        self._ann_menu.set_sensitive(has_filelog)
-        self._save_menu.set_sensitive(has_filelog)
-        return True
-
-    def _file_row_act(self, tree, path, column) :
-        """Default action is the first entry in the context menu
-        """
-        self._filemenu.get_children()[0].activate()
-        return True
-
-    def _save_file_rev(self, menuitem):
-        file = util.localpath(self.curfile)
-        file, ext = os.path.splitext(os.path.basename(file))
-        filename = "%s@%d%s" % (file, self.currev, ext)
-        fd = NativeSaveFileDialogWrapper(Title = "Save file to",
-                                         InitialDir=self.cwd,
-                                         FileName=filename)
-        result = fd.run()
-        if result:
-            import Queue
-            import hglib
-            q = Queue.Queue()
-            cpath = util.canonpath(self.repo.root, self.cwd, self.curfile)
-            hglib.hgcmd_toq(self.repo.root, q, 'cat', '--rev',
-                str(self.currev), '--output', result, cpath)
-
-    def _view_file_rev(self, menuitem):
-        '''User selected view file revision from the file list context menu'''
-        if not self.curfile:
-            # ignore view events for the [Description] row
-            return
-        rev = self.currev
-        parents = self.parents
-        if len(parents) == 0:
-            parent = rev-1
-        else:
-            parent = parents[0]
-        pair = '%u:%u' % (parent, rev)
-        self._node1, self._node2 = cmdutil.revpair(self.repo, [pair])
-        self._view_file('M', self.curfile, force_left=False)
-
-    def _diff_file_to_mark(self, menuitem):
-        '''User selected diff to mark from the file list context menu'''
-        from status import GStatus
-        from gtools import cmdtable
-        rev0 = self.graphview.get_mark_rev()
-        rev1 = self.currev
-        statopts = self.merge_opts(cmdtable['gstatus|gst'][1],
-                ('include', 'exclude', 'git'))
-        statopts['rev'] = ['%u:%u' % (rev1, rev0)]
-        statopts['modified'] = True
-        statopts['added'] = True
-        statopts['removed'] = True
-        dialog = GStatus(self.ui, self.repo, self.cwd, [self.curfile],
-                statopts, False)
-        dialog.display()
-        return True
-
-    def _diff_file_from_mark(self, menuitem):
-        '''User selected diff from mark from the file list context menu'''
-        from status import GStatus
-        from gtools import cmdtable
-        rev0 = self.graphview.get_mark_rev()
-        rev1 = self.currev
-        statopts = self.merge_opts(cmdtable['gstatus|gst'][1],
-                ('include', 'exclude', 'git'))
-        statopts['rev'] = ['%u:%u' % (rev0, rev1)]
-        statopts['modified'] = True
-        statopts['added'] = True
-        statopts['removed'] = True
-        dialog = GStatus(self.ui, self.repo, self.cwd, [self.curfile],
-                statopts, False)
-        dialog.display()
-
-    def _ann_file(self, menuitem):
-        '''User selected diff from mark from the file list context menu'''
-        from datamine import DataMineDialog
-        rev = self.currev
-        dialog = DataMineDialog(self.ui, self.repo, self.cwd, [], {}, False)
-        dialog.display()
-        dialog.add_annotate_page(self.curfile, str(rev))
-
-    def _file_history(self, menuitem):
-        '''User selected file history from file list context menu'''
-        if self.glog_parent:
-            # If this changeset browser is embedded in glog, send
-            # send this event to the main app
-            opts = {'filehist' : self.curfile}
-            self.glog_parent.custombutton.set_active(True)
-            self.glog_parent.graphview.refresh(True, None, opts)
-        else:
-            # Else launch our own GLog instance
-            from history import GLog
-            dialog = GLog(self.ui, self.repo, self.cwd, [self.repo.root],
-                    {}, False)
-            dialog.open_with_file(self.curfile)
-            dialog.display()
-
-    def _revert_file(self, menuitem):
-        '''User selected file revert from the file list context menu'''
-        rev = self.currev
-        dialog = Confirm('revert file to old revision', [], self,
-                'Revert %s to contents at revision %d?' % (self.curfile, rev))
-        if dialog.run() == gtk.RESPONSE_NO:
-            return
-        cmdline = ['hg', 'revert', '--verbose', '--rev', str(rev), self.curfile]
-        dlg = CmdDialog(cmdline)
-        dlg.run()
-        dlg.hide()
-        shell_notify([self.curfile])
-
-def run(root='', cwd='', files=[], **opts):
-    u = ui.ui()
-    u.updateopts(debug=False, traceback=False)
-    repo = hg.repository(u, path=root)
-
-    dialog = ChangeSet(u, repo, cwd, files, opts, True)
-    dialog.display()
-
-    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()
-    opts['rev'] = ['750']
-    run(**opts)
+#
+# changeset.py - Changeset dialog for TortoiseHg
+#
+# Copyright 2008 Steve Borho <steve@borho.org>
+#
+
+import os
+import subprocess
+import sys
+import time
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import gobject
+import pango
+import StringIO
+
+from mercurial.i18n import _
+from mercurial.node import *
+from mercurial import cmdutil, util, ui, hg, commands
+from mercurial import context, patch, revlog
+from gdialog import *
+from hgcmd import CmdDialog
+from hglib import toutf, fromutf
+from gtklib import StatusBar
+
+
+class ChangeSet(GDialog):
+    """GTK+ based dialog for displaying repository logs
+    """
+    def __init__(self, ui, repo, cwd, pats, opts, main, stbar=None):
+        GDialog.__init__(self, ui, repo, cwd, pats, opts, main)
+        self.stbar = stbar
+
+    def get_title(self):
+        title = os.path.basename(self.repo.root) + ' changeset '
+        title += self.opts['rev'][0]
+        return title
+
+    def get_icon(self):
+        return 'menushowchanged.ico'
+
+    def get_tbbuttons(self):
+        self.parent_toggle = gtk.ToggleToolButton(gtk.STOCK_UNDO)
+        self.parent_toggle.set_use_underline(True)
+        self.parent_toggle.set_label('_other parent')
+        self.parent_toggle.set_tooltip(self.tooltips, 'diff other parent')
+        self.parent_toggle.set_sensitive(False)
+        self.parent_toggle.set_active(False)
+        self.parent_toggle.connect('toggled', self._parent_toggled)
+        return [self.parent_toggle]
+
+    def _parent_toggled(self, button):
+        self.load_details(self.currev)
+
+    def prepare_display(self):
+        self.currow = None
+        self.graphview = None
+        self.glog_parent = None
+        node0, node1 = cmdutil.revpair(self.repo, self.opts.get('rev'))
+        self.load_details(self.repo.changelog.rev(node0))
+
+    def save_settings(self):
+        settings = GDialog.save_settings(self)
+        settings['changeset'] = self._hpaned.get_position()
+        return settings
+
+    def load_settings(self, settings):
+        GDialog.load_settings(self, settings)
+        if settings and 'changeset' in settings:
+            self._setting_hpos = settings['changeset']
+        else:
+            self._setting_hpos = -1
+
+    def load_details(self, rev):
+        '''Load selected changeset details into buffer and filelist'''
+        self.currev = rev
+        self._buffer.set_text('')
+        self._filelist.clear()
+
+        parents = [x for x in self.repo.changelog.parentrevs(rev) \
+                if x != nullrev]
+        self.parents = parents
+        title = self.get_title()
+        if len(parents) == 2:
+            self.parent_toggle.set_sensitive(True)
+            if self.parent_toggle.get_active():
+                title += ':' + str(self.parents[1])
+            else:
+                title += ':' + str(self.parents[0])
+        else:
+            self.parent_toggle.set_sensitive(False)
+            if self.parent_toggle.get_active():
+                # Parent button must be pushed out, but this
+                # will cause load_details to be called again
+                # so we exit out to prevent recursion.
+                self.parent_toggle.set_active(False)
+                return
+
+        ctx = self.repo.changectx(rev)
+        if not ctx:
+            self._last_rev = None
+            return False
+        self.set_title(title)
+        self.textview.freeze_child_notify()
+        try:
+            self._fill_buffer(self._buffer, rev, ctx, self._filelist)
+        finally:
+            self.textview.thaw_child_notify()
+
+    def _fill_buffer(self, buf, rev, ctx, filelist):
+        self.stbar.begin('Retrieving changeset data...')
+        
+        def title_line(title, text, tag):
+            pad = ' ' * (12 - len(title))
+            utext = toutf(title + pad + text)
+            buf.insert_with_tags_by_name(eob, utext, tag)
+            buf.insert(eob, "\n")
+
+        # TODO: Add toggle for gmtime/localtime
+        eob = buf.get_end_iter()
+        date = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(ctx.date()[0]))
+        if self.clipboard:
+            self.clipboard.set_text(short(ctx.node()))
+        change = str(rev) + ':' + short(ctx.node())
+        tags = ' '.join(ctx.tags())
+        parents = self.parents
+
+        title_line('changeset:', change, 'changeset')
+        if ctx.branch() != 'default':
+            title_line('branch:', ctx.branch(), 'greybg')
+        title_line('user/date:', ctx.user() + '\t' + date, 'changeset')
+        for p in parents:
+            pctx = self.repo.changectx(p)
+            summary = pctx.description().splitlines()[0]
+            summary = toutf(summary)
+            change = str(p) + ':' + short(self.repo.changelog.node(p))
+            title = 'parent:'
+            title += ' ' * (12 - len(title))
+            buf.insert_with_tags_by_name(eob, title, 'parent')
+            buf.insert_with_tags_by_name(eob, change, 'link')
+            buf.insert_with_tags_by_name(eob, ' ' + summary, 'parent')
+            buf.insert(eob, "\n")
+        for n in self.repo.changelog.children(ctx.node()):
+            cctx = self.repo.changectx(n)
+            summary = cctx.description().splitlines()[0]
+            summary = toutf(summary)
+            childrev = self.repo.changelog.rev(n)
+            change = str(childrev) + ':' + short(n)
+            title = 'child:'
+            title += ' ' * (12 - len(title))
+            buf.insert_with_tags_by_name(eob, title, 'parent')
+            buf.insert_with_tags_by_name(eob, change, 'link')
+            buf.insert_with_tags_by_name(eob, ' ' + summary, 'parent')
+            buf.insert(eob, "\n")
+        for n in self.repo.changelog.children(ctx.node()):
+            childrev = self.repo.changelog.rev(n)
+        if tags: title_line('tags:', tags, 'tag')
+
+        log = toutf(ctx.description())
+        buf.insert(eob, '\n' + log + '\n\n')
+
+        if self.parent_toggle.get_active():
+            parent = self.repo.changelog.node(parents[1])
+        elif parents:
+            parent = self.repo.changelog.node(parents[0])
+        else:
+            parent = nullid
+
+        buf.create_mark('begmark', buf.get_start_iter())
+        filelist.append(('*', '[Description]', 'begmark', False, ()))
+        pctx = self.repo.changectx(parent)
+
+        nodes = parent, ctx.node()
+        iterator = self.diff_generator(*nodes)
+        gobject.idle_add(self.get_diffs, iterator, nodes, pctx, buf, filelist)
+        self.curnodes = nodes
+
+    def get_diffs(self, iterator, nodes, pctx, buf, filelist):
+        if self.curnodes != nodes:
+            return False
+
+        try:
+            status, file, txt = iterator.next()
+        except StopIteration:
+            self.stbar.end()
+            return False
+
+        lines = txt.splitlines()
+        eob = buf.get_end_iter()
+        offset = eob.get_offset()
+        fileoffs, tags, lines, statmax = self.prepare_diff(lines, offset, file)
+        for l in lines:
+            buf.insert(eob, l)
+
+        # inserts the tags
+        for name, p0, p1 in tags:
+            i0 = buf.get_iter_at_offset(p0)
+            i1 = buf.get_iter_at_offset(p1)
+            txt = buf.get_text(i0, i1)
+            buf.apply_tag_by_name(name, i0, i1)
+            
+        # inserts the marks
+        for mark, offset, stats in fileoffs:
+            pos = buf.get_iter_at_offset(offset)
+            mark = 'mark_%d' % offset
+            buf.create_mark(mark, pos)
+            filelist.append((status, toutf(file), mark, True, stats))
+        sob, eob = buf.get_bounds()
+        buf.apply_tag_by_name("mono", pos, eob)
+        return True
+
+    # Hacked up version of mercurial.patch.diff()
+    # Use git mode by default (to show copies, renames, permissions) but
+    # never show binary diffs.  It operates as a generator, so it can be
+    # called iteratively to get file diffs from a changeset
+    def diff_generator(self, node1, node2):
+        repo = self.repo
+
+        ccache = {}
+        def getctx(r):
+            if r not in ccache:
+                ccache[r] = context.changectx(repo, r)
+            return ccache[r]
+
+        flcache = {}
+        def getfilectx(f, ctx):
+            flctx = ctx.filectx(f, filelog=flcache.get(f))
+            if f not in flcache:
+                flcache[f] = flctx._filelog
+            return flctx
+
+        ctx1 = context.changectx(repo, node1) # parent
+        ctx2 = context.changectx(repo, node2) # current
+
+        if node1 == repo.changelog.parents(node2)[0]:
+            filelist = ctx2.files()
+        else:
+            changes = repo.status(node1, node2, None)[:5]
+            modified, added, removed, deleted, unknown = changes
+            filelist = modified + added + removed
+
+
+        # force manifest reading
+        man1 = ctx1.manifest()
+        date1 = util.datestr(ctx1.date())
+
+        execf2 = ctx2.manifest().execf
+        linkf2 = ctx2.manifest().linkf
+
+        # returns False if there was no rename between ctx1 and ctx2
+        # returns None if the file was created between ctx1 and ctx2
+        # returns the (file, node) present in ctx1 that was renamed to f in ctx2
+        # This will only really work if c1 is the Nth 1st parent of c2.
+        def renamed(c1, c2, man, f):
+            startrev = c1.rev()
+            c = c2
+            crev = c.rev()
+            if crev is None:
+                crev = repo.changelog.count()
+            orig = f
+            files = (f,)
+            while crev > startrev:
+                if f in files:
+                    try:
+                        src = getfilectx(f, c).renamed()
+                    except revlog.LookupError:
+                        return None
+                    if src:
+                        f = src[0]
+                crev = c.parents()[0].rev()
+                # try to reuse
+                c = getctx(crev)
+                files = c.files()
+            if f not in man:
+                return None
+            if f == orig:
+                return False
+            return f
+
+        status = {}
+        def filestatus(f):
+            if f in status:
+                return status[f]
+            try:
+                # Determine file status by presence in manifests
+                s = 'R'
+                ctx2.filectx(f)
+                s = 'A'
+                ctx1.filectx(f)
+                s = 'M'
+            except revlog.LookupError:
+                pass
+            status[f] = s
+            return s
+
+        copied = {}
+        for f in filelist:
+            src = renamed(ctx1, ctx2, man1, f)
+            if src:
+                copied[f] = src
+
+        srcs = [x[1] for x in copied.iteritems() if filestatus(x[0]) == 'A']
+
+        gone = {}
+        for f in filelist:
+            s = filestatus(f)
+            to = None
+            tn = None
+            dodiff = True
+            header = []
+            if f in man1:
+                to = getfilectx(f, ctx1).data()
+            if s != 'R':
+                tn = getfilectx(f, ctx2).data()
+            a, b = f, f
+            def gitmode(x, l):
+                return l and '120000' or (x and '100755' or '100644')
+            def addmodehdr(header, omode, nmode):
+                if omode != nmode:
+                    header.append('old mode %s\n' % omode)
+                    header.append('new mode %s\n' % nmode)
+
+            if s == 'A':
+                mode = gitmode(execf2(f), linkf2(f))
+                if f in copied:
+                    a = copied[f]
+                    omode = gitmode(man1.execf(a), man1.linkf(a))
+                    addmodehdr(header, omode, mode)
+                    if filestatus(a) == 'R' and a not in gone:
+                        op = 'rename'
+                        gone[a] = 1
+                    else:
+                        op = 'copy'
+                    header.append('%s from %s\n' % (op, a))
+                    header.append('%s to %s\n' % (op, f))
+                    to = getfilectx(a, ctx1).data()
+                else:
+                    header.append('new file mode %s\n' % mode)
+                if util.binary(tn):
+                    dodiff = 'binary'
+            elif s == 'R':
+                if f in srcs:
+                    dodiff = False
+                else:
+                    mode = gitmode(man1.execf(f), man1.linkf(f))
+                    header.append('deleted file mode %s\n' % mode)
+            else:
+                omode = gitmode(man1.execf(f), man1.linkf(f))
+                nmode = gitmode(execf2(f), linkf2(f))
+                addmodehdr(header, omode, nmode)
+                if util.binary(to) or util.binary(tn):
+                    dodiff = 'binary'
+            header.insert(0, 'diff --git a/%s b/%s\n' % (a, b))
+            if dodiff == 'binary':
+                text = 'binary file has changed.\n'
+            elif dodiff:
+                try:
+                    text = patch.mdiff.unidiff(to, date1,
+                                    tn, util.datestr(ctx2.date()),
+                                    fn1=a, fn2=b, r=None,
+                                    opts=patch.mdiff.defaultopts)
+                except TypeError:
+                    # hg-0.9.5 and before
+                    text = patch.mdiff.unidiff(to, date1,
+                                    tn, util.datestr(ctx2.date()),
+                                    f, None, opts=patch.mdiff.defaultopts)