blob: 4bb74b716ae262d451836a6b20b454cfa2c37397 [file] [log] [blame]
Guido van Rossumac4f8d31995-08-29 23:46:35 +00001"""File selection dialog classes.
2
3Classes:
4
5- FileDialog
6- LoadFileDialog
7- SaveFileDialog
8
9XXX Bugs:
10
11- The fields are not labeled
12- Default doesn't have absolute pathname
13- Each FileDialog instance can be used only once
14- There is no easy way for an application to add widgets of its own
15
16"""
17
18from Tkinter import *
19from Dialog import Dialog
20
21ANCHOR = 'anchor'
22
23import os
24import fnmatch
25
26
27class FileDialog:
28
29 """Standard file selection dialog -- no checks on selected file.
30
31 Usage:
32
33 d = FileDialog(master)
34 file = d.go(directory, pattern, default)
35 if file is None: ...canceled...
36
37 """
38
39 title = "File Selection Dialog"
40
41 def __init__(self, master):
42 self.master = master
43 self.directory = None
44 self.top = Toplevel(master)
45 self.top.title(self.title)
46 self.filter = Entry(self.top)
47 self.filter.pack(fill=X)
48 self.filter.bind('<Return>', self.filter_command)
49 self.midframe = Frame(self.top)
50 self.midframe.pack(expand=YES, fill=BOTH)
Guido van Rossum51b708a1996-05-28 23:10:30 +000051 self.dirs = Listbox(self.midframe, exportselection=0)
Guido van Rossumac4f8d31995-08-29 23:46:35 +000052 self.dirs.pack(side=LEFT, expand=YES, fill=BOTH)
53 self.dirs.bind('<ButtonRelease-1>', self.dirs_select_event)
54 self.dirs.bind('<Double-ButtonRelease-1>', self.dirs_double_event)
Guido van Rossum51b708a1996-05-28 23:10:30 +000055 self.files = Listbox(self.midframe, exportselection=0)
Guido van Rossumac4f8d31995-08-29 23:46:35 +000056 self.files.pack(side=RIGHT, expand=YES, fill=BOTH)
57 self.files.bind('<ButtonRelease-1>', self.files_select_event)
58 self.files.bind('<Double-ButtonRelease-1>', self.files_double_event)
59 self.selection = Entry(self.top)
60 self.selection.pack(fill=X)
61 self.selection.bind('<Return>', self.ok_event)
62 self.botframe = Frame(self.top)
63 self.botframe.pack(fill=X)
64 self.ok_button = Button(self.botframe,
65 text="OK",
66 command=self.ok_command)
67 self.ok_button.pack(side=LEFT)
68 self.filter_button = Button(self.botframe,
69 text="Filter",
70 command=self.filter_command)
71 self.filter_button.pack(side=LEFT, expand=YES)
72 self.cancel_button = Button(self.botframe,
73 text="Cancel",
74 command=self.cancel_command)
75 self.cancel_button.pack(side=RIGHT)
76
77 def go(self, directory=os.curdir, pattern="*", default=""):
78 self.directory = directory
79 self.set_filter(directory, pattern)
Guido van Rossumb9e39c81995-09-01 20:36:47 +000080 self.filter_command()
Guido van Rossumac4f8d31995-08-29 23:46:35 +000081 self.set_selection(default)
82 self.selection.focus_set()
Guido van Rossumac4f8d31995-08-29 23:46:35 +000083 self.top.grab_set()
84 try:
85 self.master.mainloop()
86 except SystemExit, how:
87 self.top.destroy()
88 return how
89
90 def dirs_double_event(self, event):
91## self.dirs_select_event(event)
92 self.filter_command()
93
94 def dirs_select_event(self, event):
95 dir, pat = self.get_filter()
96 subdir = self.dirs.get(ANCHOR)
97 dir = os.path.normpath(os.path.join(self.directory, subdir))
98 self.set_filter(dir, pat)
99
100 def files_double_event(self, event):
101## self.files_select_event(event)
102## self.master.update_idletasks()
103 self.ok_command()
104
105 def files_select_event(self, event):
106 file = self.files.get(ANCHOR)
107 self.set_selection(file)
108
109 def ok_event(self, event):
110 self.ok_command()
111
112 def ok_command(self):
113 raise SystemExit, self.selection.get()
114
115 def filter_command(self, event=None):
116 dir, pat = self.get_filter()
117 try:
118 names = os.listdir(dir)
119 except os.error:
120 self.master.bell()
121 return
122 self.directory = dir
123 self.set_filter(dir, pat)
124 names.sort()
125 subdirs = [os.pardir]
126 matchingfiles = []
127 for name in names:
128 fullname = os.path.join(dir, name)
129 if os.path.isdir(fullname):
130 subdirs.append(name)
131 elif fnmatch.fnmatch(name, pat):
132 matchingfiles.append(name)
133 self.dirs.delete(0, END)
134 for name in subdirs:
135 self.dirs.insert(END, name)
136 self.files.delete(0, END)
137 for name in matchingfiles:
138 self.files.insert(END, name)
Guido van Rossumb9e39c81995-09-01 20:36:47 +0000139 head, tail = os.path.split(self.selection.get())
140 if tail == os.curdir: tail = ''
141 self.set_selection(tail)
Guido van Rossumac4f8d31995-08-29 23:46:35 +0000142
143 def get_filter(self):
144 filter = self.filter.get()
145 if filter[-1:] == os.sep:
146 filter = filter + "*"
147 return os.path.split(filter)
148
149 def cancel_command(self):
150 raise SystemExit, None
151
152 def set_filter(self, dir, pat):
153 self.filter.delete(0, END)
154 self.filter.insert(END, os.path.join(dir or os.curdir, pat or "*"))
155
156 def set_selection(self, file):
157 self.selection.delete(0, END)
158 self.selection.insert(END, os.path.join(self.directory, file))
159
160
161class LoadFileDialog(FileDialog):
162
163 """File selection dialog which checks that the file exists."""
164
165 title = "Load File Selection Dialog"
166
167 def ok_command(self):
168 file = self.selection.get()
169 if not os.path.isfile(file):
170 self.master.bell()
171 else:
172 raise SystemExit, file
173
174
175class SaveFileDialog(FileDialog):
176
177 """File selection dialog which checks that the file may be created."""
178
179 title = "Save File Selection Dialog"
180
181 def ok_command(self):
182 file = self.selection.get()
183 if os.path.exists(file):
184 if os.path.isdir(file):
185 self.master.bell()
186 return
187 d = Dialog(self.master,
188 title="Overwrite Existing File Question",
189 text="Overwrite existing file %s?" % `file`,
190 bitmap='questhead',
191 default=0,
192 strings=("Yes", "Cancel"))
193 if d.num != 0: file = None
194 else:
195 head, tail = os.path.split(file)
196 if not os.path.isdir(head):
197 self.master.bell()
198 return
199 raise SystemExit, file
200
201
202def test():
203 """Simple test program."""
204 root = Tk()
205 root.withdraw()
206 fd = LoadFileDialog(root)
207 loadfile = fd.go()
208 fd = SaveFileDialog(root)
209 savefile = fd.go()
210 print loadfile, savefile
211
212
213if __name__ == '__main__':
214 test()