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 file = d.go(dir_or_file, pattern, default, key)
29 if file 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 cancelled. (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 dialogstates
.has_key(key
):
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()
124 self
.master
.mainloop() # Exited by self.quit(how)
126 directory
, pattern
= self
.get_filter()
128 directory
= os
.path
.dirname(self
.how
)
129 dialogstates
[key
] = directory
, pattern
133 def quit(self
, how
=None):
135 self
.master
.quit() # Exit mainloop()
137 def dirs_double_event(self
, event
):
138 self
.filter_command()
140 def dirs_select_event(self
, event
):
141 dir, pat
= self
.get_filter()
142 subdir
= self
.dirs
.get('active')
143 dir = os
.path
.normpath(os
.path
.join(self
.directory
, subdir
))
144 self
.set_filter(dir, pat
)
146 def files_double_event(self
, event
):
149 def files_select_event(self
, event
):
150 file = self
.files
.get('active')
151 self
.set_selection(file)
153 def ok_event(self
, event
):
156 def ok_command(self
):
157 self
.quit(self
.get_selection())
159 def filter_command(self
, event
=None):
160 dir, pat
= self
.get_filter()
162 names
= os
.listdir(dir)
167 self
.set_filter(dir, pat
)
169 subdirs
= [os
.pardir
]
172 fullname
= os
.path
.join(dir, name
)
173 if os
.path
.isdir(fullname
):
175 elif fnmatch
.fnmatch(name
, pat
):
176 matchingfiles
.append(name
)
177 self
.dirs
.delete(0, END
)
179 self
.dirs
.insert(END
, name
)
180 self
.files
.delete(0, END
)
181 for name
in matchingfiles
:
182 self
.files
.insert(END
, name
)
183 head
, tail
= os
.path
.split(self
.get_selection())
184 if tail
== os
.curdir
: tail
= ''
185 self
.set_selection(tail
)
187 def get_filter(self
):
188 filter = self
.filter.get()
189 filter = os
.path
.expanduser(filter)
190 if filter[-1:] == os
.sep
or os
.path
.isdir(filter):
191 filter = os
.path
.join(filter, "*")
192 return os
.path
.split(filter)
194 def get_selection(self
):
195 file = self
.selection
.get()
196 file = os
.path
.expanduser(file)
199 def cancel_command(self
, event
=None):
202 def set_filter(self
, dir, pat
):
203 if not os
.path
.isabs(dir):
209 dir = os
.path
.join(pwd
, dir)
210 dir = os
.path
.normpath(dir)
211 self
.filter.delete(0, END
)
212 self
.filter.insert(END
, os
.path
.join(dir or os
.curdir
, pat
or "*"))
214 def set_selection(self
, file):
215 self
.selection
.delete(0, END
)
216 self
.selection
.insert(END
, os
.path
.join(self
.directory
, file))
219 class LoadFileDialog(FileDialog
):
221 """File selection dialog which checks that the file exists."""
223 title
= "Load File Selection Dialog"
225 def ok_command(self
):
226 file = self
.get_selection()
227 if not os
.path
.isfile(file):
233 class SaveFileDialog(FileDialog
):
235 """File selection dialog which checks that the file may be created."""
237 title
= "Save File Selection Dialog"
239 def ok_command(self
):
240 file = self
.get_selection()
241 if os
.path
.exists(file):
242 if os
.path
.isdir(file):
246 title
="Overwrite Existing File Question",
247 text
="Overwrite existing file %s?" % `
file`
,
250 strings
=("Yes", "Cancel"))
254 head
, tail
= os
.path
.split(file)
255 if not os
.path
.isdir(head
):
262 """Simple test program."""
265 fd
= LoadFileDialog(root
)
266 loadfile
= fd
.go(key
="test")
267 fd
= SaveFileDialog(root
)
268 savefile
= fd
.go(key
="test")
269 print loadfile
, savefile
272 if __name__
== '__main__':