Kiln » TortoiseHg » TortoiseHg
Clone URL:  
Pushed to one repository · View In Graph Contained in 1.0, 1.0.1, and 1.0.2

Merge with stable

Changeset 9b596dd36937

Parents bf49ab4a328e

Parents eb7942d9d12e

by Steve Borho

Changes to 75 files · Browse files at 9b596dd36937 Showing diff from parent bf49ab4a328e eb7942d9d12e Diff from another changeset...

Change 1 of 1 Show Entire File INSTALL.txt Stacked
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@@ -0,0 +1,25 @@
+** Please do not run setup.py ** + +On Linux, the suggested methods for using TortoiseHg are to either +install a package built for your distribution, or run directly out of a +cloned repository. For details, see: + +http://bitbucket.org/tortoisehg/stable/wiki/download + +http://bitbucket.org/tortoisehg/stable/wiki/hgtk + +http://bitbucket.org/tortoisehg/stable/wiki/nautilus + + +On Windows, we prefer you use the more recent stable release, which +can always be found at http://tortoisehg.org + + +If you ran setup.py and are now having troubles with icons, you have two +choices: + +1) Find the tortoisehg/util/config.py file that was installed and +manually edit it to fixup the paths. + +2) Delete the installation and use one of the preferred install methods. +
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
 
4
5
6
7
 
 
 
8
9
 
10
11
 
 
 
 
 
 
 
 
12
13
14
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
24
25
 
 
 
26
27
28
29
 
30
31
 
32
33
34
35
36
37
38
39
40
 
41
@@ -1,14 +1,41 @@
+# +# hgtk +# +# contrib/bash_completion +# +# Copyright 2009 Andreas Tscharner <andy@vis.ethz.ch> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 +# as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +  _hgtk()  { - local cur prev opts + local cur prev opts cmds   - COMPREPLY=() - cur="${COMP_WORDS[COMP_CWORD]}" - prev="${COMP_WORDS[COMP_CWORD-1]}" + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}"   - opts="about add annotate archive blame checkout clone commit datamine diff filter email forget grep guess hgignore history ignore init incoming log merge outgoing pull push recovery remove rename repoconfig revert rollback serve shelve status strip synch unshelve update userconfig vdiff verify version" + cmds="about add annotate archive blame checkout clone commit datamine diff email explorer filter forget grep guess hgignore history ignore init incoming log merge outgoing pull push recovery remove rename repoconfig revert rollback serve shelve status strip synch unshelve update userconfig vdiff verify version"   - COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + opts="-R --repository -v --verbose -q --quiet -h --help --debugger --nofork --fork --listfile" + + if [[ ${cur} == -* ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + else + COMPREPLY=( $(compgen -W "${cmds}" -- ${cur}) ) + fi + return 0  } -  complete -F _hgtk hgtk
 
25
26
27
28
 
29
30
31
 
40
41
42
43
 
44
45
46
 
107
108
109
110
 
111
112
113
 
25
26
27
 
28
29
30
31
 
40
41
42
 
43
44
45
46
 
107
108
109
 
110
111
112
113
@@ -25,7 +25,7 @@
 import subprocess  import urllib   -from mercurial import hg, ui, match, util +from mercurial import hg, ui, match, util, error  from mercurial.node import short    def _thg_path(): @@ -40,7 +40,7 @@
  sys.path.insert(0, thgpath)  _thg_path()   -from tortoisehg.util import paths, debugthg, hglib, cachethg +from tortoisehg.util import paths, debugthg, cachethg  from tortoisehg.hgtk import gtklib    if debugthg.debug('N'): @@ -107,7 +107,7 @@
  return None   try:   return hg.repository(ui.ui(), path=p) - except hglib.RepoError: + except error.RepoError:   return None   except StandardError, e:   debugf(e)
Change 1 of 9 Show Entire File contrib/​win32/​hgtk.iss Stacked
copied from contrib/win32/mercurial.iss
 
6
7
8
9
10
11
 
 
 
12
13
14
15
 
16
17
18
19
20
21
 
22
23
24
25
26
 
 
 
27
28
29
 
34
35
36
37
38
39
40
41
42
43
 
47
48
49
50
51
52
53
54
55
56
57
58
59
 
 
 
60
61
62
 
66
67
68
69
70
71
72
73
74
75
 
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
 
103
104
105
106
107
108
109
110
 
118
119
120
121
122
 
 
 
123
124
125
 
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
 
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
 
6
7
8
 
 
 
9
10
11
12
13
14
 
15
16
17
18
19
20
 
21
22
23
 
 
 
24
25
26
27
28
29
 
34
35
36
 
 
37
 
38
39
40
 
44
45
46
 
47
48
 
 
 
 
 
 
 
49
50
51
52
53
54
 
58
59
60
 
 
 
 
61
62
63
 
66
67
68
 
69
70
71
 
 
 
72
73
74
75
76
77
 
78
79
80
 
86
87
88
 
 
89
90
91
 
99
100
101
 
 
102
103
104
105
106
107
 
116
117
118
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
120
121
 
