3 # Choose directory dialog implementation for Unix/Mac.
5 # Copyright (c) 1998-2000 by Scriptics Corporation.
10 # Make sure the tk::dialog namespace, in which all dialogs should live, exists
11 namespace eval ::tk::dialog {}
12 namespace eval ::tk::dialog::file {}
14 # Make the chooseDir namespace inside the dialog namespace
15 namespace eval ::tk::dialog::file::chooseDir {
18 # ::tk::dialog::file::tkChooseDirectory --
20 # Implements the TK directory selection dialog.
23 # args Options parsed by the procedure.
25 proc ::tk::dialog::file::chooseDir::tkChooseDirectory {args} {
27 set dataName __tk_choosedir
28 upvar ::tk::dialog::file::$dataName data
29 ::tk::dialog::file::chooseDir::Config $dataName $args
31 if {[string equal $data(-parent) .]} {
34 set w $data(-parent).$dataName
37 # (re)create the dialog box if necessary
39 if {![winfo exists $w]} {
40 ::tk::dialog::file::Create $w TkChooseDir
41 } elseif {[string compare [winfo class $w] TkChooseDir]} {
43 ::tk::dialog::file::Create $w TkChooseDir
45 set data(dirMenuBtn) $w.f1.menu
46 set data(dirMenu) $w.f1.menu.menu
47 set data(upBtn) $w.f1.up
48 set data(icons) $w.icons
49 set data(ent) $w.f2.ent
50 set data(okBtn) $w.f2.ok
51 set data(cancelBtn) $w.f3.cancel
53 wm transient $w $data(-parent)
55 trace variable data(selectPath) w [list ::tk::dialog::file::SetPath $w]
56 $data(dirMenuBtn) configure \
57 -textvariable ::tk::dialog::file::${dataName}(selectPath)
60 set data(previousEntryText) ""
61 ::tk::dialog::file::UpdateWhenIdle $w
63 # Withdraw the window, then update all the geometry information
64 # so we know how big it wants to be, then center the window in the
65 # display and de-iconify it.
67 ::tk::PlaceWindow $w widget $data(-parent)
68 wm title $w $data(-title)
70 # Set a grab and claim the focus too.
72 ::tk::SetFocusGrab $w $data(ent)
73 $data(ent) delete 0 end
74 $data(ent) insert 0 $data(selectPath)
75 $data(ent) selection range 0 end
76 $data(ent) icursor end
78 # Wait for the user to respond, then restore the focus and
79 # return the index of the selected button. Restore the focus
80 # before deleting the window, since otherwise the window manager
81 # may take the focus away so we can't redirect it. Finally,
82 # restore any grab that was in effect.
84 tkwait variable tkPriv(selectFilePath)
86 ::tk::RestoreFocusGrab $w $data(ent) withdraw
88 # Cleanup traces on selectPath variable
91 foreach trace [trace vinfo data(selectPath)] {
92 trace vdelete data(selectPath) [lindex $trace 0] [lindex $trace 1]
94 $data(dirMenuBtn) configure -textvariable {}
96 # Return value to user
99 return $tkPriv(selectFilePath)
102 # ::tk::dialog::file::chooseDir::Config --
104 # Configures the Tk choosedir dialog according to the argument list
106 proc ::tk::dialog::file::chooseDir::Config {dataName argList} {
107 upvar ::tk::dialog::file::$dataName data
109 # 0: Delete all variable that were set on data(selectPath) the
110 # last time the file dialog is used. The traces may cause troubles
111 # if the dialog is now used with a different -parent option.
113 foreach trace [trace vinfo data(selectPath)] {
114 trace vdelete data(selectPath) [lindex $trace 0] [lindex $trace 1]
117 # 1: the configuration specs
121 {-initialdir "" "" ""}
126 # 2: default values depending on the type of the dialog
128 if {![info exists data(selectPath)]} {
129 # first time the dialog has been popped up
130 set data(selectPath) [pwd]
133 # 3: parse the arguments
135 tclParseConfigSpec ::tk::dialog::file::$dataName $specs "" $argList
137 if {$data(-title) == ""} {
138 set data(-title) "Choose Directory"
141 # 4: set the default directory and selection according to the -initial
144 if {$data(-initialdir) != ""} {
145 # Ensure that initialdir is an absolute path name.
146 if {[file isdirectory $data(-initialdir)]} {
148 cd $data(-initialdir)
149 set data(selectPath) [pwd]
152 set data(selectPath) [pwd]
156 if {![winfo exists $data(-parent)]} {
157 error "bad window path name \"$data(-parent)\""
161 # Gets called when user presses Return in the "Selection" entry or presses OK.
163 proc ::tk::dialog::file::chooseDir::OkCmd {w} {
164 upvar ::tk::dialog::file::[winfo name $w] data
166 # This is the brains behind selecting non-existant directories. Here's
168 # 1. If the icon list has a selection, join it with the current dir,
169 # and return that value.
170 # 1a. If the icon list does not have a selection ...
171 # 2. If the entry is empty, do nothing.
172 # 3. If the entry contains an invalid directory, then...
173 # 3a. If the value is the same as last time through here, end dialog.
174 # 3b. If the value is different than last time, save it and return.
175 # 4. If entry contains a valid directory, then...
176 # 4a. If the value is the same as the current directory, end dialog.
177 # 4b. If the value is different from the current directory, change to
180 set iconText [tkIconList_Get $data(icons)]
181 if { ![string equal $iconText ""] } {
182 set iconText [file join $data(selectPath) $iconText]
183 ::tk::dialog::file::chooseDir::Done $w $iconText
185 set text [$data(ent) get]
186 if { [string equal $text ""] } {
189 set text [eval file join [file split [string trim $text]]]
190 if { ![file exists $text] || ![file isdirectory $text] } {
191 # Entry contains an invalid directory. If it's the same as the
192 # last time they came through here, reset the saved value and end
193 # the dialog. Otherwise, save the value (so we can do this test
195 if { [string equal $text $data(previousEntryText)] } {
196 set data(previousEntryText) ""
197 ::tk::dialog::file::chooseDir::Done $w $text
199 set data(previousEntryText) $text
202 # Entry contains a valid directory. If it is the same as the
203 # current directory, end the dialog. Otherwise, change to that
205 if { [string equal $text $data(selectPath)] } {
206 ::tk::dialog::file::chooseDir::Done $w $text
208 set data(selectPath) $text
215 proc ::tk::dialog::file::chooseDir::DblClick {w} {
216 upvar ::tk::dialog::file::[winfo name $w] data
217 set text [tkIconList_Get $data(icons)]
218 if {[string compare $text ""]} {
219 set file $data(selectPath)
220 if {[file isdirectory $file]} {
221 ::tk::dialog::file::ListInvoke $w $text
227 # Gets called when user browses the IconList widget (dragging mouse, arrow
230 proc ::tk::dialog::file::chooseDir::ListBrowse {w text} {
231 upvar ::tk::dialog::file::[winfo name $w] data
233 if {[string equal $text ""]} {
237 set file [::tk::dialog::file::JoinFile $data(selectPath) $text]
238 $data(ent) delete 0 end
239 $data(ent) insert 0 $file
242 # ::tk::dialog::file::chooseDir::Done --
244 # Gets called when user has input a valid filename. Pops up a
245 # dialog box to confirm selection when necessary. Sets the
246 # tkPriv(selectFilePath) variable, which will break the "tkwait"
247 # loop in tk_chooseDirectory and return the selected filename to the
248 # script that calls tk_getOpenFile or tk_getSaveFile
250 proc ::tk::dialog::file::chooseDir::Done {w {selectFilePath ""}} {
251 upvar ::tk::dialog::file::[winfo name $w] data
254 if {[string equal $selectFilePath ""]} {
255 set selectFilePath $data(selectPath)
257 if { $data(-mustexist) } {
258 if { ![file exists $selectFilePath] || \
259 ![file isdir $selectFilePath] } {
263 set tkPriv(selectFilePath) $selectFilePath