1 """File selection dialog classes.
12 from Dialog
import Dialog
23 """Standard file selection dialog -- no checks on selected file.
27 d = FileDialog(master)
28 fname = d.go(dir_or_file, pattern, default, key)
29 if fname is None: ...canceled...
32 All arguments to go() are optional.
34 The 'key' argument specifies a key in the global dictionary
35 'dialogstates', which keeps track of the values for the directory
36 and pattern arguments, overriding the values passed in (it does
37 not keep track of the default argument!). If no key is specified,
38 the dialog keeps no memory of previous state. Note that memory is
39 kept even when the dialog is canceled. (All this emulates the
40 behavior of the Macintosh file selection dialogs.)
44 title
= "File Selection Dialog"
46 def __init__(self
, master
, title
=None):
47 if title
is None: title
= self
.title
51 self
.top
= Toplevel(master
)
53 self
.top
.iconname(title
)
55 self
.botframe
= Frame(self
.top
)
56 self
.botframe
.pack(side
=BOTTOM
, fill
=X
)
58 self
.selection
= Entry(self
.top
)
59 self
.selection
.pack(side
=BOTTOM
, fill
=X
)
60 self
.selection
.bind('<Return>', self
.ok_event
)
62 self
.filter = Entry(self
.top
)
63 self
.filter.pack(side
=TOP
, fill
=X
)
64 self
.filter.bind('<Return>', self
.filter_command
)
66 self
.midframe
= Frame(self
.top
)
67 self
.midframe
.pack(expand
=YES
, fill
=BOTH
)
69 self
.filesbar
= Scrollbar(self
.midframe
)
70 self
.filesbar
.pack(side
=RIGHT
, fill
=Y
)
71 self
.files
= Listbox(self
.midframe
, exportselection
=0,
72 yscrollcommand
=(self
.filesbar
, 'set'))
73 self
.files
.pack(side
=RIGHT
, expand
=YES
, fill
=BOTH
)
74 btags
= self
.files
.bindtags()
75 self
.files
.bindtags(btags
[1:] + btags
[:1])
76 self
.files
.bind('<ButtonRelease-1>', self
.files_select_event
)
77 self
.files
.bind('<Double-ButtonRelease-1>', self
.files_double_event
)
78 self
.filesbar
.config(command
=(self
.files
, 'yview'))
80 self
.dirsbar
= Scrollbar(self
.midframe
)
81 self
.dirsbar
.pack(side
=LEFT
, fill
=Y
)
82 self
.dirs
= Listbox(self
.midframe
, exportselection
=0,
83 yscrollcommand
=(self
.dirsbar
, 'set'))
84 self
.dirs
.pack(side
=LEFT
, expand
=YES
, fill
=BOTH
)
85 self
.dirsbar
.config(command
=(self
.dirs
, 'yview'))
86 btags
= self
.dirs
.bindtags()
87 self
.dirs
.bindtags(btags
[1:] + btags
[:1])
88 self
.dirs
.bind('<ButtonRelease-1>', self
.dirs_select_event
)
89 self
.dirs
.bind('<Double-ButtonRelease-1>', self
.dirs_double_event
)
91 self
.ok_button
= Button(self
.botframe
,
93 command
=self
.ok_command
)
94 self
.ok_button
.pack(side
=LEFT
)
95 self
.filter_button
= Button(self
.botframe
,
97 command
=self
.filter_command
)
98 self
.filter_button
.pack(side
=LEFT
, expand
=YES
)
99 self
.cancel_button
= Button(self
.botframe
,
101 command
=self
.cancel_command
)
102 self
.cancel_button
.pack(side
=RIGHT
)
104 self
.top
.protocol('WM_DELETE_WINDOW', self
.cancel_command
)
105 # XXX Are the following okay for a general audience?
106 self
.top
.bind('<Alt-w>', self
.cancel_command
)
107 self
.top
.bind('<Alt-W>', self
.cancel_command
)
109 def go(self
, dir_or_file
=os
.curdir
, pattern
="*", default
="", key
=None):
110 if key
and key
in dialogstates
:
111 self
.directory
, pattern
= dialogstates
[key
]
113 dir_or_file
= os
.path
.expanduser(dir_or_file
)
114 if os
.path
.isdir(dir_or_file
):
115 self
.directory
= dir_or_file
117 self
.directory
, default
= os
.path
.split(dir_or_file
)
118 self
.set_filter(self
.directory
, pattern
)
119 self
.set_selection(default
)
120 self
.filter_command()
121 self
.selection
.focus_set()
122 self
.top
.wait_visibility() # window needs to be visible for the grab
125 self
.master
.mainloop() # Exited by self.quit(how)
127 directory
, pattern
= self
.get_filter()
129 directory
= os
.path
.dirname(self
.how
)
130 dialogstates
[key
] = directory
, pattern
134 def quit(self
, how
=None):
136 self
.master
.quit() # Exit mainloop()
138 def dirs_double_event(self
, event
):
139 self
.filter_command()
141 def dirs_select_event(self
, event
):
142 dir, pat
= self
.get_filter()
143 subdir
= self
.dirs
.get('active')
144 dir = os
.path
.normpath(os
.path
.join(self
.directory
, subdir
))
145 self
.set_filter(dir, pat
)
147 def files_double_event(self
, event
):
150 def files_select_event(self
, event
):
151 file = self
.files
.get('active')
152 self
.set_selection(file)
154 def ok_event(self
, event
):
157 def ok_command(self
):
158 self
.quit(self
.get_selection())
160 def filter_command(self
, event
=None):
161 dir, pat
= self
.get_filter()
163 names
= os
.listdir(dir)
168 self
.set_filter(dir, pat
)
170 subdirs
= [os
.pardir
]
173 fullname
= os
.path
.join(dir, name
)
174 if os
.path
.isdir(fullname
):
176 elif fnmatch
.fnmatch(name
, pat
):
177 matchingfiles
.append(name
)
178 self
.dirs
.delete(0, END
)
180 self
.dirs
.insert(END
, name
)
181 self
.files
.delete(0, END
)
182 for name
in matchingfiles
:
183 self
.files
.insert(END
, name
)
184 head
, tail
= os
.path
.split(self
.get_selection())
185 if tail
== os
.curdir
: tail
= ''
186 self
.set_selection(tail
)
188 def get_filter(self
):
189 filter = self
.filter.get()
190 filter = os
.path
.expanduser(filter)
191 if filter[-1:] == os
.sep
or os
.path
.isdir(filter):
192 filter = os
.path
.join(filter, "*")
193 return os
.path
.split(filter)
195 def get_selection(self
):
196 file = self
.selection
.get()
197 file = os
.path
.expanduser(file)
200 def cancel_command(self
, event
=None):
203 def set_filter(self
, dir, pat
):
204 if not os
.path
.isabs(dir):
210 dir = os
.path
.join(pwd
, dir)
211 dir = os
.path
.normpath(dir)
212 self
.filter.delete(0, END
)
213 self
.filter.insert(END
, os
.path
.join(dir or os
.curdir
, pat
or "*"))
215 def set_selection(self
, file):
216 self
.selection
.delete(0, END
)
217 self
.selection
.insert(END
, os
.path
.join(self
.directory
, file))
220 class LoadFileDialog(FileDialog
):
222 """File selection dialog which checks that the file exists."""
224 title
= "Load File Selection Dialog"
226 def ok_command(self
):
227 file = self
.get_selection()
228 if not os
.path
.isfile(file):
234 class SaveFileDialog(FileDialog
):
236 """File selection dialog which checks that the file may be created."""
238 title
= "Save File Selection Dialog"
240 def ok_command(self
):
241 file = self
.get_selection()
242 if os
.path
.exists(file):
243 if os
.path
.isdir(file):
247 title
="Overwrite Existing File Question",
248 text
="Overwrite existing file %r?" % (file,),
251 strings
=("Yes", "Cancel"))
255 head
, tail
= os
.path
.split(file)
256 if not os
.path
.isdir(head
):
263 """Simple test program."""
266 fd
= LoadFileDialog(root
)
267 loadfile
= fd
.go(key
="test")
268 fd
= SaveFileDialog(root
)
269 savefile
= fd
.go(key
="test")
270 print loadfile
, savefile
273 if __name__
== '__main__':