156
157
158
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
@@ -6,24 +6,24 @@
 #endif    [Setup] -AppCopyright=Copyright 2005-2009 Matt Mackall and others -AppName=TortoiseHg -AppVerName=TortoiseHg {#VERSION} +AppCopyright=Copyright 2005-2009 Steve Borho and others +AppName=hgtk +AppVerName=hgtk {#VERSION}  InfoAfterFile=contrib/win32/postinstall.txt  LicenseFile=COPYING.txt  ShowLanguageDialog=yes -AppPublisher=Steve Borho and others +AppPublisher=Steve Borho  AppPublisherURL=http://tortoisehg.org/  AppSupportURL=http://tortoisehg.org/  AppUpdatesURL=http://tortoisehg.org/  AppID=TortoiseHg  AppContact=Steve Borho <steve@borho.org> -OutputBaseFilename=TortoiseHg-{#VERSION} +OutputBaseFilename=Hgtk-{#VERSION}  DefaultDirName={pf}\TortoiseHg  SourceDir=..\.. -VersionInfoDescription=Mercurial distributed SCM -VersionInfoCopyright=Copyright 2005-2009 Matt Mackall and others -VersionInfoCompany=Matt Mackall and others +VersionInfoDescription=TortoiseHg Dialogs for Mercurial SCM +VersionInfoCopyright=Copyright 2005-2009 Steve Borho and others +VersionInfoCompany=Steve Borho and others  InternalCompressLevel=max  SolidCompression=true  SetupIconFile=icons\thg_logo.ico @@ -34,10 +34,7 @@
 WizardSmallImageFile=..\misc\install-wizard-small.bmp  AllowNoIcons=true  DefaultGroupName=TortoiseHg -PrivilegesRequired=poweruser -AlwaysRestart=no  SetupLogging=yes -ArchitecturesInstallIn64BitMode=x64    [Types]  Name: full; Description: Full installation @@ -47,16 +44,11 @@
 Name: main; Description: Main Files (includes 'hg' and 'hgtk' commands); Types: full custom; Flags: fixed  Name: help; Description: Help Files; Types: full  Name: hgbook; Description: The book 'Mercurial: The Definitive Guide' (PDF); Types: full -Name: shell; Description: Shell integration (overlay icons, context menu) [admin required]; Types: full; Flags: restart; Check: ShellInstallPossible    [Files] -Source: ..\build-hg\contrib\mercurial.el; DestDir: {app}/contrib -Source: ..\build-hg\contrib\vim\*.*; DestDir: {app}/contrib/vim -Source: ..\build-hg\contrib\zsh_completion; DestDir: {app}/contrib -Source: ..\build-hg\contrib\hgk; DestDir: {app}/contrib -Source: ..\build-hg\contrib\win32\ReadMe.html; DestDir: {app}; Flags: isreadme -Source: ..\build-hg\templates\*.*; DestDir: {app}\templates; Flags: recursesubdirs createallsubdirs -Source: ..\build-hg\locale\*.*; DestDir: {app}\locale; Flags: recursesubdirs createallsubdirs +Source: ..\build-hg\mercurial\templates\*.*; DestDir: {app}\templates; Flags: recursesubdirs createallsubdirs +Source: ..\build-hg\mercurial\help\*.txt; DestDir: {app}\help; Components: help +Source: ..\build-hg\mercurial\locale\*.*; DestDir: {app}\locale; Flags: recursesubdirs createallsubdirs  Source: ..\build-hg\i18n\*.*; DestDir: {app}\i18n  Source: ..\build-hg\doc\*.html; DestDir: {app}\docs; Flags: ignoreversion; Components: help  Source: ..\build-hg\doc\style.css; DestDir: {app}\docs; Flags: ignoreversion; Components: help @@ -66,10 +58,6 @@
 Source: ReleaseNotes.txt; DestDir: {app}; DestName: ReleaseNotes.txt  Source: ..\contrib\*.exe; DestDir: {app}  Source: ..\contrib\*.dll; DestDir: {app} -Source: ..\contrib\TortoiseOverlays\*.*; DestDir: {app}/TortoiseOverlays -Source: contrib\refreshicons.cmd; DestDir: {app}/contrib -Source: dist\*.exe; Excludes: thgtaskbar.exe; DestDir: {app}; Flags: ignoreversion -Source: dist\thgtaskbar.exe; DestDir: {app}; Flags: ignoreversion; Components: shell  Source: dist\*.dll; DestDir: {app}; Flags: ignoreversion  Source: dist\library.zip; DestDir: {app}  Source: doc\build\pdf\*.pdf; DestDir: {app}/docs; Flags: ignoreversion; Components: help @@ -78,20 +66,15 @@
 Source: dist\gtk\*; DestDir: {app}\gtk; Flags: ignoreversion recursesubdirs createallsubdirs  Source: locale\*.*; DestDir: {app}\locale; Flags: recursesubdirs createallsubdirs  Source: i18n\*.*; DestDir: {app}\i18n; Flags: recursesubdirs createallsubdirs -Source: win32\*.reg; DestDir: {app}\cmenu_i18n  Source: COPYING.txt; DestDir: {app}; DestName: Copying.txt  Source: icons\thg_logo.ico; DestDir: {app}  Source: ..\misc\hgbook.pdf; DestDir: {app}/docs; Flags: ignoreversion; Components: hgbook -Source: ..\misc\ThgShellx86.dll; DestDir: {app}; DestName: ThgShell.dll; Check: not Is64BitInstallMode; Flags: ignoreversion restartreplace uninsrestartdelete; Components: shell -Source: ..\misc\ThgShellx86.dll; DestDir: {app}; DestName: ThgShellx86.dll; Check: Is64BitInstallMode; Flags: ignoreversion restartreplace uninsrestartdelete; Components: shell -Source: ..\misc\ThgShellx64.dll; DestDir: {app}; DestName: ThgShell.dll; Check: Is64BitInstallMode; Flags: ignoreversion restartreplace uninsrestartdelete; Components: shell    [INI]  Filename: {app}\Mercurial.url; Section: InternetShortcut; Key: URL; String: http://mercurial.selenic.com/  Filename: {app}\TortoiseHg.url; Section: InternetShortcut; Key: URL; String: http://tortoisehg.org/    [Icons] -Name: {group}\Start Taskbar App; Filename: {app}\thgtaskbar.exe; Components: shell  Name: {group}\TortoiseHg Book (chm); Filename: {app}\docs\TortoiseHg.chm; Components: help  Name: {group}\TortoiseHg Book (pdf); Filename: {app}\docs\TortoiseHg.pdf; Components: help  Name: {group}\TortoiseHg Web Site; Filename: {app}\TortoiseHg.url @@ -103,8 +86,6 @@
   [Run]  Filename: {app}\add_path.exe; Parameters: {app}; StatusMsg: Adding the installation path to the search path... -Filename: msiexec.exe; Parameters: "/i ""{app}\TortoiseOverlays\TortoiseOverlays-1.0.6.16523-win32.msi"" /qn /norestart ALLUSERS=1"; Components: shell; StatusMsg: Installing TortoiseOverlays.dll ... -Filename: msiexec.exe; Parameters: "/i ""{app}\TortoiseOverlays\TortoiseOverlays-1.0.6.16523-x64.msi"" /qn /norestart ALLUSERS=1"; Check: Is64BitInstallMode; Components: shell; StatusMsg: Installing TortoiseOverlays.dll ...    [UninstallRun]  Filename: {app}\add_path.exe; Parameters: /del {app} @@ -118,8 +99,9 @@
 Root: HKLM; Subkey: Software\Mercurial; Flags: uninsdeletekey; ValueData: {app}\Mercurial.ini    [Code] -const - wm_Close = $0010; + +var UserInfoPage: TInputQueryWizardPage; +var GetUserName: Boolean;    procedure FileExpandString(fn: String);  var @@ -134,38 +116,6 @@
  SaveStringsToFile(InFile, InFileLines, False);  end;   -var IsUpgrade: Boolean; - -function InitializeSetup(): Boolean; -var - ThgSwReg: String; - msg: String; - CRLF: String; -begin - CRLF := Chr(10) + Chr(13); - Result := True; - - {abort installation if TortoiseHg 0.7 or earlier is installed} - if RegQueryStringValue(HKLM, 'Software\TortoiseHg', '', ThgSwReg) then - begin - IsUpgrade := True; - {hgproc was removed after 0.7, so it's a good guess} - if (FileExists(ThgSwReg + '\hgproc.exe')) then - begin - msg := 'TortoiseHg Setup Error:' + CRLF + CRLF + - 'The version of TortoiseHg installed is too old to upgrade in place.' + CRLF + - 'You must uninstall it before installing this version.' + CRLF + CRLF + - 'Please uninstall the existing versions of TortoiseHg and TortoiseOverlays,' + CRLF + - 'then run the installer again to continue.'; - MsgBox(msg, mbError, MB_OK); - Result := False; {quit and abort installation} - end; - end; -end; - -var UserInfoPage: TInputQueryWizardPage; -var GetUserName: Boolean; -  procedure InitializeWizard();  begin   if (not(FileExists(ExpandConstant('{%USERPROFILE}\Mercurial.ini')))) then @@ -206,60 +156,3 @@
  SaveStringsToFile(InFile, InFileLines, False);   end;  end; - -function ShouldSkipPage(PageID: Integer): Boolean; -begin - { Skip wpSelectDir page if upgrading; show all others } - case PageID of - wpSelectDir: - Result := IsUpgrade; - else - Result := False; - end; -end; - -function TerminateThgTaskbar(): Boolean; -var - TaskbarWindow: HWND; - TaskbarMutex: String; - tries: Integer; -begin - { Terminate thgtaskbar.exe if it is running. Returns True, if successful } - TaskbarMutex := 'thgtaskbar,Global\thgtaskbar'; - tries := 0; - while (tries < 4) and CheckForMutexes(TaskbarMutex) do begin - TaskbarWindow := FindWindowByWindowName('TortoiseHg RPC server'); - if TaskbarWindow <> 0 then - SendMessage(TaskbarWindow, wm_Close, 0, 0); - Sleep(3000 { ms }); - tries := tries + 1; - end; - Result := not CheckForMutexes(TaskbarMutex); -end; - -function PrepareToInstall: String; -begin - if TerminateThgTaskbar() then - Result := '' - else - Result := 'The installer failed to shut down thgtaskbar.exe, and will now close.'; -end; - -procedure CurUninstallStepChanged(step: TUninstallStep); -begin - if step = usAppMutexCheck then - TerminateThgTaskbar(); -end; - -function ShellInstallPossible(): Boolean; -begin - if not IsAdminLoggedOn then begin - SuppressibleMsgBox( - 'The shell integration install option (overlay icons, context menu) is unavailable (Administrator required)', - mbInformation, MB_OK, 0 - ); - Result := False; - end else Result := True; -end; - -#include "registry.iss"
 
58
59
60
 
 
 
 
61
62
63
 
147
148
149
 
 
150
151
152
153
154
155
156
157
158
159
160
161
162
163
 
58
59
60
61
62
63
64
65
66
67
 
151
152
153
154
155
156
 
 
 
 
 
 
 
 
 
 
157
158
159
@@ -58,6 +58,10 @@
 winmergeu.args=/e /ub /dl other /dr local $other $local $output  winmergeu.fixeol=True  winmergeu.gui=True +araxis.executable=C:\Program Files\Araxis\Araxis Merge v6.5\AraxisP4WinMrg.exe +araxis.priority=1 +araxis.args=$base $other $local $output +araxis.gui=True    ;  ; For more information about mercurial extensions, start here @@ -147,17 +151,9 @@
 ;cmd.vdiff = C:\Progra~1\TortoiseSVN\bin\TortoiseMerge.exe  ;cmd.vimdiff = gvim.exe  ;opts.vimdiff = -f '+next' '+execute "DirDiff ".argv(0)." ".argv(1)' +;cmd.araxis=C:\Program Files\Araxis\Araxis Merge v6.5\compare.exe +;opts.araxis=/wait   -[qct] -;See http://bitbucket.org/tortoisehg/stable/wiki/FAQ for details -;path="C:\Program Files\qct\qct.exe" - -[hgk] -;See http://bitbucket.org/tortoisehg/stable/wiki/FAQ for details -;path={app}\scripts\hgk.cmd -;vdiff=vdiff - -;  ; The git extended diff format will properly store binary files,  ; file permission changes, and rename information that the normal  ; patch format cannot cover. However it is also not 100% compatible
Change 1 of 2 Show Entire File contrib/​win32/​tortoisehg.iss Stacked
renamed from contrib/win32/mercurial.iss
 
50
51
52
53
54
55
56
57
58
59
 
 
 
60
61
62
 
228
229
230
 
 
 
231
232
233
 
50
51
52
 
 
 
 
 
 
 
53
54
55
56
57
58
 
224
225
226
227
228
229
230
231
232
@@ -50,13 +50,9 @@
 Name: shell; Description: Shell integration (overlay icons, context menu) [admin required]; Types: full; Flags: restart; Check: ShellInstallPossible    [Files] -Source: ..\build-hg\contrib\mercurial.el; DestDir: {app}/contrib -Source: ..\build-hg\contrib\vim\*.*; DestDir: {app}/contrib/vim -Source: ..\build-hg\contrib\zsh_completion; DestDir: {app}/contrib -Source: ..\build-hg\contrib\hgk; DestDir: {app}/contrib -Source: ..\build-hg\contrib\win32\ReadMe.html; DestDir: {app}; Flags: isreadme -Source: ..\build-hg\templates\*.*; DestDir: {app}\templates; Flags: recursesubdirs createallsubdirs -Source: ..\build-hg\locale\*.*; DestDir: {app}\locale; Flags: recursesubdirs createallsubdirs +Source: ..\build-hg\mercurial\templates\*.*; DestDir: {app}\templates; Flags: recursesubdirs createallsubdirs +Source: ..\build-hg\mercurial\help\*.txt; DestDir: {app}\help; Components: help +Source: ..\build-hg\mercurial\locale\*.*; DestDir: {app}\locale; Flags: recursesubdirs createallsubdirs  Source: ..\build-hg\i18n\*.*; DestDir: {app}\i18n  Source: ..\build-hg\doc\*.html; DestDir: {app}\docs; Flags: ignoreversion; Components: help  Source: ..\build-hg\doc\style.css; DestDir: {app}\docs; Flags: ignoreversion; Components: help @@ -228,6 +224,9 @@
  TaskbarMutex := 'thgtaskbar,Global\thgtaskbar';   tries := 0;   while (tries < 4) and CheckForMutexes(TaskbarMutex) do begin + TaskbarWindow := FindWindowByWindowName('TortoiseHg Overlay Icon Server'); + if TaskbarWindow <> 0 then + SendMessage(TaskbarWindow, wm_Close, 0, 0);   TaskbarWindow := FindWindowByWindowName('TortoiseHg RPC server');   if TaskbarWindow <> 0 then   SendMessage(TaskbarWindow, wm_Close, 0, 0);
 
332
333
334
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
335
336
337
 
341
342
343
 
 
344
345
346
 
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
 
375
376
377
378
379
380
381
382
@@ -332,6 +332,40 @@
 patches into a repository, so this must be done on the command line with  the :command:`hg import` command.   +Message Parsing +--------------- + +New in TortoiseHg 0.10, the repository browser will detect and underline +changeset hashes and bug report identifiers inside changeset messages. These +underlined phrases are clickable links. + +Every word-boundary delimited string of 12 or 40 characters from the +range [0-9a-f] is considered a changeset link. Clicking on it in the +repository explorer will jump to the given changeset if possible. + +Issue tracker links are enabled when configured in the tortoisehg +section of the configuration files. There are two keys: issue.regex +and issue.link. The first defines the regex to match when picking up +issue numbers, while the second defines the command to run when an +issue number is recognized. + +You may include groups in issue.regex, and corresponding {n} tokens +in issue.link (where n is a non-negative integer). {0} refers to the +entire string matched by issue.regex, while {1} refers to the first +group and so on. If no {n} tokens are found in issue.link, the entire +matched string is appended instead. + +Examples:: + + BitBucket: + issue.regex = #(\d+)\b + issue.link = http://bitbucket.org/<your project and repo>/issue/{1}/ + + Mercurial: + issue.regex = \bissue\d+\b + issue.link = http://mercurial.selenic.com/bts/ + +  Keyboard navigation  -------------------   @@ -341,6 +375,8 @@
  Display visual diffs for selected changeset or file  :kbd:`Ctrl-R`   Refresh repository contents +:kbd:`Ctrl-G` + Go to a specific revision      Configurables
 
49
50
51
52
 
53
54
 
55
56
57
 
49
50
51
 
52
53
 
54
55
56
57
@@ -49,9 +49,9 @@
 # built documents.  #  # The short X.Y version. -version = '0.9' +version = '0.10'  # The full version, including alpha/beta/rc tags. -release = '0.9.1' +release = '0.10.0'    # The language for content autogenerated by Sphinx. Refer to documentation  # for a list of supported languages.
 
83
84
85
86
87
 
 
88
89
 
90
91
 
92
93
94
 
83
84
85
 
 
86
87
88
 
89
90
 
91
92
93
94
@@ -83,12 +83,12 @@
 `download <http://bitbucket.org/tortoisehg/stable/wiki/download/>`_  page of the wiki.   -Deb packages for Ubuntu can be found at -`that <https://launchpad.net/~tortoisehg-ppa>`_. +Packages for Ubuntu can be found at the TortoiseHg +`PPA <https://launchpad.net/~tortoisehg-ppa>`_ web site.   -For MacOSX, no packages are available but you can run hgtk and all the +For Mac OS X, no packages are available but you can run hgtk and all the  dialogs via the source install method. For details, see -`MacOSX <http://bitbucket.org/tortoisehg/stable/wiki/MacOSX>`_. +`Mac OS X <http://bitbucket.org/tortoisehg/stable/wiki/MacOSX>`_.    Language settings  ^^^^^^^^^^^^^^^^^
Added image
Added image
Added image
Added image
Change 1 of 1 Show Entire File setup.py Stacked
 
191
192
193
194
 
195
196
197
 
191
192
193
 
194
195
196
197
@@ -191,7 +191,7 @@
  version=version,   author='Steve Borho',   author_email='steve@borho.org', - url='http://tortoisehg.bitbucket.org', + url='http://tortoisehg.org',   description=desc,   license='GNU GPL2',   scripts=scripts,
Change 1 of 13 Show Entire File thgtaskbar.py Stacked
 
1
2
 
 
3
4
5
 
28
29
30
31
32
33
34
35
36
37
38
 
39
40
41
42
43
 
93
94
95
96
97
98
99
100
 
 
 
101
102
103
 
115
116
117
118
119
 
120
121
122
 
130
131
132
133
134
135
136
137
138
 
139
140
141
 
143
144
145
146
147
148
149
150
 
151
152
153
 
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
 
208
209
210
211
 
212
213
214
215
216
217
218
 
 
 
219
220
221
222
223
 
 
 
 
 
224
225
226
 
279
280
281
 
282
283
284
285
286
 
 
287
288
289
290
291
 
292
293
294
 
296
297
298
299
300
 
 
301
302
303
 
318
319
320
321
 
322
323
324
 
462
463
464
 
465
466
467
 
471
472
473
 
 
 
 
 
 
 
 
 
 
474
475
476
 
1
 
2
3
4
5
6
 
29
30
31
 
 
 
32
33
34
35
 
36
37
 
38
39
40
 
90
91
92
 
93
94
95
 
96
97
98
99
100
101
 
113
114
115
 
 
116
117
118
119
 
127
128
129
 
 
 
 
 
 
130
131
132
133
 
135
136
137
 
 
 
138
 
139
140
141
142
 
162
163
164
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
166
167
 
178
179
180
 
181
182
 
 
 
 
 
 
183
184
185
186
187
188
 
 
189
190
191
192
193
194
195
196
 
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
 
264
265
266
267
 
269
270
271
 
 
272
273
274
275
276
 
291
292
293
 
294
295
296
297
 
435
436
437
438
439
440
441
 
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
@@ -1,5 +1,6 @@
 # Creates a task-bar icon. Run from Python.exe to see the -# messages printed. +# messages printed. Takes an optional logfile as first command +# line parameter    import gc  import os @@ -28,16 +29,12 @@
 from tortoisehg.util import thread2, paths, shlib    if hasattr(sys, "frozen"): - # Insert PATH to binary installer gtk directory - gtkpath = os.path.join(paths.bin_path, 'gtk') - os.environ['PATH'] = os.pathsep.join([gtkpath, os.environ['PATH']])   # Give stdout/stderr closed attributes to prevent ui.py errors   sys.stdout.closed = True   sys.stderr.closed = True   -APP_TITLE = _('TortoiseHg RPC server') +APP_TITLE = _('TortoiseHg Overlay Icon Server')   -SHOWLOG_CMD = 1023  EXIT_CMD = 1025    def SetIcon(hwnd, name, add=False): @@ -93,11 +90,12 @@
  0, 0, win32con.CW_USEDEFAULT, win32con.CW_USEDEFAULT, \   0, 0, hinst, None)   UpdateWindow(self.hwnd) - self.guithread = None   self._DoCreateIcons()     def _DoCreateIcons(self): - SetIcon(self.hwnd, "hg.ico", add=True) + show, highlight = get_config() + if show: + SetIcon(self.hwnd, "hg.ico", add=True)   # start namepipe server for hg status   self.start_pipe_server()   @@ -115,8 +113,7 @@
  def OnTaskbarNotify(self, hwnd, msg, wparam, lparam):   if lparam==win32con.WM_RBUTTONUP or lparam==win32con.WM_LBUTTONUP:   menu = CreatePopupMenu() - AppendMenu(menu, win32con.MF_STRING, SHOWLOG_CMD, _('Options...')) - AppendMenu(menu, win32con.MF_SEPARATOR, 0, '') + # AppendMenu(menu, win32con.MF_SEPARATOR, 0, '')   AppendMenu(menu, win32con.MF_STRING, EXIT_CMD, _('Exit'))   pos = GetCursorPos()   # See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/menus_0hdi.asp @@ -130,12 +127,7 @@
    def OnCommand(self, hwnd, msg, wparam, lparam):   id = LOWORD(wparam) - if id == SHOWLOG_CMD: - if not self.guithread or not self.guithread.isAlive(): - self.launchgui() - else: - print "TortoiseHG options dialog already running" - elif id == EXIT_CMD: + if id == EXIT_CMD:   self.exit_application()   else:   print "Unknown command -", id @@ -143,11 +135,8 @@
  def exit_application(self):   if self.stop_pipe_server():   DestroyWindow(self.hwnd) - if self.guithread and self.guithread.isAlive(): - import gobject - gobject.idle_add(self.dialog.destroy)   print "Goodbye" - +   def stop_pipe_server(self):   print "Stopping pipe server..."   if not self.pipethread.isAlive(): @@ -173,25 +162,6 @@
  else:   return True   - def launchgui(self): - def launch(): - import gtk - # Import hgtk for signal setup side-effects - from tortoisehg.hgtk import hgtk - from tortoisehg.hgtk import taskbarui - dlg = taskbarui.TaskBarUI(logger.getqueue(), requests) - dlg.show_all() - dlg.connect('destroy', gtk.main_quit) - self.dialog = dlg - gtk.gdk.threads_init() - gtk.gdk.threads_enter() - gtk.main() - gtk.gdk.threads_leave() - logger.reset() - - self.guithread = thread2.Thread(target=launch) - self.guithread.start() -   def start_pipe_server(self):   def servepipe():   self.svc = PipeServer(self.hwnd) @@ -208,19 +178,19 @@
   class Logger():   def __init__(self): - self.q = None + self.file = None   - def getqueue(self): - self.q = Queue.Queue() - return self.q - - def reset(self): - self.q = None + def setfile(self, name): + self.file = open(name, 'wb') + self.msg('Logging to file started')     def msg(self, msg):   ts = '[%s] ' % time.strftime('%c') - if self.q: - self.q.put(ts + msg) + f = self.file + if f: + f.write(ts + msg + '\n') + f.flush() + os.fsync(f.fileno())   print 'L' + ts + msg   else:   print ts + msg @@ -279,16 +249,19 @@
 requests = Queue.Queue(0)    def get_config(): + show_taskbaricon = True   hgighlight_taskbaricon = True   try:   from _winreg import HKEY_CURRENT_USER, OpenKey, QueryValueEx   hkey = OpenKey(HKEY_CURRENT_USER, r'Software\TortoiseHg')   t = ('1', 'True') + try: show_taskbaricon = QueryValueEx(hkey, 'ShowTaskbarIcon')[0] in t + except EnvironmentError: pass   try: hgighlight_taskbaricon = QueryValueEx(hkey, 'HighlightTaskbarIcon')[0] in t   except EnvironmentError: pass   except (ImportError, WindowsError):   pass - return hgighlight_taskbaricon + return (show_taskbaricon, hgighlight_taskbaricon)    def update(args, hwnd):   batch = [] @@ -296,8 +269,8 @@
  print "got update request %s (first in batch)" % r   batch.append(r)   print "wait a bit for additional requests..." - highlight = get_config() - if highlight: + show, highlight = get_config() + if show and highlight:   SetIcon(hwnd, "hgB.ico")   time.sleep(0.2)   deferred_requests = [] @@ -318,7 +291,7 @@
  msg = "processing batch with %i update requests"   print msg % len(batch)   update_batch(batch) - if highlight: + if show and highlight:   SetIcon(hwnd, "hg.ico")    def remove(args): @@ -462,6 +435,7 @@
 RUNMUTEXNAME = 'thgtaskbar-' + GetUserName()    def main(): + args = sys.argv[1:]   sa = win32security.SECURITY_ATTRIBUTES()   sa.SetSecurityDescriptorDacl(1, None, 0) # allow full access   runmutex = win32event.CreateMutex(sa, 1, RUNMUTEXNAME) @@ -471,6 +445,16 @@
  # see http://www.jrsoftware.org/iskb.php?mutexsessions   installmutex1 = win32event.CreateMutex(sa, 1, INSTALLMUTEXNAME)   installmutex2 = win32event.CreateMutex(sa, 1, 'Global\\' + INSTALLMUTEXNAME) + + logfilename = None + for arg in args: + if arg[0] == '-': + pass + else: + logfilename = arg + if logfilename: + logger.setfile(logfilename) +   w=MainWindow()   PumpMessages()  
 
