1#
2# Tcl Library for TkCVS
3#
4
5#
6# Current working directory display.  Handles all of the functions
7# concerned with navigating about the current directory on the main
8# window.
9#
10
11proc workdir_setup {} {
12  global cwd
13  global module_dir
14  global cvscfg
15  global cvsglb
16  global current_tagname
17  global logclass
18  global tcl_platform
19
20  gen_log:log T "ENTER"
21  set cwd [pwd]
22  set pid [pid]
23
24  if {[winfo exists .workdir]} {
25    wm deiconify .workdir
26    raise .workdir
27    return
28  }
29
30  # Make a new toplevel and unmap . so that the working directory browser
31  # the module browser are equal
32  toplevel .workdir
33  wm title .workdir "TkCVS $cvscfg(version) Working Directory"
34  wm iconname .workdir "TkCVS"
35  if {$tcl_platform(platform) eq "unix"} {
36    wm iconbitmap .workdir @$cvscfg(bitmapdir)/tkcvs48.xbm
37  }
38  wm minsize .workdir 430 300
39  wm protocol .workdir WM_DELETE_WINDOW { .workdir.close invoke }
40  wm withdraw .
41
42  if {[catch "image type Conflict"]} {
43    workdir_images
44  }
45  if {[info exists cvscfg(workgeom)]} {
46    wm geometry .workdir $cvscfg(workgeom)
47  }
48
49  workdir_menus
50
51  #
52  # Top section - where we are, where the module is
53  #
54  frame .workdir.top -relief groove -border 2
55  pack .workdir.top -side top -fill x
56
57  ::picklist::entry .workdir.top.tcwd cwd directory
58  ::picklist::bind .workdir.top.tcwd <Return> \
59     {if {[pwd] != $cwd} {change_dir "$cwd"}}
60
61  button .workdir.top.updir_btn -image updir \
62    -command {change_dir ..}
63
64  label .workdir.top.lmodule -text "Path"
65  label .workdir.top.tmodule -textvariable module_dir -anchor w -relief groove
66
67  label .workdir.top.ltagname -text "Tag"
68  label .workdir.top.ttagname -textvariable current_tagname \
69     -anchor w -relief groove
70
71  # Make the Repository Browser button prominent
72  button .workdir.top.bmodbrowse -image Modules \
73     -command modbrowse_run
74
75  label .workdir.top.lcvsroot -text "CVSROOT"
76  entry .workdir.top.tcvsroot -textvariable cvscfg(cvsroot) \
77     -bd 1 -relief sunk -state readonly
78
79  grid columnconf .workdir.top 1 -weight 1
80  grid rowconf .workdir.top 3 -weight 1
81  grid .workdir.top.updir_btn -column 0 -row 0 -sticky s
82  grid .workdir.top.tcwd -column 1 -row 0 -columnspan 2 \
83    -sticky sew -padx 4 -pady 1
84  grid .workdir.top.lmodule -column 0 -row 1 -sticky nw
85  grid .workdir.top.tmodule -column 1 -row 1 -columnspan 2\
86     -padx 4 -pady 1 -sticky new
87  grid .workdir.top.bmodbrowse -column 2 -row 2 -rowspan 2 -sticky w
88  grid .workdir.top.ltagname -column 0 -row 2 -sticky nw
89  grid .workdir.top.ttagname -column 1 -row 2 -padx 4 -pady 1 -sticky new
90  grid .workdir.top.lcvsroot -column 0 -row 3 -sticky nw
91  grid .workdir.top.tcvsroot -column 1 -row 3 -padx 3 -sticky new
92
93
94  # Pack the bottom before the middle so it doesnt disappear if
95  # the window is resized smaller
96  #frame .workdir.bottom -relief groove -border 2 -height 128
97  frame .workdir.bottom
98  frame .workdir.bottom.filters -relief raised
99  pack .workdir.bottom -side bottom -fill x
100  pack .workdir.bottom.filters -side top -fill x
101
102  label .workdir.bottom.filters.showlbl -text "Show:" -anchor w
103  entry .workdir.bottom.filters.showentry -textvariable cvscfg(file_filter) -width 12
104  label .workdir.bottom.filters.hidelbl -text "   Hide:" -anchor w
105  entry .workdir.bottom.filters.hideentry -width 12 \
106     -textvariable cvsglb(default_ignore_filter)
107  label .workdir.bottom.filters.space -text "    "
108  button .workdir.bottom.filters.cleanbutton -text "Clean:" \
109     -pady 0 -highlightthickness 0 \
110     -command workdir_cleanup
111  entry .workdir.bottom.filters.cleanentry -width 12 \
112     -textvariable cvscfg(clean_these)
113  bind .workdir.bottom.filters.showentry <Return> {setup_dir}
114  bind .workdir.bottom.filters.hideentry <Return> {
115     set cvsglb(default_ignore_filter) [.workdir.bottom.filters.hideentry get]
116     setup_dir}
117  bind .workdir.bottom.filters.cleanentry <Return> {workdir_cleanup}
118  pack .workdir.bottom.filters.showlbl -side left
119  pack .workdir.bottom.filters.showentry -side left
120  pack .workdir.bottom.filters.hidelbl -side left
121  pack .workdir.bottom.filters.hideentry -side left
122  pack .workdir.bottom.filters.space -side left
123  pack .workdir.bottom.filters.cleanbutton -side left -ipadx 2 -ipady 0
124  pack .workdir.bottom.filters.cleanentry -side left
125
126  frame .workdir.bottom.buttons -relief groove -bd 2
127  frame .workdir.bottom.buttons.funcs -relief groove -bd 2
128  frame .workdir.bottom.buttons.dirfuncs -relief groove -bd 2
129  frame .workdir.bottom.buttons.cvsfuncs -relief groove -bd 2
130  frame .workdir.bottom.buttons.oddfuncs -relief groove -bd 2
131  frame .workdir.bottom.buttons.close -relief groove -bd 2
132  pack .workdir.bottom.buttons -side top -fill x -expand yes
133  pack .workdir.bottom.buttons.close -side right -padx 10
134  pack .workdir.bottom.buttons.funcs -side left -expand yes -anchor w
135  pack .workdir.bottom.buttons.dirfuncs -side left -expand yes -anchor w
136  pack .workdir.bottom.buttons.cvsfuncs -side left -expand yes -anchor w
137  pack .workdir.bottom.buttons.oddfuncs -side left -expand yes -anchor w
138
139  #
140  # Action buttons along the bottom of the screen.
141  #
142  button .workdir.bottom.buttons.funcs.bedit_files -image Fileedit \
143     -command { workdir_edit_file [workdir_list_files] }
144  button .workdir.bottom.buttons.funcs.bview_files -image Fileview \
145     -command { workdir_view_file [workdir_list_files] }
146  button .workdir.bottom.buttons.funcs.bdelete_file -image Delete \
147     -command { workdir_delete_file [workdir_list_files] }
148  button .workdir.bottom.buttons.funcs.bmkdir -image Dir_new \
149     -command { file_input_and_do "New Directory" workdir_newdir}
150
151  button .workdir.bottom.buttons.dirfuncs.brefresh -image Refresh \
152     -command { setup_dir }
153  button .workdir.bottom.buttons.dirfuncs.bcheckdir -image Check
154
155  button .workdir.bottom.buttons.cvsfuncs.blogfile -image Branches \
156     -command { cvs_branches [workdir_list_files] }
157  button .workdir.bottom.buttons.cvsfuncs.bannotate -image Annotate \
158     -command { cvs_annotate $current_tagname [workdir_list_files] }
159  button .workdir.bottom.buttons.cvsfuncs.bfilelog -image Log \
160    -command { cvs_log [workdir_list_files] }
161  button .workdir.bottom.buttons.cvsfuncs.bdiff -image Diff \
162     -command { comparediff [workdir_list_files] }
163  button .workdir.bottom.buttons.cvsfuncs.bconflict -image Conflict \
164     -command { cvs_merge_conflict [workdir_list_files] }
165
166  button .workdir.bottom.buttons.cvsfuncs.btag -image Tag \
167     -command { file_tag_dialog "tag" }
168  button .workdir.bottom.buttons.cvsfuncs.bbranchtag -image Branchtag \
169     -command { file_tag_dialog "branch" }
170  button .workdir.bottom.buttons.cvsfuncs.badd_files -image Add \
171     -command { add_dialog [workdir_list_files] }
172  button .workdir.bottom.buttons.cvsfuncs.bremove -image Remove \
173     -command { subtract_dialog [workdir_list_files] }
174  button .workdir.bottom.buttons.cvsfuncs.bcheckin -image Checkin \
175      -command cvs_commit_dialog
176  button .workdir.bottom.buttons.cvsfuncs.bupdate -image Checkout
177  button .workdir.bottom.buttons.cvsfuncs.bupdateopts -image CheckoutOpts \
178     -command { cvs_update_options }
179  button .workdir.bottom.buttons.cvsfuncs.brevert -image Revert \
180     -command { cvs_revert [workdir_list_files] }
181  button .workdir.bottom.buttons.cvsfuncs.bjoin -image DirBranches \
182     -command cvs_joincanvas
183
184  button .workdir.bottom.buttons.oddfuncs.bcvsedit_files -image Edit \
185     -command { cvs_edit [workdir_list_files] }
186  button .workdir.bottom.buttons.oddfuncs.bunedit_files -image Unedit \
187     -command { cvs_unedit [workdir_list_files] }
188  button .workdir.bottom.buttons.oddfuncs.block -image Lock
189  button .workdir.bottom.buttons.oddfuncs.bunlock -image UnLock
190  button .workdir.close -text "Close" \
191      -command {
192        global cvscfg
193        set cvscfg(workgeom) [wm geometry .workdir]
194        destroy .workdir
195        exit_cleanup 0
196      }
197
198  # These buttons work in any directory
199  grid .workdir.bottom.buttons.funcs.bdelete_file -column 0 -row 0 \
200    -ipadx 4
201  grid .workdir.bottom.buttons.funcs.bedit_files -column 1 -row 0 \
202     -ipadx 4
203  grid .workdir.bottom.buttons.funcs.bmkdir -column 0 -row 1 \
204     -ipadx 4
205  grid .workdir.bottom.buttons.funcs.bview_files -column 1 -row 1 \
206     -ipadx 4
207
208  # Directory functions
209  grid rowconf .workdir.bottom.buttons.dirfuncs 0 -weight 1
210  grid .workdir.bottom.buttons.dirfuncs.brefresh       -column 0 -row 0 \
211     -ipadx 4 -ipady 4
212  grid .workdir.bottom.buttons.dirfuncs.bcheckdir      -column 1 -row 0 \
213     -ipadx 4 -ipady 4
214
215  # Revcontrol functions
216  grid .workdir.bottom.buttons.cvsfuncs.blogfile      -column 0 -row 0 \
217    -ipadx 4
218  grid .workdir.bottom.buttons.cvsfuncs.bjoin         -column 0 -row 1 \
219    -ipadx 4
220  grid .workdir.bottom.buttons.cvsfuncs.bdiff         -column 1 -row 0 \
221    -ipadx 2
222  grid .workdir.bottom.buttons.cvsfuncs.bconflict     -column 1 -row 1 \
223    -ipadx 2
224  grid .workdir.bottom.buttons.cvsfuncs.bfilelog      -column 2 -row 0
225  grid .workdir.bottom.buttons.cvsfuncs.bannotate     -column 2 -row 1
226  grid .workdir.bottom.buttons.cvsfuncs.bupdate       -column 3 -row 0 \
227    -ipadx 4
228  grid .workdir.bottom.buttons.cvsfuncs.bcheckin      -column 3 -row 1 \
229    -ipadx 4
230  grid .workdir.bottom.buttons.cvsfuncs.bupdateopts   -column 4 -row 0 \
231    -ipadx 4
232  grid .workdir.bottom.buttons.cvsfuncs.brevert       -column 4 -row 1 \
233    -ipadx 4
234  grid .workdir.bottom.buttons.cvsfuncs.badd_files    -column 5 -row 0
235  grid .workdir.bottom.buttons.cvsfuncs.bremove       -column 5 -row 1
236  grid .workdir.bottom.buttons.cvsfuncs.btag          -column 6 -row 0 \
237    -ipadx 4
238  grid .workdir.bottom.buttons.cvsfuncs.bbranchtag    -column 6 -row 1 \
239    -ipadx 4
240
241  # These are specialized an not always available
242  grid .workdir.bottom.buttons.oddfuncs.block          -column 0 -row 0
243  grid .workdir.bottom.buttons.oddfuncs.bunlock        -column 0 -row 1
244  grid .workdir.bottom.buttons.oddfuncs.bcvsedit_files -column 1 -row 0
245  grid .workdir.bottom.buttons.oddfuncs.bunedit_files  -column 1 -row 1
246
247  pack .workdir.close -in .workdir.bottom.buttons.close \
248    -side right -fill both -expand yes
249
250  set_tooltips .workdir.top.updir_btn \
251     {"Go up (..)"}
252  set_tooltips .workdir.bottom.buttons.funcs.bedit_files \
253     {"Edit the selected files"}
254  set_tooltips .workdir.bottom.buttons.funcs.bview_files \
255     {"View the selected files"}
256  set_tooltips .workdir.bottom.buttons.funcs.bdelete_file \
257     {"Delete the selected files from the current directory"}
258  set_tooltips .workdir.bottom.buttons.funcs.bmkdir \
259     {"Make a new directory"}
260
261  set_tooltips .workdir.bottom.buttons.dirfuncs.brefresh \
262     {"Re-read the current directory"}
263  set_tooltips .workdir.bottom.buttons.cvsfuncs.bjoin \
264     {"Directory Branch Diagram and Merge Tool"}
265  set_tooltips .workdir.bottom.buttons.dirfuncs.bcheckdir \
266     {"Check the status of the directory"}
267
268  set_tooltips .workdir.bottom.buttons.cvsfuncs.blogfile \
269     {"Graphical Branch Diagram of the selected files"}
270  set_tooltips .workdir.bottom.buttons.cvsfuncs.bfilelog \
271     {"Revision Log of the selected files"}
272  set_tooltips .workdir.bottom.buttons.cvsfuncs.bannotate \
273     {"Revision where each line was modified (annotate/blame)"}
274  set_tooltips .workdir.bottom.buttons.cvsfuncs.bdiff \
275     {"Compare the selected files with the repository version"}
276  set_tooltips .workdir.bottom.buttons.cvsfuncs.bconflict \
277     {"Merge Conflicts using TkDiff"}
278  set_tooltips .workdir.bottom.buttons.cvsfuncs.badd_files \
279     {"Add the selected files to the repository"}
280  set_tooltips .workdir.bottom.buttons.cvsfuncs.btag \
281     {"Tag the selected files"}
282  set_tooltips .workdir.bottom.buttons.cvsfuncs.bbranchtag \
283     {"Branch the selected files"}
284  set_tooltips .workdir.bottom.buttons.cvsfuncs.bremove \
285     {"Remove the selected files from the repository"}
286  set_tooltips .workdir.bottom.buttons.cvsfuncs.bcheckin \
287     {"Check in (commit) the selected files to the repository"}
288  set_tooltips .workdir.bottom.buttons.cvsfuncs.bupdate \
289     {"Update (checkout, patch) the selected files from the repository"}
290  set_tooltips .workdir.bottom.buttons.cvsfuncs.brevert \
291     {"Revert the selected files, discarding local edits"}
292  set_tooltips .workdir.bottom.buttons.cvsfuncs.bupdateopts \
293     {"Update with options (-A, -r, -f, -d, -kb)"}
294
295  set_tooltips .workdir.bottom.buttons.oddfuncs.block \
296     {"Lock the selected files"}
297  set_tooltips .workdir.bottom.buttons.oddfuncs.bunlock \
298     {"Unlock the selected files"}
299  set_tooltips .workdir.bottom.buttons.oddfuncs.bcvsedit_files \
300     {"Set the Edit flag on the selected files"}
301  set_tooltips .workdir.bottom.buttons.oddfuncs.bunedit_files \
302     {"Reset the Edit flag on the selected files"}
303
304  set_tooltips .workdir.top.bmodbrowse \
305     {"Open the Repository Browser"}
306  set_tooltips .workdir.close \
307     {"Close the Working Directory Browser"}
308
309
310  frame .workdir.main
311  pack .workdir.main -side bottom -fill both -expand 1 -fill both
312  update idletasks
313
314  if {! [winfo ismapped .workdir]} {
315    wm deiconify .workdir
316  }
317
318  #change_dir "[pwd]"
319  setup_dir
320  gen_log:log T "LEAVE"
321}
322
323proc workdir_images {} {
324  global cvscfg
325
326  image create photo arr_up \
327    -format gif -file [file join $cvscfg(bitmapdir) arrow_up.gif]
328  image create photo arr_dn \
329    -format gif -file [file join $cvscfg(bitmapdir) arrow_dn.gif]
330  image create photo arh_up \
331    -format gif -file [file join $cvscfg(bitmapdir) arrow_hl_up.gif]
332  image create photo arh_dn \
333    -format gif -file [file join $cvscfg(bitmapdir) arrow_hl_dn.gif]
334  image create photo updir \
335    -format gif -file [file join $cvscfg(bitmapdir) updir.gif]
336  image create photo Folder \
337    -format gif -file [file join $cvscfg(bitmapdir) dir.gif]
338  image create photo Check \
339    -format gif -file [file join $cvscfg(bitmapdir) check.gif]
340  image create photo Fileview \
341    -format gif -file [file join $cvscfg(bitmapdir) fileview.gif]
342  image create photo Fileedit \
343    -format gif -file [file join $cvscfg(bitmapdir) fileedit.gif]
344  image create photo Annotate \
345    -format gif -file [file join $cvscfg(bitmapdir) annotate.gif]
346  image create photo Delete \
347    -format gif -file [file join $cvscfg(bitmapdir) delete.gif]
348  image create photo Dir_new \
349    -format gif -file [file join $cvscfg(bitmapdir) dir_new.gif]
350  image create photo Refresh \
351    -format gif -file [file join $cvscfg(bitmapdir) loop-glasses.gif]
352  image create photo Branches \
353    -format gif -file [file join $cvscfg(bitmapdir) branch.gif]
354  image create photo DirBranches \
355    -format gif -file [file join $cvscfg(bitmapdir) dirbranch.gif]
356  image create photo Add \
357    -format gif -file [file join $cvscfg(bitmapdir) add.gif]
358  image create photo Remove \
359    -format gif -file [file join $cvscfg(bitmapdir) remove.gif]
360  image create photo Diff \
361    -format gif -file [file join $cvscfg(bitmapdir) diff.gif]
362  image create photo Checkin \
363    -format gif -file [file join $cvscfg(bitmapdir) checkin.gif]
364  image create photo Revert \
365    -format gif -file [file join $cvscfg(bitmapdir) loop-ball.gif]
366  image create photo Edit \
367    -format gif -file [file join $cvscfg(bitmapdir) edit.gif]
368  image create photo Unedit \
369    -format gif -file [file join $cvscfg(bitmapdir) unedit.gif]
370  image create photo Modules \
371    -format gif -file [file join $cvscfg(bitmapdir) modbrowse.gif]
372  image create photo Modules_cvs \
373    -format gif -file [file join $cvscfg(bitmapdir) modbrowse_cvs.gif]
374  image create photo Modules_svn \
375    -format gif -file [file join $cvscfg(bitmapdir) modbrowse_svn.gif]
376  image create photo Lock \
377    -format gif -file [file join $cvscfg(bitmapdir) locked.gif]
378  image create photo UnLock \
379    -format gif -file [file join $cvscfg(bitmapdir) unlocked.gif]
380  image create photo Tags \
381    -format gif -file [file join $cvscfg(bitmapdir) tags.gif]
382  image create photo Mergebranch \
383    -format gif -file [file join $cvscfg(bitmapdir) newmerge_simple.gif]
384  image create photo Mergediff \
385    -format gif -file [file join $cvscfg(bitmapdir) newmerge.gif]
386  image create photo Conflict \
387    -format gif -file [file join $cvscfg(bitmapdir) conflict.gif]
388
389  image create photo Man \
390    -format gif -file [file join $cvscfg(bitmapdir) man.gif]
391}
392
393proc workdir_menus {} {
394  global cvscfg
395  global cvsglb
396  global cvsmenu
397  global usermenu
398  global execmenu
399  global bookmarks
400
401  gen_log:log T "ENTER"
402  set startdir "[pwd]"
403
404  .workdir configure -menu .workdir.menubar
405  menu .workdir.menubar
406
407  #
408  # Create the Menu bar
409  #
410  .workdir.menubar add cascade -label "File" -menu .workdir.menubar.file -underline 0
411  menu .workdir.menubar.file -tearoff 0
412  .workdir.menubar add cascade -label "CVS" -menu .workdir.menubar.cvs -underline 0
413  menu .workdir.menubar.cvs -tearoff 0
414  .workdir.menubar add cascade -label "SVN" -menu .workdir.menubar.svn -underline 0
415  menu .workdir.menubar.svn -tearoff 0
416  .workdir.menubar add cascade -label "RCS" -menu .workdir.menubar.rcs -underline 0
417  menu .workdir.menubar.rcs -tearoff 0
418  .workdir.menubar add cascade -label "Reports" -menu .workdir.menubar.reports -underline 2
419  menu .workdir.menubar.reports -tearoff 0
420  .workdir.menubar add cascade -label "Options" -menu .workdir.menubar.options -underline 0
421  menu .workdir.menubar.options -tearoff 0
422
423  if { [info exists cvsmenu] || \
424       [info exists usermenu] || \
425       [info exists execmenu]} {
426    .workdir.menubar add cascade -label "User Defined" -menu .workdir.menubar.user -underline 0
427    menu .workdir.menubar.user -tearoff 0
428    gen_log:log T "Adding user defined menu"
429  }
430  .workdir.menubar add cascade -label "Go" -menu .workdir.menubar.goto -underline 0
431  menu .workdir.menubar.goto -tearoff 0
432
433  menu_std_help .workdir.menubar
434
435  #
436  # Create the Menus
437  #
438
439  # File
440  .workdir.menubar.file add command -label "Open Selection" -underline 0 \
441     -command { workdir_edit_file [workdir_list_files] }
442  .workdir.menubar.file add command -label "Print Selected File" -underline 0 \
443     -command { workdir_print_file  [workdir_list_files ] }
444  .workdir.menubar.file add command -label "Make New Directory" -underline 0 \
445     -command { file_input_and_do "New Directory" workdir_newdir}
446  .workdir.menubar.file add separator
447  .workdir.menubar.file add command -label "Browse Modules" -underline 0 \
448     -command modbrowse_run
449  .workdir.menubar.file add command -label "Cleanup Directory" -underline 4 \
450     -command workdir_cleanup
451  .workdir.menubar.file add separator
452  .workdir.menubar.file add command -label "Shell window" -underline 0 \
453     -command { exec::new $cvscfg(shell) }
454  .workdir.menubar.file add separator
455  .workdir.menubar.file add command -label Close -underline 1 \
456     -command {.workdir.close invoke}
457  .workdir.menubar.file add command -label Exit -underline 1 \
458     -command { exit_cleanup 1 }
459
460  # CVS
461  .workdir.menubar.cvs add command -label "Update" -underline 0 \
462     -command { \
463        cvs_update {BASE} {Normal} {Remove} {recurse} {prune} {No} { } [workdir_list_files] }
464  .workdir.menubar.cvs add command -label "Update with Options" -underline 7 \
465     -command cvs_update_options
466  .workdir.menubar.cvs add command -label "Commit/Checkin" -underline 0 \
467     -command cvs_commit_dialog
468  .workdir.menubar.cvs add command -label "Add Files" -underline 0 \
469     -command { add_dialog [workdir_list_files] }
470  .workdir.menubar.cvs add command -label "Add Recursively" \
471     -command { addir_dialog [workdir_list_files] }
472  .workdir.menubar.cvs add command -label "Remove Files" -underline 0 \
473     -command { subtract_dialog [workdir_list_files] }
474  .workdir.menubar.cvs add command -label "Remove Recursively" \
475     -command { subtractdir_dialog [workdir_list_files] }
476  .workdir.menubar.cvs add command -label "Set Binary Flag" \
477     -command { cvs_binary [workdir_list_files] }
478  .workdir.menubar.cvs add command -label "Unset Binary Flag" \
479     -command { cvs_ascii [workdir_list_files] }
480  .workdir.menubar.cvs add command -label "Set Edit Flag (Edit)" -underline 15 \
481     -command { cvs_edit [workdir_list_files] }
482  .workdir.menubar.cvs add command -label "Unset Edit Flag (Unedit)" -underline 11 \
483     -command { cvs_unedit [workdir_list_files] }
484  .workdir.menubar.cvs add command -label "Tag Files" -underline 0 \
485     -command { file_tag_dialog "tag" }
486  .workdir.menubar.cvs add command -label "Browse the Log Diagram" \
487     -command { cvs_branches [workdir_list_files] }
488  .workdir.menubar.cvs add command -label "Resolve Conflicts" \
489     -command { cvs_merge_conflict [workdir_list_files] }
490  .workdir.menubar.cvs add separator
491  .workdir.menubar.cvs add command -label "Release" \
492     -command { release_dialog [workdir_list_files] }
493  .workdir.menubar.cvs add command -label "Join (Merge) Directory" \
494     -underline 0 -command { cvs_directory_merge }
495  .workdir.menubar.cvs add command -label "Import CWD into Repository" \
496     -underline 0 -command import_run
497
498  # SVN
499  .workdir.menubar.svn add command -label "Update" -underline 0 \
500     -command {svn_update [workdir_list_files]}
501  .workdir.menubar.svn add command -label "Resolve (Un-mark Conflict)" -underline 0 \
502     -command {svn_resolve [workdir_list_files]}
503  .workdir.menubar.svn add command -label "Commit/Checkin" -underline 0 \
504     -command svn_commit_dialog
505  .workdir.menubar.svn add command -label "Add Files" -underline 0 \
506     -command { add_dialog [workdir_list_files] }
507  .workdir.menubar.svn add command -label "Remove Files" -underline 0 \
508     -command { subtract_dialog [workdir_list_files] }
509  .workdir.menubar.svn add command -label "Browse the Log Diagram" \
510     -command { svn_branches [workdir_list_files] }
511  .workdir.menubar.svn add separator
512  .workdir.menubar.svn add command -label "Import CWD into Repository" \
513     -underline 0 -command svn_import_run
514
515  # RCS
516  .workdir.menubar.rcs add command -label "Checkout" -underline 0 \
517     -command { rcs_checkout [workdir_list_files] }
518  .workdir.menubar.rcs add command -label "Checkin" -underline 0 \
519     -command { rcs_checkin [workdir_list_files] }
520  .workdir.menubar.rcs add command -label "Browse the Log Diagram" \
521     -command { rcs_branches [workdir_list_files] }
522
523  # These commands will vary according to revision system.  Does it still make sense to
524  # keep them in their own menu?
525  .workdir.menubar.reports add command -label "Check Directory" -underline 0
526  .workdir.menubar.reports add command -label "Status" -underline 0
527  .workdir.menubar.reports add command -label "Log" -underline 0
528  .workdir.menubar.reports add command -label "Annotate/Blame" -underline 0
529  .workdir.menubar.reports add command -label "Info" -underline 0
530
531  .workdir.menubar.options add checkbutton -label "Show hidden files" \
532     -variable cvscfg(allfiles) -onvalue true -offvalue false \
533     -command setup_dir
534  .workdir.menubar.options add checkbutton -label "Automatic directory status" \
535     -variable cvscfg(auto_status) -onvalue true -offvalue false
536  .workdir.menubar.options add checkbutton -label "Confirmation Dialogs" \
537     -variable cvscfg(confirm_prompt) -onvalue true -offvalue false
538  .workdir.menubar.options add separator
539  .workdir.menubar.options add checkbutton -label "Editor/Author/Locker Column" \
540     -variable cvscfg(showeditcol) -onvalue true -offvalue false \
541     -command { if {($incvs || $insvn || $inrcs) && $cvscfg(showeditcol)} {
542                  DirCanvas:map_column .workdir.main editcol
543                } else {
544                  DirCanvas:unmap_column .workdir.main editcol
545                }
546              }
547  .workdir.menubar.options add checkbutton -label "Status Column" \
548     -variable cvscfg(showstatcol) -onvalue true -offvalue false \
549     -command { if {($incvs || $insvn || $inrcs) && $cvscfg(showstatcol)} {
550                  DirCanvas:map_column .workdir.main statcol
551                } else {
552                  DirCanvas:unmap_column .workdir.main statcol
553                }
554              }
555  .workdir.menubar.options add checkbutton -label "Date Column" \
556     -variable cvscfg(showdatecol) -onvalue true -offvalue false \
557     -command { if {$cvscfg(showdatecol)} {
558                  DirCanvas:map_column .workdir.main datecol
559                } else {
560                  DirCanvas:unmap_column .workdir.main datecol
561                }
562              }
563  .workdir.menubar.options add radiobutton -label "Sort by Name" \
564     -variable cvscfg(sortcol) -value filecol \
565     -command "DirCanvas:sort_by_col .workdir.main filecol -decreasing"
566  .workdir.menubar.options add radiobutton -label "Sort by Status" \
567     -variable cvscfg(sortcol) -value statcol \
568     -command "DirCanvas:sort_by_col .workdir.main statcol -decreasing"
569  .workdir.menubar.options add separator
570  .workdir.menubar.options add checkbutton -label "Report->Check Shows Unknown Files" \
571     -variable cvscfg(status_filter) -onvalue false -offvalue true
572  .workdir.menubar.options add checkbutton -label "Report->Check/Status are Recursive" \
573     -variable cvscfg(recurse) -onvalue true -offvalue false
574  .workdir.menubar.options add cascade -label "Status Detail" \
575     -menu .workdir.menubar.options.report_detail
576  .workdir.menubar.options add cascade -label "Log Detail" \
577     -menu .workdir.menubar.options.logfile_detail
578  .workdir.menubar.options add separator
579  .workdir.menubar.options add checkbutton -label "Tracing On/Off" \
580     -variable cvscfg(logging) -onvalue true -offvalue false \
581     -command log_toggle
582  .workdir.menubar.options add cascade -label "Trace Level" \
583     -menu .workdir.menubar.options.loglevel
584  .workdir.menubar.options add separator
585  .workdir.menubar.options add command -label "Save Options" -underline 0 \
586     -command save_options
587
588  menu .workdir.menubar.options.loglevel
589  .workdir.menubar.options.loglevel add checkbutton -label "commands (C)" \
590     -variable logclass(C) -onvalue "C" -offvalue "" \
591     -command gen_log:changeclass
592  .workdir.menubar.options.loglevel add checkbutton -label "stderr (E)" \
593     -variable logclass(E) -onvalue "E" -offvalue "" \
594     -command gen_log:changeclass
595  .workdir.menubar.options.loglevel add checkbutton -label "stdout and file creation/deletion (F)"\
596     -variable logclass(F) -onvalue "F" -offvalue "" \
597     -command gen_log:changeclass
598  .workdir.menubar.options.loglevel add checkbutton -label "Function entry/exit (T)" \
599     -variable logclass(T) -onvalue "T" -offvalue "" \
600     -command gen_log:changeclass
601  .workdir.menubar.options.loglevel add checkbutton -label "Debugging (D)" \
602     -variable logclass(D) -onvalue "D" -offvalue "" \
603     -command gen_log:changeclass
604
605  menu .workdir.menubar.options.report_detail
606  .workdir.menubar.options.report_detail add radiobutton -label "Verbose" \
607     -variable cvscfg(rdetail) -value "verbose"
608  .workdir.menubar.options.report_detail add radiobutton -label "Summary" \
609     -variable cvscfg(rdetail) -value "summary"
610  .workdir.menubar.options.report_detail add radiobutton -label "Terse" \
611     -variable cvscfg(rdetail) -value "terse"
612
613  menu .workdir.menubar.options.logfile_detail
614  .workdir.menubar.options.logfile_detail add radiobutton -label "Summary" \
615     -variable cvscfg(ldetail) -value "summary"
616  .workdir.menubar.options.logfile_detail add radiobutton -label "Latest" \
617     -variable cvscfg(ldetail) -value "latest"
618  .workdir.menubar.options.logfile_detail add radiobutton -label "Verbose" \
619     -variable cvscfg(ldetail) -value "verbose"
620
621  .workdir.menubar.goto add command -label "Go Home" \
622     -command {change_dir $cvscfg(home)}
623  .workdir.menubar.goto add command -label "Add Bookmark" \
624     -command add_bookmark
625  .workdir.menubar.goto add command -label "Delete Bookmark" \
626     -command delete_bookmark_dialog
627  .workdir.menubar.goto add separator
628  foreach mark [lsort [array names bookmarks]] {
629    # Backward compatibility.  Value used to be a placeholder, is now a revsystem type
630    if {$bookmarks($mark) == "t"} {set bookmarks($mark) ""}
631    .workdir.menubar.goto add command -label "$mark $bookmarks($mark)" \
632       -command "change_dir \"$mark\""
633  }
634
635
636  #
637  # Add user commands to the menu.
638  #
639  if {[info exists cvsmenu]} {
640    foreach item [array names cvsmenu] {
641      .workdir.menubar.user add command -label $item \
642         -command "eval cvs_usercmd $cvsmenu($item) \[workdir_list_files\]"
643    }
644  }
645  if {[info exists usermenu]} {
646    .workdir.menubar.user add separator
647    foreach item [array names usermenu] {
648      .workdir.menubar.user add command -label $item \
649         -command "eval cvs_catchcmd $usermenu($item) \[workdir_list_files\]"
650    }
651  }
652  if {[info exists execmenu]} {
653    .workdir.menubar.user add separator
654    foreach item [array names execmenu] {
655      .workdir.menubar.user add command -label $item \
656         -command "eval cvs_execcmd $execmenu($item) \[workdir_list_files\]"
657    }
658  }
659  gen_log:log T "LEAVE"
660}
661
662proc workdir_list_files {} {
663  global cvscfg
664  global cvsglb
665
666  gen_log:log T "ENTER (cvsglb(current_selection) = $cvsglb(current_selection))"
667
668  for {set i 0} {$i < [llength $cvsglb(current_selection)]} {incr i} {
669    set item [lindex $cvsglb(current_selection) $i]
670    regsub {^no file } $item "" item
671    # regsub here causes file isfile to return 0.  You have to do it in each
672    # proc, just before the cvs command, after file tests have been done.
673    #regsub -all {\$} $item {\$} item
674    set cvsglb(current_selection) [lreplace $cvsglb(current_selection) $i $i $item]
675  }
676  gen_log:log T "LEAVE -- ($cvsglb(current_selection))"
677  return $cvsglb(current_selection)
678}
679
680proc workdir_edit_command {file} {
681  global cvscfg
682
683  gen_log:log T "ENTER ($file)"
684  if {[info exists cvscfg(editors)]} {
685    foreach {editor pattern} $cvscfg(editors) {
686      if {[string match $pattern $file]} {
687        return "$editor \"$file\""
688      }
689    }
690  }
691  return "$cvscfg(editor) \"$file\""
692}
693
694proc workdir_newdir {file} {
695  global cvscfg
696
697  gen_log:log T "ENTER ($file)"
698
699  file mkdir $file
700
701  if {$cvscfg(auto_status)} {
702    setup_dir
703  }
704  gen_log:log T "LEAVE"
705}
706
707proc workdir_edit_file {args} {
708  global cvscfg
709  global cwd
710
711  gen_log:log T "ENTER ($args)"
712
713  set filelist [join $args]
714  if {$filelist == ""} {
715    file_input_and_do "Edit File" workdir_edit_file
716    return
717  }
718
719  gen_log:log D "$filelist"
720  foreach file $filelist {
721    if {[file isdirectory $file]} {
722      change_dir "$file"
723    } else {
724      if {![file exists $file] || [file isfile $file]} {
725        # If the file doesn't exist it's tempting to touch the file and
726        # trigger a reread, but is an empty file of this type valid?
727        regsub -all {\$} $file {\$} file
728        set commandline [workdir_edit_command $file]
729        set editcmd [exec::new $commandline]
730      } else {
731        cvsfail "$file is not a plain file" .workdir
732      }
733    }
734  }
735  gen_log:log T "LEAVE"
736}
737
738proc workdir_view_file {args} {
739  global cvscfg
740  global cwd
741
742  gen_log:log T "ENTER ($args)"
743
744  set filelist [join $args]
745  if {$filelist == ""} {
746    cvsfail "Please select some files to view first!" .workdir
747    return
748  }
749
750  gen_log:log D "$filelist"
751  foreach file $filelist {
752    set filelog ""
753    if {[file isfile $file]} {
754      #regsub -all {\$} $file {\$} file
755      gen_log:log F "OPEN $file"
756      set f [open $file]
757      while { [eof $f] == 0 } {
758        append filelog [gets $f]
759        append filelog "\n"
760      }
761      view_output::new "$file" $filelog
762    } else {
763      cvsfail "$file is not a plain file" .workdir
764    }
765  }
766  gen_log:log T "LEAVE"
767}
768
769# Let the user mark directories they visit often
770proc add_bookmark { } {
771  global incvs inrcs insvn
772  global bookmarks
773
774  gen_log:log T "ENTER"
775  set dir [pwd]
776  regsub -all {\$} $dir {\$} dir
777
778  gen_log:log D "directory $dir"
779  foreach mark [array names bookmarks] {
780    gen_log:log D "  $mark \"$bookmarks($mark)\""
781  }
782
783  if {[info exists bookmarks($dir)]} {
784    .workdir.menubar.goto delete "$dir $bookmarks($dir)"
785  }
786  set rtype ""
787  if {$inrcs} {
788    set rtype "(RCS)"
789  } elseif {$incvs} {
790    set rtype "(CVS)"
791  } elseif {$insvn} {
792    set rtype "(SVN)"
793  }
794  set bookmarks($dir) $rtype
795  .workdir.menubar.goto add command -label "$dir $rtype" \
796     -command "change_dir \"$dir\""
797
798  gen_log:log T "LEAVE"
799}
800
801# A listbox to choose a bookmark to delete
802proc delete_bookmark_dialog { } {
803   global cvscfg
804   global cvsglb
805   global bookmarks
806
807   gen_log:log T "ENTER"
808   set maxlbl 0
809   foreach mark [array names bookmarks] {
810   gen_log:log D "  $mark $bookmarks($mark)"
811     set len [string length "$mark $bookmarks($mark)"]
812     if {$len > $maxlbl} {
813        set maxlbl $len
814     }
815   }
816
817   set wname .workdir.bookmarkedit
818   toplevel $wname
819   grab set $wname
820   wm title $wname "Delete Bookmarks"
821   listbox $wname.lbx -selectmode multiple \
822     -font $cvscfg(listboxfont) -width $maxlbl
823   pack $wname.lbx -ipadx 10 -ipady 10 -expand y -fill both
824   foreach mark [lsort [array names bookmarks]] {
825     $wname.lbx insert end "$mark $bookmarks($mark)"
826   }
827   frame $wname.buttons
828   pack $wname.buttons -side top -fill x
829   button $wname.delete -text "Delete" \
830     -command "delete_bookmark $wname"
831
832   button $wname.close -text "Done" \
833     -command "
834       grab release $wname
835       destroy $wname
836       exit_cleanup 0"
837   pack $wname.delete $wname.close -in $wname.buttons \
838     -side right -ipadx 2 -ipady 2 -padx 4 -pady 4 \
839     -expand y
840
841   gen_log:log T "LEAVE"
842}
843
844# Do the actual deletion of the bookmark
845proc delete_bookmark {w} {
846  global bookmarks
847
848  gen_log:log T "ENTER ($w)"
849  set items [$w.lbx curselection]
850  foreach item $items {
851    set itemstring [$w.lbx get $item]
852    #set dir [join [lrange $itemstring 0 end-1]]
853    regsub {\s+$} $itemstring {} dir
854    regsub {\s+\([A-Z][A-Z][A-Z]\)$} $dir {} dir
855    gen_log:log D "$item \"$itemstring\""
856    gen_log:log D "  directory \"$dir\""
857    unset bookmarks($dir)
858    $w.lbx delete $item
859    .workdir.menubar.goto delete $itemstring
860  }
861   gen_log:log T "LEAVE"
862}
863
864proc change_dir {new_dir} {
865  global cwd
866
867  gen_log:log T "ENTER ($new_dir)"
868  if {![file exists $new_dir]} {
869    set cwd [pwd]
870    cvsfail "Directory $new_dir doesn\'t exist!" .workdir
871    return
872  }
873  set cwd $new_dir
874  # Deleting the tree discards the saved scroll position
875  # so we start with yview 0 in a new directory
876  DirCanvas:deltree .workdir.main
877  setup_dir
878
879  gen_log:log T "LEAVE"
880}
881
882proc auto_setup_dir {command} {
883  global cvscfg
884
885  if {$cvscfg(auto_status)} {
886    $command\::wait
887    setup_dir
888  } else {
889    after 0 "$command\::wait; $command\::destroy"
890  }
891}
892
893proc setup_dir { } {
894  #
895  # Call this when entering a directory.  It puts all of the file names
896  # in the listbox, and reads the directory.
897  #
898  global cwd
899  global module_dir
900  global incvs
901  global insvn
902  global inrcs
903  global cvscfg
904  global current_tagname
905  global cvsglb
906
907  gen_log:log T "ENTER"
908
909  set savyview 0
910  if { ! [winfo exists .workdir.main] } {
911    workdir_setup
912    return
913  } else {
914    if {[winfo exists .workdir.main.filecol.list]} {
915      set savyview [lindex [.workdir.main.filecol.list yview] 0]
916    }
917    DirCanvas:deltree .workdir.main
918  }
919  gen_log:log D "YVIEW $savyview"
920
921  if {![file isdirectory $cwd]} {
922    gen_log:log D "$cwd is not a directory"
923    gen_log:log T "LEAVE -- $cwd is not a directory"
924    return
925  }
926
927  cd $cwd
928  gen_log:log F "CD [pwd]"
929
930  set module_dir ""
931  set current_tagname ""
932  ::picklist::used directory [pwd]
933
934  foreach {incvs insvn inrcs} [cvsroot_check [pwd]] { break }
935  gen_log:log D "incvs $incvs  inrcs $inrcs  insvn $insvn"
936
937  .workdir.top.bmodbrowse configure -image Modules
938  .workdir.top.lmodule configure -text "Path"
939  .workdir.top.ltagname configure -text "Tag"
940  # Start with the revision-control menus disabled
941  .workdir.menubar entryconfigure "CVS" -state normal
942  .workdir.menubar entryconfigure "SVN" -state normal
943  .workdir.menubar entryconfigure "RCS" -state normal
944  .workdir.menubar.reports entryconfigure 0 -state disabled
945  .workdir.menubar.reports entryconfigure 1 -state disabled
946  .workdir.menubar.reports entryconfigure 2 -state disabled
947  .workdir.menubar.reports entryconfigure 3 -state disabled
948  .workdir.menubar.reports entryconfigure 4 -state disabled
949  # Start with the revision-control buttons disabled and the
950  .workdir.bottom.buttons.dirfuncs.bcheckdir configure -state disabled
951  foreach widget [grid slaves .workdir.bottom.buttons.cvsfuncs ] {
952    $widget configure -state disabled
953  }
954  foreach widget [grid slaves .workdir.bottom.buttons.cvsfuncs ] {
955    $widget configure -state disabled
956  }
957  foreach widget [grid slaves .workdir.bottom.buttons.oddfuncs ] {
958    $widget configure -state disabled
959  }
960
961  # Now enable them depending on where we are
962  if {$inrcs} {
963    # Top
964    .workdir.top.lcvsroot configure -text "RCS *,v"
965    .workdir.top.tcvsroot configure -textvariable cvscfg(rcsdir)
966    # Buttons
967    .workdir.bottom.buttons.dirfuncs.bcheckdir configure -state normal \
968      -command { rcs_check }
969    .workdir.bottom.buttons.cvsfuncs.bdiff configure -state normal
970    .workdir.bottom.buttons.cvsfuncs.blogfile configure -state normal \
971      -command { rcs_branches [workdir_list_files] }
972    .workdir.bottom.buttons.cvsfuncs.bfilelog configure -state normal \
973      -command { rcs_log [workdir_list_files] }
974    .workdir.bottom.buttons.cvsfuncs.bupdate configure -state normal \
975      -command { rcs_checkout [workdir_list_files] }
976    .workdir.bottom.buttons.cvsfuncs.bcheckin configure -state normal \
977      -command { rcs_checkin [workdir_list_files] }
978    .workdir.bottom.buttons.cvsfuncs.brevert configure -state normal \
979      -command { rcs_revert [workdir_list_files] }
980    .workdir.bottom.buttons.oddfuncs.block configure -state normal \
981      -command { rcs_lock lock [workdir_list_files] }
982    .workdir.bottom.buttons.oddfuncs.bunlock configure -state normal \
983      -command { rcs_lock unlock [workdir_list_files] }
984    # Menus
985    .workdir.menubar entryconfigure "CVS" -state disabled
986    .workdir.menubar entryconfigure "SVN" -state disabled
987    .workdir.menubar entryconfigure "RCS" -state normal
988    # Reports Menu
989    # Check Directory (log & rdiff)
990    .workdir.menubar.reports entryconfigure 0 -state normal \
991       -command { rcs_check }
992    .workdir.menubar.reports entryconfigure 1 -state disabled
993    # Log (rlog)
994    .workdir.menubar.reports entryconfigure 2 -state normal \
995       -command { rcs_log [workdir_list_files] }
996    .workdir.menubar.reports entryconfigure 3 -state disabled
997    .workdir.menubar.reports entryconfigure 4 -state disabled
998  } elseif {$insvn} {
999    # Top
1000    .workdir.top.bmodbrowse configure -image Modules_svn \
1001      -command {modbrowse_run svn}
1002    .workdir.top.lmodule configure -text "Path"
1003    .workdir.top.ltagname configure -text "Tag"
1004    .workdir.top.lcvsroot configure -text "SVN URL"
1005    .workdir.top.tcvsroot configure -textvariable cvscfg(url)
1006    # Buttons
1007    .workdir.bottom.buttons.dirfuncs.bcheckdir configure -state normal \
1008      -command { svn_check [workdir_list_files] }
1009    .workdir.bottom.buttons.cvsfuncs.bjoin configure -state normal \
1010      -command { svn_branches . }
1011    .workdir.bottom.buttons.cvsfuncs.bdiff configure -state normal
1012    .workdir.bottom.buttons.cvsfuncs.blogfile configure -state normal \
1013      -command { svn_branches [workdir_list_files] }
1014    .workdir.bottom.buttons.cvsfuncs.bfilelog configure -state normal \
1015      -command { svn_log [workdir_list_files] }
1016    .workdir.bottom.buttons.cvsfuncs.bannotate configure -state normal \
1017      -command { svn_annotate BASE [workdir_list_files] }
1018    .workdir.bottom.buttons.cvsfuncs.bconflict configure -state normal \
1019      -command { foreach f [workdir_list_files] {svn_merge_conflict \"$f\"} }
1020    .workdir.bottom.buttons.cvsfuncs.badd_files configure -state normal
1021    .workdir.bottom.buttons.cvsfuncs.bremove configure -state normal
1022    .workdir.bottom.buttons.cvsfuncs.bupdate configure -state normal \
1023      -command { svn_update [workdir_list_files] }
1024    .workdir.bottom.buttons.cvsfuncs.bupdateopts configure -state normal \
1025     -command { svn_update_options }
1026    .workdir.bottom.buttons.cvsfuncs.bcheckin configure -state normal \
1027      -command svn_commit_dialog
1028    .workdir.bottom.buttons.cvsfuncs.brevert configure -state normal \
1029      -command { svn_revert [workdir_list_files] }
1030    .workdir.bottom.buttons.cvsfuncs.btag configure -state normal
1031    .workdir.bottom.buttons.cvsfuncs.bbranchtag configure -state normal
1032    .workdir.bottom.buttons.oddfuncs.block configure -state normal \
1033      -command { svn_lock lock [workdir_list_files] }
1034    .workdir.bottom.buttons.oddfuncs.bunlock configure -state normal \
1035      -command { svn_lock unlock [workdir_list_files] }
1036    # Menus
1037    .workdir.menubar entryconfigure "CVS" -state disabled
1038    .workdir.menubar entryconfigure "SVN" -state normal
1039    .workdir.menubar entryconfigure "RCS" -state disabled
1040    # Reports Menu
1041    # Check Directory (svn status)
1042    .workdir.menubar.reports entryconfigure 0 -state normal \
1043       -command { svn_check {} }
1044    # Status (svn status <filelist>)
1045    .workdir.menubar.reports entryconfigure 1 -state normal \
1046       -command { svn_check [workdir_list_files] }
1047    # Log (svn log)
1048    .workdir.menubar.reports entryconfigure 2 -state normal \
1049       -command { svn_log [workdir_list_files] }
1050    # Annotate/Blame (svn blame)
1051    .workdir.menubar.reports entryconfigure 3 -state normal \
1052       -command { svn_annotate BASE [workdir_list_files] }
1053    # Info (svn info)
1054    .workdir.menubar.reports entryconfigure 4 -state normal \
1055       -command { svn_info [workdir_list_files] }
1056  } elseif {$incvs} {
1057    # Top
1058    .workdir.top.bmodbrowse configure -image Modules_cvs \
1059      -command {modbrowse_run cvs}
1060    .workdir.top.lmodule configure -text "Module"
1061    .workdir.top.ltagname configure -text "Tag"
1062    .workdir.top.lcvsroot configure -text "CVSROOT"
1063    .workdir.top.tcvsroot configure -textvariable cvscfg(cvsroot)
1064    # Buttons
1065    .workdir.bottom.buttons.dirfuncs.bcheckdir configure -state normal \
1066      -command { cvs_check [workdir_list_files] }
1067    .workdir.bottom.buttons.cvsfuncs.bjoin configure -state normal \
1068      -command cvs_joincanvas
1069    .workdir.bottom.buttons.cvsfuncs.bdiff configure -state normal
1070    .workdir.bottom.buttons.cvsfuncs.bconflict configure -state normal \
1071      -command { cvs_merge_conflict [workdir_list_files] }
1072    .workdir.bottom.buttons.cvsfuncs.bfilelog configure -state normal \
1073      -command { cvs_log [workdir_list_files] }
1074    .workdir.bottom.buttons.cvsfuncs.bannotate configure -state normal \
1075      -command { cvs_annotate $current_tagname [workdir_list_files] }
1076    .workdir.bottom.buttons.cvsfuncs.badd_files configure -state normal
1077    .workdir.bottom.buttons.cvsfuncs.bremove configure -state normal
1078    .workdir.bottom.buttons.cvsfuncs.bupdate configure -state normal \
1079       -command { \
1080       cvs_update {BASE} {Normal} {Remove} {recurse} {prune} {No} { } [workdir_list_files] }
1081    .workdir.bottom.buttons.cvsfuncs.bupdateopts configure -state normal \
1082     -command { cvs_update_options }
1083    .workdir.bottom.buttons.cvsfuncs.bcheckin configure -state normal \
1084      -command cvs_commit_dialog
1085    .workdir.bottom.buttons.cvsfuncs.brevert configure -state normal \
1086      -command {cvs_revert [workdir_list_files] }
1087    .workdir.bottom.buttons.cvsfuncs.btag configure -state normal
1088    .workdir.bottom.buttons.cvsfuncs.bbranchtag configure -state normal
1089    .workdir.bottom.buttons.cvsfuncs.blogfile configure -state normal \
1090      -command { cvs_branches [workdir_list_files] }
1091    .workdir.bottom.buttons.cvsfuncs.bfilelog configure -state normal \
1092      -command { cvs_log [workdir_list_files] }
1093    if {$cvscfg(econtrol)} {
1094      .workdir.bottom.buttons.oddfuncs.bcvsedit_files configure -state normal
1095      .workdir.bottom.buttons.oddfuncs.bunedit_files configure -state normal
1096    }
1097    if {$cvscfg(cvslock)} {
1098      .workdir.bottom.buttons.oddfuncs.block configure -state normal \
1099        -command { cvs_lock lock [workdir_list_files] }
1100      .workdir.bottom.buttons.oddfuncs.bunlock configure -state normal \
1101        -command { cvs_lock unlock [workdir_list_files] }
1102    }
1103    # Menus
1104    .workdir.menubar entryconfigure "CVS" -state normal
1105    .workdir.menubar entryconfigure "SVN" -state disabled
1106    .workdir.menubar entryconfigure "RCS" -state disabled
1107    # Reports Menu
1108    # Check Directory (cvs -n -q update)
1109    .workdir.menubar.reports entryconfigure 0 -state normal \
1110       -command { cvs_check {} }
1111    # Status (cvs -Q status)
1112    .workdir.menubar.reports entryconfigure 1 -state normal \
1113       -command { cvs_status [workdir_list_files] }
1114    # Log (cvs log)
1115    .workdir.menubar.reports entryconfigure 2 -state normal \
1116       -command { cvs_log [workdir_list_files] }
1117    # Annotate/Blame (cvs annotate)
1118    .workdir.menubar.reports entryconfigure 3 -state normal \
1119       -command { cvs_annotate $current_tagname [workdir_list_files] }
1120    .workdir.menubar.reports entryconfigure 4 -state disabled
1121  }
1122
1123  DirCanvas:create .workdir.main
1124  pack .workdir.main.pw -side bottom -fill both -expand yes
1125
1126  set cvsglb(current_selection) {}
1127
1128  set cvscfg(ignore_file_filter) $cvsglb(default_ignore_filter)
1129
1130  if { [ file exists ".cvsignore" ] } {
1131    set fileId [ open ".cvsignore" "r" ]
1132    while { [ eof $fileId ] == 0 } {
1133      gets $fileId line
1134      append cvscfg(ignore_file_filter) " $line"
1135    }
1136    close $fileId
1137  } else {
1138    if {$insvn} {
1139      # Have to do eval exec because we need the error output
1140      set command "svn propget svn:ignore"
1141      gen_log:log C "$command"
1142      set ret [catch {eval "exec $command"} output]
1143      if {$ret} {
1144        cvsfail $output
1145        return
1146      }
1147      foreach infoline [split $output "\n"] {
1148        append cvscfg(ignore_file_filter) " $infoline"
1149      }
1150    }
1151  }
1152
1153  set filelist [ getFiles ]
1154  directory_list $filelist
1155  # Update, otherwise it won't be mapped before we restore the scroll position
1156  update
1157  DirCanvas:yview_windows .workdir.main $savyview
1158
1159  gen_log:log T "LEAVE"
1160}
1161
1162proc directory_list { filenames } {
1163  global module_dir
1164  global incvs
1165  global insvn
1166  global inrcs
1167  global cvs
1168  global cwd
1169  global cvscfg
1170  global cvsglb
1171  global cmd
1172  global Filelist
1173
1174  gen_log:log T "ENTER ($filenames)"
1175
1176  if {[info exists Filelist]} {
1177    unset Filelist
1178  }
1179
1180  busy_start .workdir.main
1181
1182  #gen_log:log F "processing files in the local directory"
1183  set cwd [pwd]
1184  set my_cwd $cwd
1185
1186  # If we have commands running they were for a different directory
1187  # and won't be needed now. (i.e. this is a recursive invocation
1188  # triggered by a button click)
1189  if {[info exists cmd(cvs_status)]} {
1190    catch {$cmd(cvs_status)\::abort}
1191    catch {unset cmd(cvs_status)}
1192  }
1193  if {[info exists cmd(cvs_editors)]} {
1194    catch {$cmd(cvs_editors)\::abort}
1195    catch {unset cmd(cvs_editors)}
1196  }
1197
1198  # Select from those files only the ones we want (e.g., no CVS dirs)
1199  foreach i $filenames {
1200    if { $i == "."  || $i == ".."} {
1201      gen_log:log D "SKIPPING $i"
1202      continue
1203    }
1204    if {[file isdirectory $i]} {
1205      if {[isCmDirectory $i]} {
1206        # Read the bookkeeping files but don't list the directory
1207        if {$i == "CVS" || $i == ".svn" || $i == "RCS"} {
1208          continue
1209        }
1210      }
1211      if {[file exists [file join $i "CVS"]]} {
1212        set Filelist($i:status) "<directory:CVS>"
1213      } elseif {[file exists [file join $i ".svn"]]} {
1214        set Filelist($i:status) "<directory:SVN>"
1215      } elseif {[file exists [file join $i "RCS"]]} {
1216        set Filelist($i:status) "<directory:RCS>"
1217      } else {
1218        set Filelist($i:status) "<directory>"
1219      }
1220    } else {
1221      if {$incvs} {
1222        set Filelist($i:status) "Not managed by CVS"
1223      } else {
1224        set Filelist($i:status) "<file>"
1225      }
1226    }
1227    set Filelist($i:wrev) ""
1228    set Filelist($i:stickytag) ""
1229    set Filelist($i:option) ""
1230    # Prepending ./ to the filename prevents tilde expansion
1231    catch {set Filelist($i:date) \
1232       [clock format [file mtime ./$i] -format $cvscfg(dateformat)]}
1233  }
1234
1235  gen_log:log D "incvs=$incvs insvn=$insvn inrcs=$inrcs"
1236  if {$incvs} {
1237    DirCanvas:headtext .workdir.main "editors"
1238    cvs_workdir_status
1239  }
1240
1241  if {$inrcs} {
1242    DirCanvas:headtext .workdir.main "locked by"
1243    rcs_workdir_status
1244  }
1245
1246  if {$insvn} {
1247    DirCanvas:headtext .workdir.main "author"
1248    svn_workdir_status
1249  }
1250
1251  gen_log:log D "Sending all files to the canvas"
1252  foreach i [array names Filelist *:status] {
1253    regsub {:status$} $i "" j
1254    # If it's locally removed or missing, it may not have
1255    # gotten a date especially on a remote client.
1256    if {! [info exists Filelist($j:date)]} {
1257      set Filelist($j:date) ""
1258    }
1259    DirCanvas:newitem .workdir.main "$j"
1260  }
1261
1262  busy_done .workdir.main
1263
1264  gen_log:log T "LEAVE"
1265}
1266
1267proc workdir_cleanup {} {
1268  global cvscfg
1269
1270  gen_log:log T "ENTER"
1271  set rmitem ""
1272  set list [ split $cvscfg(clean_these) " " ]
1273  foreach pattern $list {
1274    gen_log:log D "pattern $pattern"
1275    if { $pattern != "" } {
1276      set items [lsort [glob -nocomplain $pattern]]
1277      gen_log:log D "$items"
1278      if {[llength $items] != 0} {
1279        append rmitem " [concat $items]"
1280      }
1281    }
1282  }
1283
1284  if {$rmitem != ""} {
1285    if { [ are_you_sure "You are about to delete:\n" $rmitem] == 1 } {
1286      gen_log:log F "DELETE $rmitem"
1287      eval file delete -force -- $rmitem
1288    }
1289  } else {
1290    gen_log:log F "No files to delete"
1291    cvsok "Nothing matched $cvscfg(clean_these)" .workdir
1292    return
1293  }
1294  setup_dir
1295  gen_log:log T "LEAVE"
1296}
1297
1298proc workdir_delete_file {args} {
1299  global cvscfg
1300
1301  gen_log:log T "ENTER ($args)"
1302
1303  set filelist [join $args]
1304  if {$filelist == ""} {
1305    cvsfail "Please select some files to delete first!" .workdir
1306    return
1307  }
1308
1309  if { [ are_you_sure "This will delete these files from your local, working directory:\n" $filelist ] == 1 } {
1310    gen_log:log F "DELETE $filelist"
1311    eval file delete -force -- $filelist
1312    setup_dir
1313  }
1314  gen_log:log T "LEAVE"
1315}
1316
1317proc are_you_sure {mess args} {
1318#
1319# General posting message
1320#
1321  global cvscfg
1322
1323  gen_log:log T "ENTER ($mess $args)"
1324
1325  set filelist [join $args]
1326  if {$cvscfg(confirm_prompt)} {
1327    append mess "\n"
1328    set indent "      "
1329
1330    foreach item $filelist {
1331      if { $item != {} } {
1332        append mess " $indent"
1333        append mess " $item\n"
1334      }
1335    }
1336    append mess "\nAre you sure?"
1337    if {[cvsconfirm $mess .workdir] != "ok"} {
1338      gen_log:log T "LEAVE 0"
1339      return 0
1340    }
1341  }
1342  gen_log:log T "LEAVE 1"
1343  return 1
1344}
1345
1346proc workdir_print_file {args} {
1347  global cvscfg
1348
1349  gen_log:log T "ENTER ($args)"
1350
1351  set filelist [join $args]
1352  if {$filelist == ""} {
1353    cvsfail "Please select some files to print first!" .workdir
1354    return
1355  }
1356
1357  set mess "This will print these files:\n\n"
1358  foreach file $filelist {
1359    append mess "   $file\n"
1360  }
1361  append mess "\nUsing $cvscfg(print_cmd)\n"
1362  append mess "\nAre you sure?"
1363  if {[cvsconfirm $mess .workdir] == "ok"} {
1364    set final_result ""
1365    foreach file $filelist {
1366      set commandline [concat $cvscfg(print_cmd) \"$file\"]
1367      exec::new $commandline
1368    }
1369  }
1370  gen_log:log T "LEAVE"
1371}
1372
1373proc cvsroot_check { dir } {
1374  global cvscfg
1375  global cvsglb
1376
1377  gen_log:log T "ENTER ($dir)"
1378
1379  foreach {incvs insvn inrcs} {0 0 0} {break}
1380
1381  if {[file isfile [file join $dir CVS Root]]} {
1382    set incvs [ read_cvs_dir [file join $dir CVS] ]
1383  } elseif {! [catch {eval "exec svn info"}]} {
1384    set insvn [ read_svn_dir $dir ]
1385  } else {
1386    set rcsdir [file join $dir RCS]
1387    if {[file exists $rcsdir]} {
1388      set cvscfg(rcsdir) $rcsdir
1389      set inrcs 1
1390    } elseif {[llength [glob -nocomplain -dir $dir *,v]] > 0} {
1391      set inrcs 1
1392      set cvscfg(rcsdir) $dir
1393    } else {
1394      set cvscfg(rcsdir) ""
1395    }
1396  }
1397
1398  if {$inrcs} {
1399    # Make sure we have rcs, and bag this (silently) if we don't
1400    set command "rcs -V"
1401    gen_log:log C "$command"
1402    set ret [catch {eval "exec $command"} raw_rcs_log]
1403    if {$ret} {
1404       gen_log:log D "$raw_rcs_log"
1405       if [string match {*Unknown option:*} $raw_rcs_log] {
1406         # An old version of RCS, but it's here
1407         set inrcs 1
1408       } else {
1409         set inrcs 0
1410       }
1411    }
1412  }
1413
1414  gen_log:log T "LEAVE ($incvs $insvn $inrcs)"
1415  return [list $incvs $insvn $inrcs]
1416}
1417
1418proc isCmDirectory { file } {
1419  #gen_log:log T "ENTER ($file)"
1420  switch -- $file  {
1421    "CVS"  -
1422    "RCS"  -
1423    ".svn"  -
1424    "SCCS" { set value 1 }
1425    default { set value 0 }
1426  }
1427  #gen_log:log T "LEAVE ($value)"
1428  return $value
1429}
1430
1431# Get the files in the current working directory.  Use the file_filter
1432# values Add hidden files if desired by the user.  Sort them to match
1433# the ordering that will be returned by cvs commands (this matches the
1434# default ls ordering.).
1435proc getFiles { } {
1436  global cvscfg
1437  global cvsglb
1438
1439  gen_log:log T "ENTER"
1440  set filelist ""
1441
1442  # make sure the file filter is at least set to "*".
1443  if { $cvscfg(file_filter) == "" } {
1444    set cvscfg(file_filter) "* .svn"
1445  }
1446
1447  # get the initial file list, including hidden if requested
1448  if {$cvscfg(allfiles)} {
1449    # get hidden as well
1450    foreach item $cvscfg(file_filter) {
1451      set filelist [ concat [ glob -nocomplain .$item $item ] $filelist ]
1452    }
1453  } else {
1454    foreach item $cvscfg(file_filter) {
1455      set filelist [ concat [ glob -nocomplain $item ] $filelist ]
1456    }
1457  }
1458  #gen_log:log D "filelist ($filelist)"
1459
1460  # ignore files if requested
1461  if { $cvscfg(ignore_file_filter) != "" } {
1462    foreach item $cvscfg(ignore_file_filter) {
1463      # for each pattern
1464      if { $item != "*" } {
1465        # if not "*"
1466        while { [set idx [lsearch $filelist $item]] != -1 } {
1467          # for each occurence, delete
1468          catch { set filelist [ lreplace $filelist $idx $idx ] }
1469        }
1470      }
1471    }
1472  }
1473
1474  # make sure "." is always in the list for 'cd' purposes
1475  if { ( [ lsearch -exact $filelist "." ] == -1 ) } {
1476    set filelist [ concat "." $filelist ]
1477  }
1478
1479  # make sure ".." is always in the list for 'cd' purposes
1480  if { ( [ lsearch -exact $filelist ".." ] == -1 ) } {
1481    set filelist [ concat ".." $filelist ]
1482  }
1483
1484  # sort it
1485  set filelist [ lsort $filelist ]
1486
1487  # if this directory is under CVS and CVS is not in the list, add it. Its
1488  # presence is needed for later processing
1489  if { ( [ file exists "CVS" ] ) &&
1490       ( [ lsearch -exact $filelist "CVS" ] == -1 ) } {
1491    #puts "********* added CVS"
1492    catch { set filelist [ concat "CVS" $filelist ] }
1493  }
1494
1495  set cvscfg(ignore_file_filter) $cvsglb(default_ignore_filter)
1496  gen_log:log T "return ($filelist)"
1497  return $filelist
1498}
1499
1500proc log_toggle { } {
1501  global cvscfg
1502
1503  if {$cvscfg(logging)} {
1504    gen_log:init
1505  } else {
1506    gen_log:quit
1507  }
1508}
1509
1510proc exit_cleanup { force } {
1511  global cvscfg
1512
1513  # Count the number of toplevels that are currently interacting
1514  # with the user (i.e. exist and are not withdrawn)
1515  set wlist {}
1516  foreach w [winfo children .] {
1517    if {[wm state $w] != {withdrawn}} {
1518      lappend wlist $w
1519    }
1520  }
1521
1522  if {$force == 0 && [llength $wlist] != 0 \
1523    && $wlist != {.trace} && $wlist != {.bgerrorTrace}} {
1524      return
1525  }
1526
1527  # If toplevel windows exist ask them to close gracefully if possible
1528  foreach w $wlist {
1529    # Except .trace!
1530    if {$w != {.trace}} {
1531      catch {$w.close invoke}
1532    } else {
1533      # Invoking trace's close turns off logging. We don't want that,
1534      # but we do want to save its geometry.
1535      if {[winfo exists .trace]} {
1536        set cvscfg(tracgeom) [wm geometry .trace]
1537      }
1538    }
1539  }
1540
1541  save_options
1542  set pid [pid]
1543  gen_log:log F "DELETE $cvscfg(tmpdir)/cvstmpdir.$pid"
1544  catch {file delete -force [file join $cvscfg(tmpdir) cvstmpdir.$pid]}
1545  exit
1546}
1547
1548proc save_options { } {
1549#
1550# Save the options which are configurable from the GUI
1551#
1552  global cvscfg
1553  global logcfg
1554  global bookmarks
1555
1556  gen_log:log T "ENTER"
1557
1558  # There are two kinds of options we can set
1559  set BOOLopts { allfiles auto_status confirm_prompt \
1560                 showstatcol showdatecol showeditcol auto_tag \
1561                 status_filter recurse logging blame_linenums}
1562  set STRGopts { file_filter ignore_file_filter clean_these \
1563                 printer rdetail ldetail log_classes lastdir sortcol \
1564                 workgeom modgeom loggeom tracgeom editor editorargs}
1565
1566  # Plus the logcanvas options
1567  set LOGopts [concat [array names logcfg show_*] scale]
1568
1569  # set this to current directory, so we'll add it to the menu next time
1570  if ([catch pwd]) {
1571    return
1572  }
1573  set cvscfg(lastdir) [pwd]
1574
1575  if {[info exists cvscfg(editorargs)] } {
1576    # editorargs is no longer necessary
1577    if {$cvscfg(editorargs) != ""} {
1578      set cvscfg(editor) [concat $cvscfg(editor) $cvscfg(editorargs)]
1579    }
1580    unset cvscfg(editorargs)
1581  }
1582
1583  # Save the list so we can keep track of what we've done
1584  set BOOLset $BOOLopts
1585  set STRGset $STRGopts
1586  set LOGset $LOGopts
1587
1588  set optfile [file join $cvscfg(home) .tkcvs]
1589  set bakfile [file join $cvscfg(home) .tkcvs.bak]
1590  # Save the old .tkcvs file
1591  gen_log:log F "MOVE $optfile $bakfile"
1592  catch {file rename -force $optfile $bakfile}
1593
1594  gen_log:log F "OPEN $optfile"
1595  if {[catch {set fo [open $optfile w]}]} {
1596    cvsfail "Cannot open $optfile for writing" .workdir
1597    return
1598  }
1599  gen_log:log F "OPEN $bakfile"
1600
1601  if {! [catch {set fi [open $bakfile r]}]} {
1602    while { [eof $fi] == 0 } {
1603      gets $fi line
1604      set match 0
1605      if {[regexp {^#} $line]} {
1606        # Don't try to scan comments.
1607        #gen_log:log D "PASSING \"$line\""
1608        puts $fo "$line"
1609        continue
1610      } elseif {[string match "*set *bookmarks*" $line]} {
1611        # Discard old bookmarks
1612        continue
1613      } else {
1614        foreach opt $BOOLopts {
1615          if {! [info exists cvscfg($opt)]} { continue }
1616          if {[string match "*set *cvscfg($opt)*" $line]} {
1617            # Print it and remove it from the list
1618            gen_log:log D "REPLACING $line  w/ set cvscfg($opt) $cvscfg($opt)"
1619            puts $fo "set cvscfg($opt) $cvscfg($opt)"
1620            set idx [lsearch $BOOLset $opt]
1621            set BOOLset [lreplace $BOOLset $idx $idx]
1622            set match 1
1623            break
1624          }
1625        }
1626        if {[string match "*set *cvscfg(checkrecursive)*" $line]} {
1627          # This helps us recover from a problem left behind by tkcvs 7.2
1628          continue
1629        }
1630        foreach opt $STRGopts {
1631          if {! [info exists cvscfg($opt)]} { continue }
1632          if {[string match "*set *cvscfg($opt)*" $line]} {
1633            # Print it and remove it from the list
1634            gen_log:log D "REPLACING $line  w/ set cvscfg($opt) $cvscfg($opt)"
1635            puts $fo "set cvscfg($opt) \"$cvscfg($opt)\""
1636            set idx [lsearch $STRGset $opt]
1637            set STRGset [lreplace $STRGset $idx $idx]
1638            set match 1
1639            break
1640          }
1641        }
1642        if {[string match "*set *cvscfg(editorargs)*" $line]} {
1643          # editorargs is no longer necessary
1644          continue
1645        }
1646        foreach opt $LOGopts {
1647          if {! [info exists logcfg($opt)]} { continue }
1648          if {[string match "*set *logcfg($opt)*" $line]} {
1649            # Print it and remove it from the list
1650            gen_log:log D "REPLACING \"$line\"  w/ set logcfg($opt) \"$logcfg($opt)\""
1651            puts $fo "set logcfg($opt) \"$logcfg($opt)\""
1652            set idx [lsearch $LOGset $opt]
1653            set LOGset [lreplace $LOGset $idx $idx]
1654            set match 1
1655            break
1656          }
1657        }
1658        if {$match == 0} {
1659          # We didn't do a replacement
1660          gen_log:log D "PASSING \"$line\""
1661          # If we don't check this, we get an extra blank line every time
1662          # we save the file.  Messy.
1663          if {[eof $fi] == 1} { break }
1664          puts $fo "$line"
1665        }
1666      }
1667    }
1668    foreach mark [lsort [array names bookmarks]] {
1669      gen_log:log D "Adding bookmark \"$mark\""
1670      puts $fo "set \"bookmarks($mark)\" \"$bookmarks($mark)\""
1671    }
1672
1673    close $fi
1674  }
1675
1676  # Print what's left over
1677  foreach opt $BOOLset {
1678    if {! [info exists cvscfg($opt)]} { continue }
1679    gen_log:log D "ADDING cvscfg($opt) $cvscfg($opt)"
1680    puts $fo "set cvscfg($opt) $cvscfg($opt)"
1681  }
1682
1683  foreach opt $STRGset {
1684    if {! [info exists cvscfg($opt)]} { continue }
1685    gen_log:log D "ADDING cvscfg($opt) \"$cvscfg($opt)\""
1686    puts $fo "set cvscfg($opt) \"$cvscfg($opt)\""
1687  }
1688
1689  foreach opt $LOGset {
1690    if {! [info exists logcfg($opt)]} { continue }
1691    gen_log:log D "ADDING logcfg($opt) \"$logcfg($opt)\""
1692    puts $fo "set logcfg($opt) \"$logcfg($opt)\""
1693  }
1694
1695  close $fo
1696  ::picklist::save
1697  gen_log:log T "LEAVE"
1698}
1699
1700