e6af07359551abe1b585326137e987cc73fdab43
1# git-gui revision chooser
2# Copyright (C) 2006, 2007 Shawn Pearce
3
4class choose_rev {
5
6image create photo ::choose_rev::img_find -data {R0lGODlhEAAQAIYAAPwCBCQmJDw+PBQSFAQCBMza3NTm5MTW1HyChOT29Ozq7MTq7Kze5Kzm7Oz6/NTy9Iza5GzGzKzS1Nzy9Nz29Kzq9HTGzHTK1Lza3AwKDLzu9JTi7HTW5GTCzITO1Mzq7Hza5FTK1ESyvHzKzKzW3DQyNDyqtDw6PIzW5HzGzAT+/Dw+RKyurNTOzMTGxMS+tJSGdATCxHRydLSqpLymnLSijBweHERCRNze3Pz69PTy9Oze1OTSxOTGrMSqlLy+vPTu5OzSvMymjNTGvNS+tMy2pMyunMSefAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAe4gACCAAECA4OIiAIEBQYHBAKJgwIICQoLDA0IkZIECQ4PCxARCwSSAxITFA8VEBYXGBmJAQYLGhUbHB0eH7KIGRIMEBAgISIjJKaIJQQLFxERIialkieUGigpKRoIBCqJKyyLBwvJAioEyoICLS4v6QQwMQQyLuqLli8zNDU2BCf1lN3AkUPHDh49fAQAAEnGD1MCCALZEaSHkIUMBQS8wWMIkSJGhBzBmFEGgRsBUqpMiSgdAD+BAAAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7}
7
8field w ; # our megawidget path
9field w_list ; # list of currently filtered specs
10field w_filter ; # filter entry for $w_list
11
12field c_expr {}; # current revision expression
13field filter ; # current filter string
14field revtype head; # type of revision chosen
15field cur_specs [list]; # list of specs for $revtype
16field spec_head ; # list of all head specs
17field spec_trck ; # list of all tracking branch specs
18field spec_tag ; # list of all tag specs
19
20constructor new {path {title {}}} {
21 global all_heads current_branch
22
23 set w $path
24
25 if {$title ne {}} {
26 labelframe $w -text $title
27 } else {
28 frame $w
29 }
30 bind $w <Destroy> [cb _delete %W]
31
32 radiobutton $w.expr_r \
33 -text {Revision Expression:} \
34 -value expr \
35 -variable @revtype
36 entry $w.expr_t \
37 -borderwidth 1 \
38 -relief sunken \
39 -width 50 \
40 -textvariable @c_expr \
41 -validate key \
42 -validatecommand [cb _validate %d %S]
43 grid $w.expr_r $w.expr_t -sticky we -padx {0 5}
44
45 frame $w.types
46 radiobutton $w.types.head_r \
47 -text {Local Branch} \
48 -value head \
49 -variable @revtype
50 pack $w.types.head_r -side left
51 radiobutton $w.types.trck_r \
52 -text {Tracking Branch} \
53 -value trck \
54 -variable @revtype
55 pack $w.types.trck_r -side left
56 radiobutton $w.types.tag_r \
57 -text {Tag} \
58 -value tag \
59 -variable @revtype
60 pack $w.types.tag_r -side left
61 set w_filter $w.types.filter
62 entry $w_filter \
63 -borderwidth 1 \
64 -relief sunken \
65 -width 12 \
66 -textvariable @filter \
67 -validate key \
68 -validatecommand [cb _filter %P]
69 pack $w_filter -side right
70 pack [label $w.types.filter_icon \
71 -image ::choose_rev::img_find \
72 ] -side right
73 grid $w.types -sticky we -padx {0 5} -columnspan 2
74
75 frame $w.list
76 set w_list $w.list.l
77 listbox $w_list \
78 -font font_diff \
79 -width 50 \
80 -height 5 \
81 -selectmode browse \
82 -exportselection false \
83 -xscrollcommand [cb _sb_set $w.list.sbx h] \
84 -yscrollcommand [cb _sb_set $w.list.sby v]
85 pack $w_list -fill both -expand 1
86 grid $w.list -sticky nswe -padx {20 5} -columnspan 2
87
88 grid columnconfigure $w 1 -weight 1
89 grid rowconfigure $w 2 -weight 1
90
91 trace add variable @revtype write [cb _select]
92 bind $w_filter <Key-Return> [list focus $w_list]\;break
93 bind $w_filter <Key-Down> [list focus $w_list]
94
95 set spec_head [list]
96 foreach name $all_heads {
97 lappend spec_head [list $name refs/heads/$name]
98 }
99
100 set spec_trck [list]
101 foreach spec [all_tracking_branches] {
102 set name [lindex $spec 0]
103 regsub ^refs/(heads|remotes)/ $name {} name
104 lappend spec_trck [concat $name $spec]
105 }
106
107 set spec_tag [list]
108 foreach name [load_all_tags] {
109 lappend spec_tag [list $name refs/tags/$name]
110 }
111
112 if {[llength $spec_head] > 0} { set revtype head
113 } elseif {[llength $spec_trck] > 0} { set revtype trck
114 } elseif {[llength $spec_tag ] > 0} { set revtype tag
115 } else { set revtype expr
116 }
117
118 if {$revtype eq {head} && $current_branch ne {}} {
119 set i 0
120 foreach spec $spec_head {
121 if {[lindex $spec 0] eq $current_branch} {
122 $w_list selection set $i
123 break
124 }
125 incr i
126 }
127 }
128
129 return $this
130}
131
132method none {text} {
133 if {![winfo exists $w.none_r]} {
134 radiobutton $w.none_r \
135 -anchor w \
136 -value none \
137 -variable @revtype
138 grid $w.none_r -sticky we -padx {0 5} -columnspan 2
139 }
140 $w.none_r configure -text $text
141}
142
143method get {} {
144 switch -- $revtype {
145 head -
146 trck -
147 tag {
148 set i [$w_list curselection]
149 if {$i ne {}} {
150 return [lindex $cur_specs $i 0]
151 } else {
152 return {}
153 }
154 }
155
156 expr { return $c_expr }
157 none { return {} }
158 default { error "unknown type of revision" }
159 }
160}
161
162method pick_tracking_branch {} {
163 set revtype trck
164}
165
166method get_tracking_branch {} {
167 set i [$w_list curselection]
168 if {$i eq {} || $revtype ne {trck}} {
169 return {}
170 }
171 return [lrange [lindex $cur_specs $i] 1 end]
172}
173
174method get_commit {} {
175 set e [_expr $this]
176 if {$e eq {}} {
177 return {}
178 }
179 return [git rev-parse --verify "$e^0"]
180}
181
182method commit_or_die {} {
183 if {[catch {set new [get_commit $this]} err]} {
184
185 # Cleanup the not-so-friendly error from rev-parse.
186 #
187 regsub {^fatal:\s*} $err {} err
188 if {$err eq {Needed a single revision}} {
189 set err {}
190 }
191
192 set top [winfo toplevel $w]
193 set msg "Invalid revision: [get $this]\n\n$err"
194 tk_messageBox \
195 -icon error \
196 -type ok \
197 -title [wm title $top] \
198 -parent $top \
199 -message $msg
200 error $msg
201 }
202 return $new
203}
204
205method _expr {} {
206 switch -- $revtype {
207 head -
208 trck -
209 tag {
210 set i [$w_list curselection]
211 if {$i ne {}} {
212 return [lindex $cur_specs $i 1]
213 } else {
214 error "No revision selected."
215 }
216 }
217
218 expr {
219 if {$c_expr ne {}} {
220 return $c_expr
221 } else {
222 error "Revision expression is empty."
223 }
224 }
225 none { return {} }
226 default { error "unknown type of revision" }
227 }
228}
229
230method _validate {d S} {
231 if {$d == 1} {
232 if {[regexp {\s} $S]} {
233 return 0
234 }
235 if {[string length $S] > 0} {
236 set revtype expr
237 }
238 }
239 return 1
240}
241
242method _filter {P} {
243 if {[regexp {\s} $P]} {
244 return 0
245 }
246 _rebuild $this $P
247 return 1
248}
249
250method _select {args} {
251 _rebuild $this $filter
252 if {[$w_filter cget -state] eq {normal}} {
253 focus $w_filter
254 }
255}
256
257method _rebuild {pat} {
258 set ste normal
259 switch -- $revtype {
260 head { set new $spec_head }
261 trck { set new $spec_trck }
262 tag { set new $spec_tag }
263 expr -
264 none {
265 set new [list]
266 set ste disabled
267 }
268 }
269
270 if {[$w_list cget -state] eq {disabled}} {
271 $w_list configure -state normal
272 }
273 $w_list delete 0 end
274
275 if {$pat ne {}} {
276 set pat *${pat}*
277 }
278 set cur_specs [list]
279 foreach spec $new {
280 set txt [lindex $spec 0]
281 if {$pat eq {} || [string match $pat $txt]} {
282 lappend cur_specs $spec
283 $w_list insert end $txt
284 }
285 }
286
287 if {[$w_filter cget -state] ne $ste} {
288 $w_list configure -state $ste
289 $w_filter configure -state $ste
290 }
291}
292
293method _delete {current} {
294 if {$current eq $w} {
295 delete_this
296 }
297}
298
299method _sb_set {sb orient first last} {
300 set old_focus [focus -lastfor $w]
301
302 if {$first == 0 && $last == 1} {
303 if {[winfo exists $sb]} {
304 destroy $sb
305 if {$old_focus ne {}} {
306 update
307 focus $old_focus
308 }
309 }
310 return
311 }
312
313 if {![winfo exists $sb]} {
314 if {$orient eq {h}} {
315 scrollbar $sb -orient h -command [list $w_list xview]
316 pack $sb -fill x -side bottom -before $w_list
317 } else {
318 scrollbar $sb -orient v -command [list $w_list yview]
319 pack $sb -fill y -side right -before $w_list
320 }
321 if {$old_focus ne {}} {
322 update
323 focus $old_focus
324 }
325 }
326 $sb set $first $last
327}
328
329}