9
10
11
12
13
14
15
 
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
 
43
44
45
 
65
66
67
68
 
69
70
71
 
83
84
85
86
87
 
 
 
 
88
89
90
 
9
10
11
 
12
13
 
14
15
16
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
20
21
22
 
42
43
44
 
45
46
47
48
 
60
61
62
 
 
63
64
65
66
67
68
69
@@ -9,37 +9,14 @@
 import os  import sys  import gtk -import threading    from tortoisehg.util.i18n import _ -from tortoisehg.util import version, paths, hglib +from tortoisehg.util import version, paths, hglib, shlib    from tortoisehg.hgtk import gtklib, hgtk   -def browse_url(url): - def start_browser(): - if os.name == 'nt': - import win32api, win32con - win32api.ShellExecute(0, "open", url, None, "", - win32con.SW_SHOW) - elif sys.platform == 'darwin': - # use Mac OS X internet config module (removed in Python 3.0) - import ic - ic.launchurl(url) - else: - try: - import gconf - client = gconf.client_get_default() - browser = client.get_string( - '/desktop/gnome/url-handlers/http/command') + '&' - os.system(browser % url) - except ImportError: - # If gconf is not found, fall back to old standard - os.system('firefox ' + url) - threading.Thread(target=start_browser).start() -  def url_handler(dialog, link, user_data): - browse_url(link) + shlib.browse_url(link)    gtk.about_dialog_set_url_hook(url_handler, None)   @@ -65,7 +42,7 @@
  self.set_name("TortoiseHg")   self.set_version(_("(version %s)") % version.version())   if hasattr(self, 'set_wrap_license'): - self.set_wrap_license(True) + self.set_wrap_license(False)   self.set_copyright(_("Copyright 2009 Steve Borho and others"))     thg_logo = paths.get_tortoise_icon('thg_logo_92x50.png') @@ -83,8 +60,10 @@
  self.set_license('\n'.join(license))     self.set_comments(_("with %s") % lib_versions + "\n\n" + comment) - self.set_logo(gtk.gdk.pixbuf_new_from_file(thg_logo)) - self.set_icon_from_file(thg_icon) + if thg_logo: + self.set_logo(gtk.gdk.pixbuf_new_from_file(thg_logo)) + if thg_icon: + self.set_icon_from_file(thg_icon)   self.connect('response', self.response)     def response(self, widget, respid):
 
