Mercurial > cpython-lru_cache-weakref
annotate Lib/lib-tk/FileDialog.py @ 4893:c2eac126e8ff legacy-trunk
Fix the following bug:
- When dragging the mouse in either listbox, the *first* entry
clicked on is selected rather than the last (but the last one is
highlighted).
This is done by changing the bindtags so that our binding is executed
after the default binding (which sets the 'active' index to the last
item selected), and using 'active' instead of 'anchor' as the index to
ask for.
| author | Guido van Rossum <guido@python.org> |
|---|---|
| date | Fri, 03 Jan 1997 23:39:26 +0000 |
| parents | 0d1463a45b6f |
| children | 9c37ed8868b9 |
| rev | line source |
|---|---|
| 3031 | 1 """File selection dialog classes. |
| 2 | |
| 3 Classes: | |
| 4 | |
| 5 - FileDialog | |
| 6 - LoadFileDialog | |
| 7 - SaveFileDialog | |
| 8 | |
| 9 """ | |
| 10 | |
| 11 from Tkinter import * | |
| 12 from Dialog import Dialog | |
| 13 | |
| 14 import os | |
| 15 import fnmatch | |
| 16 | |
| 17 | |
| 3643 | 18 dialogstates = {} |
| 19 | |
| 20 | |
| 3031 | 21 class FileDialog: |
| 22 | |
| 23 """Standard file selection dialog -- no checks on selected file. | |
| 24 | |
| 25 Usage: | |
| 26 | |
| 27 d = FileDialog(master) | |
| 3643 | 28 file = d.go(dir_or_file, pattern, default, key) |
| 3031 | 29 if file is None: ...canceled... |
| 3643 | 30 else: ...open file... |
| 31 | |
| 32 All arguments to go() are optional. | |
| 33 | |
| 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.) | |
| 3031 | 41 |
| 42 """ | |
| 43 | |
| 44 title = "File Selection Dialog" | |
| 45 | |
| 3643 | 46 def __init__(self, master, title=None): |
| 47 if title is None: title = self.title | |
| 3031 | 48 self.master = master |
| 49 self.directory = None | |
| 3643 | 50 |
| 3031 | 51 self.top = Toplevel(master) |
| 3643 | 52 self.top.title(title) |
| 53 self.top.iconname(title) | |
| 54 | |
| 55 self.botframe = Frame(self.top) | |
| 56 self.botframe.pack(side=BOTTOM, fill=X) | |
| 57 | |
| 58 self.selection = Entry(self.top) | |
| 59 self.selection.pack(side=BOTTOM, fill=X) | |
| 60 self.selection.bind('<Return>', self.ok_event) | |
| 61 | |
| 3031 | 62 self.filter = Entry(self.top) |
| 3643 | 63 self.filter.pack(side=TOP, fill=X) |
| 3031 | 64 self.filter.bind('<Return>', self.filter_command) |
| 3643 | 65 |
| 3031 | 66 self.midframe = Frame(self.top) |
| 67 self.midframe.pack(expand=YES, fill=BOTH) | |
| 3643 | 68 |
| 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')) | |
| 3031 | 73 self.files.pack(side=RIGHT, expand=YES, fill=BOTH) |
|
4893
c2eac126e8ff
Fix the following bug:
Guido van Rossum <guido@python.org>
parents:
3643
diff
changeset
|
74 btags = self.files.bindtags() |
|
c2eac126e8ff
Fix the following bug:
Guido van Rossum <guido@python.org>
parents:
3643
diff
changeset
|
75 self.files.bindtags(btags[1:] + btags[:1]) |
| 3031 | 76 self.files.bind('<ButtonRelease-1>', self.files_select_event) |
| 77 self.files.bind('<Double-ButtonRelease-1>', self.files_double_event) | |
| 3643 | 78 self.filesbar.config(command=(self.files, 'yview')) |
| 79 | |
| 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')) | |
|
4893
c2eac126e8ff
Fix the following bug:
Guido van Rossum <guido@python.org>
parents:
3643
diff
changeset
|
86 btags = self.dirs.bindtags() |
|
c2eac126e8ff
Fix the following bug:
Guido van Rossum <guido@python.org>
parents:
3643
diff
changeset
|
87 self.dirs.bindtags(btags[1:] + btags[:1]) |
| 3643 | 88 self.dirs.bind('<ButtonRelease-1>', self.dirs_select_event) |
| 89 self.dirs.bind('<Double-ButtonRelease-1>', self.dirs_double_event) | |
| 90 | |
| 3031 | 91 self.ok_button = Button(self.botframe, |
| 92 text="OK", | |
| 93 command=self.ok_command) | |
| 94 self.ok_button.pack(side=LEFT) | |
| 95 self.filter_button = Button(self.botframe, | |
| 96 text="Filter", | |
| 97 command=self.filter_command) | |
| 98 self.filter_button.pack(side=LEFT, expand=YES) | |
| 99 self.cancel_button = Button(self.botframe, | |
| 100 text="Cancel", | |
| 101 command=self.cancel_command) | |
| 102 self.cancel_button.pack(side=RIGHT) | |
| 103 | |
| 3643 | 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) | |
| 108 | |
| 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] | |
| 112 else: | |
| 113 dir_or_file = os.path.expanduser(dir_or_file) | |
| 114 if os.path.isdir(dir_or_file): | |
| 115 self.directory = dir_or_file | |
| 116 else: | |
| 117 self.directory, default = os.path.split(dir_or_file) | |
| 118 self.set_filter(self.directory, pattern) | |
| 119 self.set_selection(default) | |
|
3068
31c52a0a372c
Filter button should set selection's directory, too
Guido van Rossum <guido@python.org>
parents:
3031
diff
changeset
|
120 self.filter_command() |
| 3031 | 121 self.selection.focus_set() |
| 122 self.top.grab_set() | |
| 3643 | 123 self.how = None |
| 124 self.master.mainloop() # Exited by self.quit(how) | |
| 125 if key: dialogstates[key] = self.get_filter() | |
| 126 self.top.destroy() | |
| 127 return self.how | |
| 128 | |
| 129 def quit(self, how=None): | |
| 130 self.how = how | |
| 131 self.master.quit() # Exit mainloop() | |
| 3031 | 132 |
| 133 def dirs_double_event(self, event): | |
| 134 self.filter_command() | |
| 135 | |
| 136 def dirs_select_event(self, event): | |
| 137 dir, pat = self.get_filter() | |
|
4893
c2eac126e8ff
Fix the following bug:
Guido van Rossum <guido@python.org>
parents:
3643
diff
changeset
|
138 subdir = self.dirs.get('active') |
| 3031 | 139 dir = os.path.normpath(os.path.join(self.directory, subdir)) |
| 140 self.set_filter(dir, pat) | |
| 141 | |
| 142 def files_double_event(self, event): | |
| 143 self.ok_command() | |
| 144 | |
| 145 def files_select_event(self, event): | |
|
4893
c2eac126e8ff
Fix the following bug:
Guido van Rossum <guido@python.org>
parents:
3643
diff
changeset
|
146 file = self.files.get('active') |
| 3031 | 147 self.set_selection(file) |
| 148 | |
| 149 def ok_event(self, event): | |
| 150 self.ok_command() | |
| 151 | |
| 152 def ok_command(self): | |
| 3643 | 153 self.quit(self.get_selection()) |
| 3031 | 154 |
| 155 def filter_command(self, event=None): | |
| 156 dir, pat = self.get_filter() | |
| 157 try: | |
| 158 names = os.listdir(dir) | |
| 159 except os.error: | |
| 160 self.master.bell() | |
| 161 return | |
| 162 self.directory = dir | |
| 163 self.set_filter(dir, pat) | |
| 164 names.sort() | |
| 165 subdirs = [os.pardir] | |
| 166 matchingfiles = [] | |
| 167 for name in names: | |
| 168 fullname = os.path.join(dir, name) | |
| 169 if os.path.isdir(fullname): | |
| 170 subdirs.append(name) | |
| 171 elif fnmatch.fnmatch(name, pat): | |
| 172 matchingfiles.append(name) | |
| 173 self.dirs.delete(0, END) | |
| 174 for name in subdirs: | |
| 175 self.dirs.insert(END, name) | |
| 176 self.files.delete(0, END) | |
| 177 for name in matchingfiles: | |
| 178 self.files.insert(END, name) | |
| 3643 | 179 head, tail = os.path.split(self.get_selection()) |
|
3068
31c52a0a372c
Filter button should set selection's directory, too
Guido van Rossum <guido@python.org>
parents:
3031
diff
changeset
|
180 if tail == os.curdir: tail = '' |
|
31c52a0a372c
Filter button should set selection's directory, too
Guido van Rossum <guido@python.org>
parents:
3031
diff
changeset
|
181 self.set_selection(tail) |
| 3031 | 182 |
| 183 def get_filter(self): | |
| 184 filter = self.filter.get() | |
| 3643 | 185 filter = os.path.expanduser(filter) |
| 186 if filter[-1:] == os.sep or os.path.isdir(filter): | |
| 187 filter = os.path.join(filter, "*") | |
| 3031 | 188 return os.path.split(filter) |
| 189 | |
| 3643 | 190 def get_selection(self): |
| 191 file = self.selection.get() | |
| 192 file = os.path.expanduser(file) | |
| 193 return file | |
| 194 | |
| 195 def cancel_command(self, event=None): | |
| 196 self.quit() | |
| 3031 | 197 |
| 198 def set_filter(self, dir, pat): | |
| 3643 | 199 if not os.path.isabs(dir): |
| 200 try: | |
| 201 pwd = os.getcwd() | |
| 202 except os.error: | |
| 203 pwd = None | |
| 204 if pwd: | |
| 205 dir = os.path.join(pwd, dir) | |
| 206 dir = os.path.normpath(dir) | |
| 3031 | 207 self.filter.delete(0, END) |
| 208 self.filter.insert(END, os.path.join(dir or os.curdir, pat or "*")) | |
| 209 | |
| 210 def set_selection(self, file): | |
| 211 self.selection.delete(0, END) | |
| 212 self.selection.insert(END, os.path.join(self.directory, file)) | |
| 213 | |
| 214 | |
| 215 class LoadFileDialog(FileDialog): | |
| 216 | |
| 217 """File selection dialog which checks that the file exists.""" | |
| 218 | |
| 219 title = "Load File Selection Dialog" | |
| 220 | |
| 221 def ok_command(self): | |
| 3643 | 222 file = self.get_selection() |
| 3031 | 223 if not os.path.isfile(file): |
| 224 self.master.bell() | |
| 225 else: | |
| 3643 | 226 self.quit(file) |
| 3031 | 227 |
| 228 | |
| 229 class SaveFileDialog(FileDialog): | |
| 230 | |
| 231 """File selection dialog which checks that the file may be created.""" | |
| 232 | |
| 233 title = "Save File Selection Dialog" | |
| 234 | |
| 235 def ok_command(self): | |
| 3643 | 236 file = self.get_selection() |
| 3031 | 237 if os.path.exists(file): |
| 238 if os.path.isdir(file): | |
| 239 self.master.bell() | |
| 240 return | |
| 3643 | 241 d = Dialog(self.top, |
| 3031 | 242 title="Overwrite Existing File Question", |
| 243 text="Overwrite existing file %s?" % `file`, | |
| 244 bitmap='questhead', | |
| 3643 | 245 default=1, |
| 3031 | 246 strings=("Yes", "Cancel")) |
| 3643 | 247 if d.num != 0: |
| 248 return | |
| 3031 | 249 else: |
| 250 head, tail = os.path.split(file) | |
| 251 if not os.path.isdir(head): | |
| 252 self.master.bell() | |
| 253 return | |
| 3643 | 254 self.quit(file) |
| 3031 | 255 |
| 256 | |
| 257 def test(): | |
| 258 """Simple test program.""" | |
| 259 root = Tk() | |
| 260 root.withdraw() | |
| 261 fd = LoadFileDialog(root) | |
| 3643 | 262 loadfile = fd.go(key="test") |
| 3031 | 263 fd = SaveFileDialog(root) |
| 3643 | 264 savefile = fd.go(key="test") |
| 3031 | 265 print loadfile, savefile |
| 266 | |
| 267 | |
| 268 if __name__ == '__main__': | |
| 269 test() |