10
11
12
13
 
14
15
16
 
39
40
41
42
 
43
44
45
 
176
177
178
179
 
180
181
182
 
10
11
12
 
13
14
15
16
 
39
40
41
 
42
43
44
45
 
176
177
178
 
179
180
181
182
@@ -10,7 +10,7 @@
 import gobject  import pango   -from mercurial import hg, ui +from mercurial import hg, ui, error    from tortoisehg.util.i18n import _  from tortoisehg.util import hglib, paths @@ -39,7 +39,7 @@
    try:   repo = hg.repository(ui.ui(), path=paths.find_root()) - except hglib.RepoError: + except error.RepoError:   gtklib.idle_add_single_call(self.destroy)   return   self.repo = repo @@ -176,7 +176,7 @@
  else:   try:   self.repo[text] - except (hglib.RepoError, hglib.LookupError): + except (error.RepoError, error.LookupError):   return   if path is None:   path = self.destentry.get_text()
 
10
11
12
13
 
14
15
16
 
43
44
45
46
 
47
48
49
 
10
11
12
 
13
14
15
16
 
43
44
45
 
46
47
48
49
@@ -10,7 +10,7 @@
 import gobject  import pango   -from mercurial import hg, ui +from mercurial import hg, ui, error    from tortoisehg.util.i18n import _  from tortoisehg.util import hglib, paths, i18n, settings @@ -43,7 +43,7 @@
    try:   repo = hg.repository(ui.ui(), path=paths.find_root()) - except hglib.RepoError: + except error.RepoError:   gtklib.idle_add_single_call(self.destroy)   return  
Change 1 of 1 Show Entire File tortoisehg/​hgtk/​bookmark.py Stacked
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
@@ -0,0 +1,281 @@
+# bookmark.py - TortoiseHg dialog to add/remove/rename bookmarks +# +# Copyright 2007 TK Soh <teekaysoh@gmail.com> +# Copyright 2007 Steve Borho <steve@borho.org> +# Copyright 2009 Emmanuel Rosa <goaway1000@gmail.com> +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +import gtk +import traceback + +from mercurial import ui, util +from hgext import bookmarks + +from tortoisehg.util.i18n import _ +from tortoisehg.util import hglib, i18n + +from tortoisehg.hgtk import dialog, gtklib + +TYPE_ADDREMOVE = 1 +TYPE_RENAME = 2 +TYPE_CURRENT = 3 + +RESPONSE_ADD = 1 +RESPONSE_REMOVE = 2 +RESPONSE_RENAME = 3 +RESPONSE_CURRENT = 4 + +class BookmarkDialog(gtk.Dialog): + """ Dialog to add bookmark to Mercurial repo """ + def __init__(self, repo, type, bookmark='', rev=''): + """ Initialize the Dialog """ + gtk.Dialog.__init__(self) + gtklib.set_tortoise_keys(self) + self.set_title(_('Bookmark - %s') % hglib.get_reponame(repo)) + self.set_resizable(False) + self.set_has_separator(False) + + self.repo = repo + + # add buttons + if type == TYPE_ADDREMOVE: + self.add_button(_('Add'), RESPONSE_ADD) + self.add_button(_('Remove'), RESPONSE_REMOVE) + elif type == TYPE_RENAME: + self.add_button(_('Rename'), RESPONSE_RENAME) + elif type == TYPE_CURRENT: + self.add_button(_('Set Current'), RESPONSE_CURRENT) + else: + raise _('unexpected type: %s') % type + self.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE) + + # layout table + table = gtklib.LayoutTable() + self.vbox.pack_start(table, True, True, 2) + + ## bookmark name input + self._bookmarkslist = gtk.ListStore(str) + self._bookmarklistbox = gtk.ComboBoxEntry(self._bookmarkslist, 0) + self._bookmark_input = self._bookmarklistbox.get_child() + self._bookmark_input.set_text(bookmark) + if type == TYPE_RENAME: + label = _('Old name:') + else: + label = _('Bookmark:') + table.add_row(label, self._bookmarklistbox, padding=False) + + ## add entry + entry = gtk.Entry() + if type == TYPE_ADDREMOVE: + self._rev_input = entry + entry.set_width_chars(12) + entry.set_text(rev) + label = _('Revision:') + elif type == TYPE_RENAME: + self._name_input = entry + label = _('New Name:') + table.add_row(label, entry, padding=False) + + # signal handlers + self.connect('response', self.dialog_response) + self._bookmark_input.connect('activate', self.entry_activated, type) + entry.connect('activate', self.entry_activated, type) + + # prepare to show + self._refresh(clear=False) + if type == TYPE_RENAME: + self._name_input.grab_focus() + else: + self._bookmarklistbox.grab_focus() + + def _refresh(self, clear=True): + """ update display on dialog with recent repo data """ + self.repo.invalidate() + self._bookmarkslist.clear() + + # add bookmarks to drop-down list + bookmarks = hglib.get_repo_bookmarks(self.repo) + bookmarks.sort() + for bookmarkname in bookmarks: + if bookmarkname != 'tip': + self._bookmarkslist.append([bookmarkname]) + + # clear bookmark name input + if clear: + self._bookmark_input.set_text('') + + def dialog_response(self, dialog, response_id): + # Add button + if response_id == RESPONSE_ADD: + self._do_add_bookmark() + # Remove button + elif response_id == RESPONSE_REMOVE: + self._do_remove_bookmark() + # Rename button + elif response_id == RESPONSE_RENAME: + self._do_rename_bookmark() + # Set Current button + elif response_id == RESPONSE_CURRENT: + self._do_current_bookmark() + # Close button or closed by the user + elif response_id in (gtk.RESPONSE_CLOSE, gtk.RESPONSE_DELETE_EVENT): + self.destroy() + return # close dialog + else: + raise _('unexpected response id: %s') % response_id + + self.run() # don't close dialog + + def entry_activated(self, entry, type): + if type == TYPE_ADDREMOVE: + self.response(RESPONSE_ADD) + elif type == TYPE_RENAME: + self.response(RESPONSE_RENAME) + elif type == TYPE_CURRENT: + self.response(RESPONSE_CURRENT) + else: + raise _('unexpected type: %s') % type + + def _do_add_bookmark(self): + # gather input data + name = self._bookmark_input.get_text() + rev = self._rev_input.get_text() + + # verify input + if name == '': + dialog.error_dialog(self, _('Bookmark input is empty'), + _('Please enter bookmark name')) + self._bookmark_input.grab_focus() + return False + + # add bookmark to repo + try: + self._add_hg_bookmark(name, rev) + dialog.info_dialog(self, _('Bookmarking completed'), + _('Bookmark "%s" has been added') % name) + self._refresh() + except util.Abort, inst: + dialog.error_dialog(self, _('Error in bookmarking'), str(inst)) + return False + except: + dialog.error_dialog(self, _('Error in bookmarking'), + traceback.format_exc()) + return False + + def _do_remove_bookmark(self): + # gather input data + name = self._bookmark_input.get_text() + + # verify input + if name == '': + dialog.error_dialog(self, _('Bookmark name is empty'), + _('Please select bookmark name to remove')) + self._bookmark_input.grab_focus() + return False + + try: + self._remove_hg_bookmark(name) + dialog.info_dialog(self, _('Bookmarking completed'), + _('Bookmark "%s" has been removed') % name) + self._refresh() + except util.Abort, inst: + dialog.error_dialog(self, _('Error in bookmarking'), str(inst)) + return False + except: + dialog.error_dialog(self, _('Error in bookmarking'), + traceback.format_exc()) + return False + + def _do_rename_bookmark(self): + # gather input data + name = self._bookmark_input.get_text() + new_name = self._name_input.get_text() + + # verify input + if name == '': + dialog.error_dialog(self, _('Bookmark input is empty'), + _('Please enter bookmark name')) + self._bookmark_input.grab_focus() + return False + + if new_name == '': + dialog.error_dialog(self, _('Bookmark new name input is empty'), + _('Please enter new bookmark name')) + self._bookmark_input.grab_focus() + return False + + # rename bookmark + try: + self._rename_hg_bookmark(name, new_name) + dialog.info_dialog(self, _('Bookmarking completed'), + _('Bookmark "%s" has been renamed to "%s"') % + (name, new_name)) + self._refresh() + except util.Abort, inst: + dialog.error_dialog(self, _('Error in bookmarking'), str(inst)) + return False + except: + dialog.error_dialog(self, _('Error in bookmarking'), + traceback.format_exc()) + return False + + def _do_current_bookmark(self): + # gather input data + name = self._bookmark_input.get_text() + + # verify input + if name == '': + dialog.error_dialog(self, _('Bookmark input is empty'), + _('Please enter bookmark name')) + self._bookmark_input.grab_focus() + return False + + # set current bookmark + try: + self._current_hg_bookmark(name) + dialog.info_dialog(self, _('Bookmarking completed'), + _('Bookmark "%s" has been made current') % + name) + self._refresh() + except util.Abort, inst: + dialog.error_dialog(self, _('Error in bookmarking'), str(inst)) + return False + except: + dialog.error_dialog(self, _('Error in bookmarking'), + traceback.format_exc()) + return False + + def _add_hg_bookmark(self, name, revision): + if name in hglib.get_repo_bookmarks(self.repo): + raise util.Abort(_('a bookmark named "%s" already exists') % name) + + bookmarks.bookmark(ui=ui.ui(), + repo=self.repo, + rev=revision, + mark=name) + + def _remove_hg_bookmark(self, name): + if not name in hglib.get_repo_bookmarks(self.repo): + raise util.Abort(_("Bookmark '%s' does not exist") % name) + + bookmarks.bookmark(ui=ui.ui(), + repo=self.repo, + mark=name, + delete=True) + + def _rename_hg_bookmark(self, name, new_name): + if new_name in hglib.get_repo_bookmarks(self.repo): + raise util.Abort(_('a bookmark named "%s" already exists') % + new_name) + bookmarks.bookmark(ui=ui.ui(), + repo=self.repo, + mark=new_name, + rename=name) + + def _current_hg_bookmark(self, name): + if name not in hglib.get_repo_bookmarks(self.repo): + raise util.Abort(_('no bookmark named "%s" exists') % + name) + bookmarks.setcurrent(self.repo, name)
Change 1 of 1 Show Entire File tortoisehg/​hgtk/​browse.py Stacked
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
@@ -0,0 +1,329 @@
+# browse.py - TortoiseHg's repository browser +# +# Copyright 2009 Steve Borho <steve@borho.org> +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +import os +import gtk +import gobject +import pango + +from mercurial import hg, ui, cmdutil + +from tortoisehg.util.i18n import _ +from tortoisehg.util import hglib, paths, shlib, menuthg + +from tortoisehg.hgtk import hgcmd, gtklib, gdialog + +folderxpm = [ + "17 16 7 1", + " c #000000", + ". c #808000", + "X c yellow", + "o c #808080", + "O c #c0c0c0", + "+ c white", + "@ c None", + "@@@@@@@@@@@@@@@@@", + "@@@@@@@@@@@@@@@@@", + "@@+XXXX.@@@@@@@@@", + "@+OOOOOO.@@@@@@@@", + "@+OXOXOXOXOXOXO. ", + "@+XOXOXOXOXOXOX. ", + "@+OXOXOXOXOXOXO. ", + "@+XOXOXOXOXOXOX. ", + "@+OXOXOXOXOXOXO. ", + "@+XOXOXOXOXOXOX. ", + "@+OXOXOXOXOXOXO. ", + "@+XOXOXOXOXOXOX. ", + "@+OOOOOOOOOOOOO. ", + "@ ", + "@@@@@@@@@@@@@@@@@", + "@@@@@@@@@@@@@@@@@" + ] +folderpb = gtk.gdk.pixbuf_new_from_xpm_data(folderxpm) + +filexpm = [ + "12 12 3 1", + " c #000000", + ". c #ffff04", + "X c #b2c0dc", + "X XXX", + "X ...... XXX", + "X ...... X", + "X . ... X", + "X ........ X", + "X . .... X", + "X ........ X", + "X . .. X", + "X ........ X", + "X . .. X", + "X ........ X", + "X X" + ] +filepb = gtk.gdk.pixbuf_new_from_xpm_data(filexpm) + +class dirnode(object): + def __init__(self): + self.subdirs = {} + self.files = [] + self.statuses = set() + def addfile(self, filename, st): + self.files.append((filename, st)) + self.addstatus(st) + def addsubdir(self, dirname): + self.subdirs[dirname] = dirnode() + def addstatus(self, st): + self.statuses.add(st) + +class BrowsePane(gtk.TreeView): + 'Dialog for browsing repo.status() output' + def __init__(self, callback): + gtk.TreeView.__init__(self) + self.callback = callback + self.cachedroot = None + self.menu = menuthg.menuThg() + fm = gtk.ListStore(str, # canonical path + bool, # Checked + str, # basename-UTF8 + bool, # M + bool, # A + bool, # R + bool, # ! + bool, # ? + bool, # I + bool, # C + bool) # isfile + self.set_model(fm) + + self.set_headers_visible(False) + self.set_reorderable(True) + self.connect('popup-menu', self.popupmenu) + self.connect('button-release-event', self.buttonrelease) + self.connect('row-activated', self.rowactivated) + self.get_selection().set_mode(gtk.SELECTION_MULTIPLE) + self.set_reorderable(False) + self.set_enable_search(True) + if hasattr(self, 'set_rubber_banding'): + self.set_rubber_banding(True) + + col = gtk.TreeViewColumn(_('status')) + self.append_column(col) + + iconw, iconh = gtk.icon_size_lookup(gtk.ICON_SIZE_SMALL_TOOLBAR) + def packpixmap(ico, id): + iconpath = paths.get_tortoise_icon(ico) + if iconpath == None: + raise (_("could not open icon file '%s' (check install)") % ico) + pm = gtk.gdk.pixbuf_new_from_file_at_size(iconpath, iconw, iconh) + cell = gtk.CellRendererPixbuf() + cell.set_property('pixbuf', pm) + col.pack_start(cell, expand=False) + col.add_attribute(cell, 'visible', id) + + #packpixmap('filemodify.ico', 3) # this icon does not load for me + packpixmap('menucommit.ico', 3) # M + packpixmap('fileadd.ico', 4) # A + packpixmap('filedelete.ico', 5) # R + packpixmap('detect_rename.ico', 6) # missing + packpixmap('menublame.ico', 7) # unknown + #packpixmap('ignore.ico', 8) # ignored + #packpixmap('hg.ico', 9) # clean + + def cell_seticon(column, cell, model, iter): + isfile = model.get_value(iter, 10) + pixbuf = isfile and filepb or folderpb + cell.set_property('pixbuf', pixbuf) + + col = gtk.TreeViewColumn(_('type')) + cell = gtk.CellRendererPixbuf() + col.pack_start(cell, expand=False) + col.set_cell_data_func(cell, cell_seticon) + self.append_column(col) + + col = gtk.TreeViewColumn(_('path'), gtk.CellRendererText(), text=2) + self.append_column(col) + + def split(self, filename): + 'Split a filename into a list of directories and the basename' + dirs = [] + path, basename = os.path.split(filename) + while path: + path, piece = os.path.split(path) + dirs.append(piece) + dirs.reverse() + return dirs, basename + + def chdir(self, cwd): + 'change to a new directory' + # disable updates while we refill the model + model = self.get_model() + self.set_model(None) + model.clear() + try: + self._chdir(model, cwd) + except Exception, e: + # report to status bar + pass + self.set_model(model) + + def _chdir(self, model, cwd): + def buildrow(name, stset, isfile): + dirs, basename = self.split(name) + row = [ name, False, hglib.toutf(basename), + 'M' in stset, 'A' in stset, 'R' in stset, + '!' in stset, '?' in stset, 'I' in stset, + 'C' in stset, isfile ] + return row + + def adddir(node): + for dname, dirnode in node.subdirs.iteritems(): + model.append(buildrow(dname, dirnode.statuses, False)) + for fname, st in node.files: + model.append(buildrow(fname, st, True)) + + drive, tail = os.path.splitdrive(cwd) + if cwd != '/' or (drive and tail): + model.append(buildrow('..', '', False)) + + root = paths.find_root(cwd) + if root and self.cachedroot != root: + self.cacherepo(root) + + if root: + node = self.cachedmodel + relpath = cwd[len(root)+len(os.sep):] + dirs, basename = self.split(relpath) + for dname in dirs: + node = node.subdirs[dname] + if basename: + node = node.subdirs[basename] + adddir(node) + self.currepo = None + else: + try: + for name in os.listdir(cwd): + isfile = os.path.isfile(os.path.join(cwd, name)) + model.append(buildrow(name, '', isfile)) + except OSError: + # report to status bar + pass + self.currepo = self.cachedrepo + + + def cacherepo(self, root, pats=[], filetypes='CI?'): + status = ([],)*7 + try: + repo = hg.repository(ui.ui(), path=root) + matcher = cmdutil.match(repo, pats) + st = repo.status(match=matcher, + clean='C' in filetypes, + ignored='I' in filetypes, + unknown='?' in filetypes) + except IOError: + pass + filelist = [] + # concatenate status output into a single list, then sort on filename + for l, s in ( (st[0], 'M'), (st[1], 'A'), (st[2], 'R'), (st[3], '!'), + (st[4], '?'), (st[5], 'I'), (st[6], 'C') ): + for m in l: + filelist.append([ m, s ]) + filelist.sort() + + # Build tree data structure + modelroot = dirnode() + for name, filestatus in filelist: + dirs, basename = self.split(name) + curdir = modelroot + for dir in dirs: + if dir not in curdir.subdirs: + curdir.addsubdir(dir) + curdir.addstatus(filestatus) + curdir = curdir.subdirs[dir] + curdir.addfile(name, filestatus) + + self.cachedmodel = modelroot + self.cachedroot = root + self.cachedrepo = repo + + def popupmenu(self, browse): + model, tpaths = browse.get_selection().get_selected_rows() + if not tpaths: + return + files = [model[p][0] for p in tpaths if model[p][10]] + if self.currepo: + repo = self.currepo + menus = self.menu.get_commands(repo, repo.root, files) + else: + menus = self.menu.get_norepo_commands(None, files) + # see nautilus extension for usage info + for menu_info in menus: + print menu_info + + def buttonrelease(self, browse, event): + if event.button != 3: + return False + self.popupmenu(browse) + return True + + def rowactivated(self, browse, path, column): + model, tpaths = browse.get_selection().get_selected_rows() + if not tpaths: + return + if len(tpaths) == 1 and not model[tpaths[0]][10]: + self.callback(model[tpaths[0]][0]) + else: + files = [model[p][0] for p in tpaths if model[p][10]] + print files, 'activated' + +class BrowseDialog(gtk.Dialog): + 'Wrapper application for BrowsePane' + def __init__(self, command, pats): + gtk.Dialog.__init__(self) + gtklib.set_tortoise_icon(self, 'hg.ico') + gtklib.set_tortoise_keys(self) + self.set_has_separator(False) + self.set_default_size(400, 500) + self.connect('response', self.dialog_response) + + entry = gtk.Entry() + self.vbox.pack_start(entry, False, True) + + def newfolder_notify(newfolder): + curpath = entry.get_text() + newpath = os.path.join(curpath, newfolder) + newpath = hglib.toutf(os.path.abspath(newpath)) + root = paths.find_root(newpath) + if root: + self.set_title(root + ' - ' + _('browser')) + else: + self.set_title(_('browser')) + entry.set_text(newpath) + browse.chdir(newpath) + + browse = BrowsePane(newfolder_notify) + scroller = gtk.ScrolledWindow() + scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + scroller.set_shadow_type(gtk.SHADOW_ETCHED_IN) + scroller.add(browse) + self.vbox.pack_start(scroller, True, True) + self.show_all() + + cwd = hglib.toutf(os.getcwd()) + entry.connect('activate', self.entry_activated, browse) + entry.set_text(cwd) + browse.chdir(cwd) + + def entry_activated(self, entry, browse): + browse.chdir(entry.get_text()) + + def dialog_response(self, dialog, response): + return True + +def run(ui, *pats, **opts): + pats = hglib.canonpaths(pats) + if opts.get('canonpats'): + pats = list(pats) + opts['canonpats'] + return BrowseDialog(opts.get('alias'), pats)
 
6
7
8
 
9
10
11
12
13
14
 
15
16
17
 
18
19
20
 
26
27
28
 
 
 
 
 
 
 
 
29
30
31
 
92
93
94
 
95
96
97
98
99
 
261
262
263
264
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
266
267
 
274
275
276
277
 
278
279
280
 
286
287
288
289
 
290
291
292
 
358
359
360
361
 
362
363
 
364
365
366
 
485
486
487
488
 
489
490
491
 
608
609
610
 
611
612
613
 
635
636
637
638
 
 
639
640
641
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
642
643
644
 
646
647
648
649
650
651
652
653
 
654
655
656
 
710
711
712
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
713
714
715
 
730
731
732
733
 
734
735
736
 
6
7
8
9
10
11
12
13
14
 
15
16
17
 
18
19
20
21
 
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 
101
102
103
104
105
 
106
107
108
 
270
271
272
 
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
 
303
304
305
 
306
307
308
309
 
315
316
317
 
318
319
320
321
 
387
388
389
 
390
391
 
392
393
394
395
 
514
515
516
 
517
518
519
520
 
637
638
639
640
641
642
643
 
665
666
667
 
668
669
670
 
 
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
 
709
710
711
 
712
 
713
714
715
716
717
718
 
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
 
842
843
844
 
845
846
847
848
@@ -6,15 +6,16 @@
 # GNU General Public License version 2, incorporated herein by reference.    import os +import re  import gtk  import gobject  import pango  import Queue   -from mercurial import cmdutil, util, patch, mdiff +from mercurial import cmdutil, util, patch, mdiff, error    from tortoisehg.util.i18n import _ -from tortoisehg.util import shlib, hglib +from tortoisehg.util import shlib, hglib, paths    from tortoisehg.hgtk import csinfo, gdialog, gtklib, hgcmd, statusbar   @@ -26,6 +27,14 @@
  self.glog_parent = None   self.bfile = None   + # initialize changeset/issue tracker link regex and dict + match = r'(\b[0-9a-f]{12}(?:[0-9a-f]{28})?\b)' + issue = repo.ui.config('tortoisehg', 'issue.regex') + if issue: + match = r'%s|(%s)' % (match, issue) + self.bodyre = re.compile(match) + self.issuedict = dict() +   def get_title(self):   title = _('%s changeset ') % self.get_reponame()   rev = self.opts['rev'] @@ -92,8 +101,8 @@
  if len(parents) == 2:   # deferred adding of parent check button   if not self.parent_button.parent: + self.parent_box.pack_start(self.parent_button, False, False)   self.parent_box.pack_start(gtk.HSeparator(), False, False) - self.parent_box.pack_start(self.parent_button, False, False)   self.parent_box.show_all()     # show parent box @@ -261,7 +270,27 @@
  buf = self._buffer   buf.set_text('')   eob = buf.get_end_iter() - buf.insert(eob, desc.rstrip('\n\r') + '\n\n') + desc = desc.rstrip('\n\r') + + pos = 0 + self.issuedict.clear() + for m in self.bodyre.finditer(desc): + a, b = m.span() + if a > pos: + buf.insert(eob, desc[pos:a]) + pos = b + groups = m.groups() + link = groups[0] + if link: + buf.insert_with_tags_by_name(eob, link, 'csetlink') + else: + link = groups[1] + if len(groups) > 2: + self.issuedict[link] = groups[1:] + buf.insert_with_tags_by_name(eob, link, 'issuelink') + if pos < len(desc): + buf.insert(eob, desc[pos:]) + buf.insert(eob, '\n\n')     def append_diff(self, wfile):   if not wfile: @@ -274,7 +303,7 @@
    try:   fctx = self.repo[rev].filectx(wfile) - except hglib.LookupError: + except error.LookupError:   fctx = None   if fctx and fctx.size() > hglib.getmaxdiffsize(self.repo.ui):   lines = ['diff', @@ -286,7 +315,7 @@
  try:   for s in patch.diff(self.repo, n1, n2, match=m, opts=opts):   lines.extend(s.splitlines()) - except (hglib.RepoLookupError, hglib.RepoError, hglib.LookupError), e: + except (error.RepoLookupError, error.RepoError, error.LookupError), e:   err = _('Repository Error: %s, refresh suggested') % str(e)   lines = ['diff', '', err]   tags, lines = self.prepare_diff(lines, offset, wfile) @@ -358,9 +387,9 @@
  offset += len(txt.decode('utf-8'))   for l1 in difflines[1:]:   l = hglib.toutf(l1) - if l.startswith('+++'): + if l.startswith('--- '):   continue - if l.startswith('---'): + if l.startswith('+++ '):   continue   if l.startswith('@@'):   tag = 'blue' @@ -485,7 +514,7 @@
  try:   tctx = self.repo[ts]   return revline_data(tctx) - except (hglib.LookupError, hglib.RepoLookupError, hglib.RepoError): + except (error.LookupError, error.RepoLookupError, error.RepoError):   return ts   elif item == 'patch':   if hasattr(ctx, '_patchname'): @@ -608,6 +637,7 @@
    ## file list   filelist_tree = gtk.TreeView() + filelist_tree.set_headers_visible(False)   filesel = filelist_tree.get_selection()   filesel.connect('changed', self.filelist_rowchanged)   self._filesel = filesel @@ -635,10 +665,43 @@
  gobject.TYPE_STRING, # filename   )   filelist_tree.set_model(self._filelist) - column = gtk.TreeViewColumn(_('Stat'), gtk.CellRendererText(), text=0) + + column = gtk.TreeViewColumn()   filelist_tree.append_column(column) - column = gtk.TreeViewColumn(_('Files'), gtk.CellRendererText(), text=1) - filelist_tree.append_column(column) + + iconcell = gtk.CellRendererPixbuf() + filecell = gtk.CellRendererText() + + column.pack_start(iconcell, expand=False) + column.pack_start(filecell, expand=False) + column.add_attribute(filecell, 'text', 1) + + iconw, iconh = gtk.icon_size_lookup(gtk.ICON_SIZE_SMALL_TOOLBAR) + + def get_pixbuf(iconfilename): + iconpath = paths.get_tortoise_icon(iconfilename) + if iconpath == None: + raise (_("could not open icon file '%s' (check install)") + % iconfilename) + return gtk.gdk.pixbuf_new_from_file_at_size( + iconpath, iconw, iconh) + + addedpixbuf = get_pixbuf('fileadd.ico') + removedpixbuf = get_pixbuf('filedelete.ico') + modifiedpixbuf = get_pixbuf('filemodify.ico') + + def cell_seticon(column, cell, model, iter): + state = model.get_value(iter, 0) + pixbuf = None + if state == 'A': + pixbuf = addedpixbuf + elif state == 'R': + pixbuf = removedpixbuf + elif state == 'M': + pixbuf = modifiedpixbuf + cell.set_property('pixbuf', pixbuf) + + column.set_cell_data_func(iconcell, cell_seticon)     list_frame = gtk.Frame()   list_frame.set_shadow_type(gtk.SHADOW_ETCHED_IN) @@ -646,11 +709,10 @@
  scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)   scroller.add(filelist_tree)   flbox = gtk.VBox() - flbox.pack_start(scroller)   list_frame.add(flbox) -   self.parent_box = gtk.VBox()   flbox.pack_start(self.parent_box, False, False) + flbox.pack_start(scroller)     btn = gtk.CheckButton(_('Diff to second Parent'))   btn.connect('toggled', self.parent_toggled) @@ -710,6 +772,56 @@
  weight=pango.WEIGHT_BOLD))   tag_table.add(make_texttag('yellowbg', background='yellow'))   + issuelink_tag = make_texttag('issuelink', foreground='blue', + underline=pango.UNDERLINE_SINGLE) + issuelink_tag.connect('event', self.issuelink_event) + tag_table.add(issuelink_tag) + csetlink_tag = make_texttag('csetlink', foreground='blue', + underline=pango.UNDERLINE_SINGLE) + csetlink_tag.connect('event', self.csetlink_event) + tag_table.add(csetlink_tag) + + def issuelink_event(self, tag, widget, event, liter): + if event.type != gtk.gdk.BUTTON_RELEASE: + return + text = self.get_link_text(tag, widget, liter) + if not text: + return + link = self.repo.ui.config('tortoisehg', 'issue.link') + if link: + groups = self.issuedict.get(text, [text]) + link, num = re.subn(r'\{(\d+)\}', lambda m: + groups[int(m.group(1))], link) + if not num: + link += text + shlib.browse_url(link) + + def csetlink_event(self, tag, widget, event, liter): + if event.type != gtk.gdk.BUTTON_RELEASE: + return + text = self.get_link_text(tag, widget, liter) + if not text: + return + try: + rev = self.repo[text].rev() + if self.graphview: + self.graphview.set_revision_id(rev, load=True) + else: + self.load_details(rev) + except error.RepoError: + pass + + def get_link_text(self, tag, widget, liter): + text_buffer = widget.get_buffer() + beg = liter.copy() + while not beg.begins_tag(tag): + beg.backward_char() + end = liter.copy() + while not end.ends_tag(tag): + end.forward_char() + text = text_buffer.get_text(beg, end) + return text +   def file_button_release(self, widget, event):   if event.button == 3 and not (event.state & (gtk.gdk.SHIFT_MASK |   gtk.gdk.CONTROL_MASK)): @@ -730,7 +842,7 @@
  try:   fctx = ctx.filectx(self.curfile)   has_filelog = fctx.filelog().linkrev(fctx.filerev()) == ctx.rev() - except hglib.LookupError: + except error.LookupError:   has_filelog = False   self.ann_menu.set_sensitive(has_filelog)   self.save_menu.set_sensitive(has_filelog)
 
51
52
53
54
 
55
56
57
 
74
75
76
77
 
 
 
 
 
 
 
 
78
79
80
 
85
86
87
88
 
89
90
91
 
206
207
208
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
210
211
 
266
267
268
269
 
270
271
272
 
51
52
53
 
54
55
56
57
 
74
75
76
 
77
78
79
80
81
82
83
84
85
86
87
 
92
93
94
 
95
96
97
98
 
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
 
288
289
290
 
291
292
293
294
@@ -51,7 +51,7 @@
  elif len(repos):   srcpath = repos[0]   - def createcombo(path, label, title): + def createcombo(path, label, title, bundle=False):   # comboentry   model = gtk.ListStore(str)   combo = gtk.ComboBoxEntry(model, 0) @@ -74,7 +74,14 @@
  browse = gtk.Button(_('Browse...'))   browse.connect('clicked', self.browse_clicked, title, entry)   - table.add_row(label, combo, 0, browse) + if bundle: + # bundle button + bundlebtn = gtk.Button(_('Bundle...')) + bundlebtn.connect('clicked', self.bundle_clicked, + _('Select a Mercurial Bundle'), entry) + table.add_row(label, combo, 0, browse, bundlebtn) + else: + table.add_row(label, combo, 0, browse)     return model, combo   @@ -85,7 +92,7 @@
  ## comboentry for source paths   self.srclist, srccombo = createcombo(srcpath,   _('Source path:'), - _('Select Source Folder')) + _('Select Source Folder'), True)   self.srcentry = srccombo.get_child()     ## add pre-defined src paths to pull-down list @@ -206,6 +213,21 @@
  if res:   entry.set_text(res)   + def bundle_clicked(self, button, title, entry): + path = entry.get_text() + if os.path.isdir(path): + initial = path + else: + initial = os.path.dirname(path) + + res = gtklib.NativeSaveFileDialogWrapper( + initial=initial, + title=title, + filter= ((_('Mercurial bundles'), '*.hg'),), + open=True).run() + if res: + entry.set_text(res) +   def checkbutton_toggled(self, checkbutton, entry):   state = checkbutton.get_active()   entry.set_sensitive(state) @@ -266,7 +288,7 @@
    def clone(self):   # gather input data - src = self.srcentry.get_text() + src = self.srcentry.get_text().strip()   dest = self.destentry.get_text() or os.path.basename(src)   remotecmd = self.remotecmdentry.get_text()   rev = self.reventry.get_text()
 
26
27
28
29
 
30
31
32
 
40
41
42
43
 
44
45
46
47
 
 
48
49
50
 
58
59
60
61
 
 
62
 
 
 
 
 
 
 
63
64
65
 
71
72
73
74
 
75
76
77
 
388
389
390
391
392
 
 
393
394
395
396
 
397
398
399
400
401
 
 
402
403
404
 
475
476
477
478
479
480
481
482
 
 
483
484
485
 
731
732
733
734
 
735
736
737
 
858
859
860
861
862
863
864
865
866
867
868
869
870
 
26
27
28
 
29
30
31
32
 
40
41
42
 
43
44
45
 
 
46
47
48
49
50
 
58
59
60
 
61
62
63
64
65
66
67
68
69
70
71
72
73
 
79
80
81
 
82
83
84
85
 
396
397
398
 
 
399
400
401
402
403
 
404
405
406
407
 
 
408
409
410
411
412
 
483
484
485
 
 
 
 
 
486
487
488
489
490
 
736
737
738
 
739
740
741
742
 
863
864
865
 
 
 
 
 
 
 
866
867
868
@@ -26,7 +26,7 @@
 from tortoisehg.hgtk import csinfo, gtklib, thgconfig, gdialog, hgcmd    class BranchOperationDialog(gtk.Dialog): - def __init__(self, branch, close, mergebranches): + def __init__(self, branch, close, repo):   gtk.Dialog.__init__(self, parent=None, flags=gtk.DIALOG_MODAL,   buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK,   gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL), @@ -40,11 +40,11 @@
  self.newbranch = None   self.closebranch = False   - if mergebranches: + if len(repo.parents()) == 2:   lbl = gtk.Label(_('Select branch of merge commit'))   branchcombo = gtk.combo_box_new_text() - for name in mergebranches: - branchcombo.append_text(name) + for p in repo.parents(): + branchcombo.append_text(p.branch())   branchcombo.set_active(0)   self.vbox.pack_start(lbl, True, True, 2)   self.vbox.pack_start(branchcombo, True, True, 2) @@ -58,8 +58,16 @@
  _('Open a new named branch'))   self.newbranchradio.set_active(True)   self.newbranchradio.connect('toggled', self.nbtoggle) - self.branchentry = gtk.Entry() + branchcombo = gtk.combo_box_entry_new_text() + self.branchentry = branchcombo.child   self.branchentry.connect('activate', self.activated) + + dblist = repo.ui.config('tortoisehg', 'deadbranch', '') + deadbranches = [ x.strip() for x in dblist.split(',') ] + for name in repo.branchtags().keys(): + if name not in deadbranches: + branchcombo.append_text(name) +   self.closebranchradio = gtk.RadioButton(nochanges,   _('Close current named branch'))   @@ -71,7 +79,7 @@
  lbl.set_markup(gtklib.markup(_('Changes take effect on next commit'),   weight='bold'))   table.add_row(lbl, padding=False, ypad=6) - table.add_row(self.newbranchradio, self.branchentry) + table.add_row(self.newbranchradio, branchcombo)   table.add_row(self.closebranchradio)   table.add_row(nochanges)   @@ -388,17 +396,17 @@
  # parent changeset info   parents_vbox = gtk.VBox(spacing=1)   self.parents_frame = parents_vbox - style = csinfo.labelstyle(contents=(_('Parent: %(rev)s'), - ' %(athead)s', ' %(branch)s', ' %(tags)s', + style = csinfo.labelstyle(contents=('%(athead)s ', + _('Parent: %(rev)s'), ' %(branch)s', ' %(tags)s',   ' %(summary)s'), selectable=True)   def data_func(widget, item, ctx):   if item == 'athead': - return widget.get_data('ishead') or self.mqmode + return widget.get_data('ishead') or bool(self.mqmode)   raise csinfo.UnknownItem(item)   def markup_func(widget, item, value):   if item == 'athead' and value is False: - text = '[%s]' % _('not at head revision') - return gtklib.markup(text, weight='bold') + text = '[%s]' % _('Not at head') + return gtklib.markup(text, weight='bold', color='#880000')   raise csinfo.UnknownItem(item)   custom = csinfo.custom(data=data_func, markup=markup_func)   factory = csinfo.factory(self.repo, custom, style) @@ -475,11 +483,8 @@
  liststore.append([sumline, msg])     def branch_clicked(self, button): - if self.is_merge(): - mb = [p.branch() for p in self.repo.parents()] - else: - mb = None - dialog = BranchOperationDialog(self.nextbranch, self.closebranch, mb) + dialog = BranchOperationDialog(self.nextbranch, + self.closebranch, self.repo)   dialog.run()   self.nextbranch = None   self.closebranch = False @@ -731,7 +736,7 @@
  self.commit_selected(commit_list)   elif self.qheader is not None:   self.commit_selected([]) - elif self.closebranch: + elif self.closebranch or self.nextbranch:   self.commit_selected([])   else:   gdialog.Prompt(_('Nothing Commited'), @@ -858,13 +863,6 @@
  _('Errors during rollback!'), self).run()     - def changelog_clicked(self, toolbutton, data=None): - from tortoisehg.hgtk import history - dlg = history.run(self.ui) - dlg.display() - return True - -   def should_addremove(self, files):   if self.test_opt('addremove'):   return True
 
12
13
14
15
16
 
 
17
18
19
 
113
114
115
116
 
117
118
119
 
165
166
167
168
 
169
170
171
172
173
174
 
175
176
177
 
191
192
193
 
194
195
196
 
212
213
214
215
 
 
 
216
217
218
 
254
255
256
257
 
258
259
260
 
269
270
271
272
 
273
274
275
 
321
322
323
324
 
 
 
325
326
327
 
12
13
14
 
 
15
16
17
18
19
 
113
114
115
 
116
117
118
119
 
165
166
167
 
168
169
170
171
172
173
 
174
175
176
177
 
191
192
193
194
195
196
197
 
213
214
215
 
216
217
218
219
220
221
 
257
258
259
 
260
261
262
263
 
272
273
274
 
275
276
277
278
 
324
325
326
 
327
328
329
330
331
332
@@ -12,8 +12,8 @@
 import gtk  import binascii   -from mercurial import patch, util -from mercurial.node import short, hex +from mercurial import patch, util, error +from mercurial.node import hex    from tortoisehg.util.i18n import _  from tortoisehg.util import hglib, paths @@ -113,7 +113,7 @@
  return None   try:   ctx = repo[rev] - except (hglib.LookupError, hglib.RepoLookupError, hglib.RepoError): + except (error.LookupError, error.RepoLookupError, error.RepoError):   ctx = None   return ctx   @@ -165,13 +165,13 @@
  continue   try:   self._parents.append(repo[p]) - except (hglib.LookupError, hglib.RepoLookupError, hglib.RepoError): + except (error.LookupError, error.RepoLookupError, error.RepoError):   self._parents.append(p)     def __str__(self):   node = self.node()   if node: - return short(node) + return node[:12]   return ''     def __int__(self): @@ -191,6 +191,7 @@
  def tags(self): return ()   def parents(self): return self._parents   def children(self): return () + def extra(self): return {}    class SummaryInfo(object):   @@ -212,7 +213,9 @@
  if item == 'rev':   revnum = self.get_data('revnum', *args)   revid = self.get_data('revid', *args) - return (revnum, revid) + if revid: + return (revnum, revid) + return None   elif item == 'revnum':   return ctx.rev()   elif item == 'revid': @@ -254,7 +257,7 @@
  if dblist and value in [hglib.toutf(b.strip()) \   for b in dblist.split(',')]:   return None - return value + return None   elif item == 'rawtags':   value = [hglib.toutf(tag) for tag in ctx.tags()]   if len(value) == 0: @@ -269,7 +272,7 @@
  value = [tag for tag in value if tag not in htags]   if len(value) == 0:   return None - return value + return None   elif item == 'transplant':   extra = ctx.extra()   try: @@ -321,7 +324,9 @@
  if item == 'rev':   revnum, revid = value   revid = gtklib.markup(revid, **mono) - return '%s (%s)' % (revnum, revid) + if revnum is not None and revid is not None: + return '%s (%s)' % (revnum, revid) + return '%s' % revid   elif item in ('revid', 'transplant'):   return gtklib.markup(value, **mono)   elif item == 'revnum':
Show Entire File tortoisehg/​hgtk/​cslist.py Stacked
This file's diff was not loaded because this changeset is very large. Load changes
 
13
14
15
16
 
17
18
19
 
191
192
193
194
 
195
196
197
 
208
209
210
211
 
212
213
214
 
453
454
455
456
 
457
458
459
 
580
581
582
583
 
584
585
586
 
752
753
754
755
 
756
757
758
 
13
14
15
 
16
17
18
19
 
191
192
193
 
194
195
196
197
 
208
209
210
 
211
212
213
214
 
453
454
455
 
456
457
458
459
 
580
581
582
 
583
584
585
586
 
752
753
754
 
755
756
757
758
@@ -13,7 +13,7 @@
 import threading  import re   -from mercurial import util +from mercurial import util, error    from tortoisehg.util.i18n import _  from tortoisehg.util import hglib, thread2 @@ -191,7 +191,7 @@
  parent_ctx = self.repo[parent_revid]   try:   parent_ctx.filectx(filepath) - except LookupError: + except error.LookupError:   # file was renamed/moved, try to find previous file path   end_iter = iter   path = graphview.get_path_at_revid(int(anotrev)) @@ -208,7 +208,7 @@
  if renamed:   filepath = renamed[0]   break - except LookupError: + except error.LookupError:   # break iteration, but don't use 'break' statement   # so that execute 'else' block for showing prompt.   iter = end_iter @@ -453,7 +453,7 @@
  def threadfunc(q, *args):   try:   hglib.hgcmd_toq(q, *args) - except (util.Abort, hglib.LookupError), e: + except (util.Abort, error.LookupError), e:   self.stbar.set_status_text(_('Abort: %s') % str(e))     thread = thread2.Thread(target=threadfunc, args=args) @@ -580,7 +580,7 @@
  ctx = self.repo.parents()[0]   try:   fctx = ctx.filectx(path) - except LookupError: + except error.LookupError:   gdialog.Prompt(_('File is unrevisioned'),   _('Unable to annotate ') + path, self).run()   return @@ -752,7 +752,7 @@
  def threadfunc(q, *args):   try:   hglib.hgcmd_toq(q, *args) - except (util.Abort, hglib.LookupError), e: + except (util.Abort, error.LookupError), e:   self.stbar.set_status_text(_('Abort: %s') % str(e))     (frame, treeview, origpath, graphview) = objs
 
18
19
20
21
 
22
23
24
 
387
388
389
390
391
 
392
393
394
 
18
19
20
 
21
22
23
24
 
387
388
389
 
 
390
391
392
393
@@ -18,7 +18,7 @@
 from mercurial import cmdutil, util, ui, hg, commands    from tortoisehg.util.i18n import _ -from tortoisehg.util import settings, hglib, paths +from tortoisehg.util import settings, hglib, paths, shlib    from tortoisehg.hgtk import gtklib   @@ -387,8 +387,7 @@
  return   if not url.startswith('http'):   url = 'http://tortoisehg.org/manual/0.9/' + url - from tortoisehg.hgtk import about - about.browse_url(url) + shlib.browse_url(url)     def launch(self, item, app):   import sys
 
9
10
11
12
 
 
13
14
15
 
54
55
56
57
 
58
59
60
61
 
62
63
64
 
9
10
11
 
12
13
14
15
16
 
55
56
57
 
58
59
60
61
 
62
63
64
65
@@ -9,7 +9,8 @@
 import os  import gtk  import gobject -import mercurial + +from mercurial import error    from tortoisehg.util.i18n import _  from tortoisehg.hgtk import gtklib, gdialog @@ -54,11 +55,11 @@
  self.gotofunc(revision)   self.revEntry.set_text('')   self.hide() - except mercurial.error.LookupError, e: + except error.LookupError, e:   gdialog.Prompt(_('Ambiguous Revision'), str(e), self).run()   self.revEntry.grab_focus()   return - except mercurial.error.RepoError, e: + except error.RepoError, e:   gdialog.Prompt(_('Invalid Revision'), str(e), self).run()   self.revEntry.grab_focus()   return
 
68
69
70
 
 
71
72
73
 
148
149
150
151
 
152
153
154
 
157
158
159
 
160
161
162
 
183
184
185
 
 
 
186
187
 
188
189
190
 
192
193
194
195
 
196
197
198
199
 
 
200
201
202
 
211
212
213
 
 
 
 
 
 
 
 
214
215
216
 
225
226
227
 
 
228
229
230
 
233
234
235
236
 
 
 
 
237
238
239
 
318
319
320
321
 
322
323
324
 
68
69
70
71
72
73
74
75
 
150
151
152
 
153
154
155
156
 
159
160
161
162
163
164
165
 
186
187
188
189
190
191
192
 
193
194
195
196
 
198
199
200
 
201
202
 
 
 
203
204
205
206
207
 
216
217
218
219
220
221
222
223
224
225
226
227
228
229
 
238
239
240
241
242
243
244
245
 
248
249
250
 
251
252
253
254
255
256
257
 
336
337
338
 
339
340
341
342
@@ -68,6 +68,8 @@
  window.connect('thg-close', thgclose)   window.connect('thg-exit', thgexit)   + return accelgroup, mod +  def thgexit(window):   if thgclose(window):   gobject.idle_add(hgtk.thgexit, window) @@ -148,7 +150,7 @@
  that isn't available"""   def __init__(self, initial = None, title = _('Save File'),   filter = ((_('All files'), '*.*'),), filterindex = 1, - filename = '', open=False): + filename = '', open=False, multi=False):   if initial is None:   initial = os.path.expanduser("~")   self.initial = initial @@ -157,6 +159,7 @@
  self.filter = filter   self.filterindex = filterindex   self.open = open + self.multi = multi     def run(self):   """run the file dialog, either return a file name, or False if @@ -183,8 +186,11 @@
  f = ''   for name, mask in self.filter:   f += '\0'.join([name, mask,'']) + flags = win32con.OFN_EXPLORER + if self.multi: + flags |= win32con.OFN_ALLOWMULTISELECT   opts = dict(InitialDir=self.initial, - Flags=win32con.OFN_EXPLORER, + Flags=flags,   File=self.filename,   DefExt=None,   Title=hglib.fromutf(self.title), @@ -192,11 +198,10 @@
  CustomFilter=None,   FilterIndex=self.filterindex)   if self.open: - fname, _, _ = win32gui.GetOpenFileNameW(**opts) + ret = win32gui.GetOpenFileNameW(**opts)   else: - fname, _, _ = win32gui.GetSaveFileNameW(**opts) - if fname: - fname = os.path.abspath(fname) + ret = win32gui.GetSaveFileNameW(**opts) + fname = ret[0]   except pywintypes.error:   pass   os.chdir(cwd) @@ -211,6 +216,14 @@
  fname = False   if q.qsize():   fname = q.get(0) + if fname and self.multi and fname.find('\x00') != -1: + splitted = fname.split('\x00') + dir, fnames = splitted[0], splitted[1:] + fname = [] + for fn in fnames: + path = os.path.abspath(os.path.join(dir, fn)) + if os.path.exists(path): + fname.append(hglib.toutf(path))   return fname     def runCompatible(self): @@ -225,6 +238,8 @@
  dlg = gtk.FileChooserDialog(self.title, None, action, buttons)   dlg.set_default_response(gtk.RESPONSE_OK)   dlg.set_current_folder(self.initial) + if self.multi: + dlg.set_select_multiple(True)   if not self.open:   dlg.set_current_name(self.filename)   for name, pattern in self.filter: @@ -233,7 +248,10 @@
  fi.add_pattern(pattern)   dlg.add_filter(fi)   if dlg.run() == gtk.RESPONSE_OK: - result = dlg.get_filename(); + if self.multi: + result = dlg.get_filenames() + else: + result = dlg.get_filename()   else:   result = False   dlg.destroy() @@ -318,7 +336,7 @@
  return fname     def runCompatible(self): - dialog = gtk.FileChooserDialog(title=None, + dialog = gtk.FileChooserDialog(title=self.title,   action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,   buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,   gtk.STOCK_OPEN,gtk.RESPONSE_OK))
 
13
14
15
16
 
17
18
19
 
44
45
46
47
 
48
49
50
 
13
14
15
 
16
17
18
19
 
44
45
46
 
47
48
49
50
@@ -13,7 +13,7 @@
 import cStringIO  import Queue   -from mercurial import hg, ui, mdiff, cmdutil, match, util +from mercurial import hg, ui, mdiff, cmdutil, match, util, error    from tortoisehg.util.i18n import _  from tortoisehg.util import hglib, shlib, paths, thread2, settings @@ -44,7 +44,7 @@
    try:   repo = hg.repository(ui.ui(), path=paths.find_root()) - except hglib.RepoError: + except error.RepoError:   gtklib.idle_add_single_call(self.destroy)   return   self.repo = repo
Show Entire File tortoisehg/​hgtk/​hgcmd.py Stacked
This file's diff was not loaded because this changeset is very large. Load changes
 
13
14
15
16
 
17
18
19
 
232
233
234
235
 
236
237
238
 
13
14
15
 
16
17
18
19
 
232
233
234
 
235
236
237
238
@@ -13,7 +13,7 @@
 import pango  import tempfile   -from mercurial import hg, ui, extensions +from mercurial import hg, ui, extensions, error    from tortoisehg.util.i18n import _  from tortoisehg.util import hglib, settings @@ -232,7 +232,7 @@
  try:   repo = hg.repository(ui.ui(), path=self.root)   self.repo = repo - except hglib.RepoError: + except error.RepoError:   self.repo = None   return  
 
10
11
12
13
 
14
15
16
 
28
29
30
31
 
32
33
34
 
10
11
12
 
13
14
15
16
 
28
29
30
 
31
32
33
34
@@ -10,7 +10,7 @@
 import gobject  import re   -from mercurial import hg, ui, match, util +from mercurial import hg, ui, match, util, error    from tortoisehg.util.i18n import _  from tortoisehg.util import shlib, hglib, paths @@ -28,7 +28,7 @@
    try:   repo = hg.repository(ui.ui(), path=paths.find_root()) - except hglib.RepoError: + except error.RepoError:   gtklib.idle_add_single_call(self.destroy)   return   self.repo = repo
 
8
9
10
11
 
12
13
14
 
33
34
35
36
 
 
 
 
37
38
39
 
110
111
112
113
 
114
115
116
 
8
9
10
 
11
12
13
14
 
33
34
35
 
36
37
38
39
40
41
42
 
113
114
115
 
116
117
118
119
@@ -8,7 +8,7 @@
 import os  import gtk   -from mercurial import hg, ui, util +from mercurial import hg, ui, util, error    from tortoisehg.util.i18n import _  from tortoisehg.util import hglib, shlib @@ -33,7 +33,10 @@
  self.cwd = os.getcwd()     # preconditioning info - self.dest_path = os.path.abspath(repos and repos[0] or self.cwd) + path = os.path.abspath(repos and repos[0] or self.cwd) + if not os.path.isdir(path): + path = os.path.dirname(path) + self.dest_path = path     # layout table   table = gtklib.LayoutTable() @@ -110,7 +113,7 @@
    try:   hg.repository(u, dest, create=1) - except hglib.RepoError, inst: + except error.RepoError, inst:   dialog.error_dialog(self, _('Unable to create new repository'),   hglib.toutf(str(inst)))   return False
 
10
11
12
13
 
14
15
16
 
169
170
171
172
 
173
174
175
 
10
11
12
 
13
14
15
16
 
169
170
171
 
172
173
174
175
@@ -10,7 +10,7 @@
 import time  import urllib2   -from mercurial import ui, util +from mercurial import ui, util, error    from tortoisehg.util.i18n import _  from tortoisehg.util import hglib, thread2 @@ -169,7 +169,7 @@
  self.postfunc(ret)   except util.Abort, e:   self.ui.write_err(_('abort: ') + str(e) + '\n') - except (hglib.RepoError, urllib2.HTTPError), e: + except (error.RepoError, urllib2.HTTPError), e:   self.ui.write_err(str(e) + '\n')   except (Exception, OSError, IOError), e:   self.ui.write_err(str(e) + '\n')
Show Entire File tortoisehg/​hgtk/​hgtk.py Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File tortoisehg/​hgtk/​history.py Stacked
This file's diff was not loaded because this changeset is very large. Load changes
(No changes)
(No changes)
This file's diff was not loaded because this changeset is very large. Load changes
(No changes)
 
10
11
12
13
 
14
15
16
 
38
39
40
41
 
42
43
44
 
10
11
12
 
13
14
15
16
 
38
39
40
 
41
42
43
44
@@ -10,7 +10,7 @@
 import gtk  import gobject   -from mercurial import hg, ui, commands +from mercurial import hg, ui, commands, error    from tortoisehg.util.i18n import _  from tortoisehg.util import hglib, paths @@ -38,7 +38,7 @@
    try:   repo = hg.repository(ui.ui(), path=paths.find_root()) - except hglib.RepoError: + except error.RepoError:   gtklib.idle_add_single_call(self.destroy)   return   self.set_title(_('Merging in %s') % hglib.get_reponame(repo))
Show Entire File tortoisehg/​hgtk/​quickop.py Stacked
This file's diff was not loaded because this changeset is very large. Load changes
 
13
14
15
16
 
17
18
19
 
32
33
34
35
 
36
37
38
 
13
14
15
 
16
17
18
19
 
32
33
34
 
35
36
37
38
@@ -13,7 +13,7 @@
 import os  import time   -from mercurial import hg, ui +from mercurial import hg, ui, error    from tortoisehg.util.i18n import _  from tortoisehg.util import hglib, shlib, paths @@ -32,7 +32,7 @@
    try:   repo = hg.repository(ui.ui(), path=paths.find_root()) - except hglib.RepoError: + except error.RepoError:   gtklib.idle_add_single_call(self.destroy)   return   self.repo = repo
Show Entire File tortoisehg/​hgtk/​rename.py Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File tortoisehg/​hgtk/​serve.py Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File tortoisehg/​hgtk/​shellconf.py Stacked
renamed from tortoisehg/hgtk/taskbarui.py
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File tortoisehg/​hgtk/​status.py Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File tortoisehg/​hgtk/​statusbar.py Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File tortoisehg/​hgtk/​synch.py Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File tortoisehg/​hgtk/​thgconfig.py Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File tortoisehg/​hgtk/​thgimport.py Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File tortoisehg/​hgtk/​thgmq.py Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File tortoisehg/​hgtk/​thgstrip.py Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File tortoisehg/​hgtk/​update.py Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File tortoisehg/​hgtk/​visdiff.py Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File tortoisehg/​util/​cachethg.py Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File tortoisehg/​util/​hglib.py Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File tortoisehg/​util/​hgversion.py Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File tortoisehg/​util/​menuthg.py Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File tortoisehg/​util/​shlib.py Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File tortoisehg/​util/​thread2.py Stacked
This file's diff was not loaded because this changeset is very large. Load changes
This file's diff was not loaded because this changeset is very large. Load changes
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File win32/​shellext/​Makefile Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File win32/​shellext/​Makefile.nmake Stacked
This file's diff was not loaded because this changeset is very large. Load changes
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File win32/​shellext/​RegistryConfig.h Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File win32/​shellext/​ThgDebug.cpp Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File win32/​shellext/​Thgstatus.h Stacked
This file's diff was not loaded because this changeset is very large. Load changes
This file's diff was not loaded because this changeset is very large. Load changes
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File win32/​shellext/​TortoiseUtils.cpp Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File win32/​shellext/​TortoiseUtils.h Stacked
This file's diff was not loaded because this changeset is very large. Load changes
Show Entire File win32/​shellext/​terminate.cpp Stacked
This file's diff was not loaded because this changeset is very large. Load changes