| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | """File selection dialog classes.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Classes: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - FileDialog | 
					
						
							|  |  |  | - LoadFileDialog | 
					
						
							|  |  |  | - SaveFileDialog | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from Tkinter import * | 
					
						
							|  |  |  | from Dialog import Dialog | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | import fnmatch | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | dialogstates = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | class FileDialog: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """Standard file selection dialog -- no checks on selected file.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Usage: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         d = FileDialog(master) | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  |         file = d.go(dir_or_file, pattern, default, key) | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  |         if file is None: ...canceled... | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | 	else: ...open file... | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     All arguments to go() are optional. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The 'key' argument specifies a key in the global dictionary | 
					
						
							|  |  |  |     'dialogstates', which keeps track of the values for the directory | 
					
						
							|  |  |  |     and pattern arguments, overriding the values passed in (it does | 
					
						
							|  |  |  |     not keep track of the default argument!).  If no key is specified, | 
					
						
							|  |  |  |     the dialog keeps no memory of previous state.  Note that memory is | 
					
						
							|  |  |  |     kept even when the dialog is cancelled.  (All this emulates the | 
					
						
							|  |  |  |     behavior of the Macintosh file selection dialogs.) | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     title = "File Selection Dialog" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  |     def __init__(self, master, title=None): | 
					
						
							|  |  |  | 	if title is None: title = self.title | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 	self.master = master | 
					
						
							|  |  |  | 	self.directory = None | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 	self.top = Toplevel(master) | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | 	self.top.title(title) | 
					
						
							|  |  |  | 	self.top.iconname(title) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	self.botframe = Frame(self.top) | 
					
						
							|  |  |  | 	self.botframe.pack(side=BOTTOM, fill=X) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	self.selection = Entry(self.top) | 
					
						
							|  |  |  | 	self.selection.pack(side=BOTTOM, fill=X) | 
					
						
							|  |  |  | 	self.selection.bind('<Return>', self.ok_event) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 	self.filter = Entry(self.top) | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | 	self.filter.pack(side=TOP, fill=X) | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 	self.filter.bind('<Return>', self.filter_command) | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 	self.midframe = Frame(self.top) | 
					
						
							|  |  |  | 	self.midframe.pack(expand=YES, fill=BOTH) | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	self.filesbar = Scrollbar(self.midframe) | 
					
						
							|  |  |  | 	self.filesbar.pack(side=RIGHT, fill=Y) | 
					
						
							|  |  |  | 	self.files = Listbox(self.midframe, exportselection=0, | 
					
						
							|  |  |  | 			     yscrollcommand=(self.filesbar, 'set')) | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 	self.files.pack(side=RIGHT, expand=YES, fill=BOTH) | 
					
						
							| 
									
										
										
										
											1997-01-03 23:39:26 +00:00
										 |  |  | 	btags = self.files.bindtags() | 
					
						
							|  |  |  | 	self.files.bindtags(btags[1:] + btags[:1]) | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 	self.files.bind('<ButtonRelease-1>', self.files_select_event) | 
					
						
							|  |  |  | 	self.files.bind('<Double-ButtonRelease-1>', self.files_double_event) | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | 	self.filesbar.config(command=(self.files, 'yview')) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	self.dirsbar = Scrollbar(self.midframe) | 
					
						
							|  |  |  | 	self.dirsbar.pack(side=LEFT, fill=Y) | 
					
						
							|  |  |  | 	self.dirs = Listbox(self.midframe, exportselection=0, | 
					
						
							|  |  |  | 			    yscrollcommand=(self.dirsbar, 'set')) | 
					
						
							|  |  |  | 	self.dirs.pack(side=LEFT, expand=YES, fill=BOTH) | 
					
						
							|  |  |  | 	self.dirsbar.config(command=(self.dirs, 'yview')) | 
					
						
							| 
									
										
										
										
											1997-01-03 23:39:26 +00:00
										 |  |  | 	btags = self.dirs.bindtags() | 
					
						
							|  |  |  | 	self.dirs.bindtags(btags[1:] + btags[:1]) | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | 	self.dirs.bind('<ButtonRelease-1>', self.dirs_select_event) | 
					
						
							|  |  |  | 	self.dirs.bind('<Double-ButtonRelease-1>', self.dirs_double_event) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 	self.ok_button = Button(self.botframe, | 
					
						
							|  |  |  | 				 text="OK", | 
					
						
							|  |  |  | 				 command=self.ok_command) | 
					
						
							|  |  |  | 	self.ok_button.pack(side=LEFT) | 
					
						
							|  |  |  | 	self.filter_button = Button(self.botframe, | 
					
						
							|  |  |  | 				    text="Filter", | 
					
						
							|  |  |  | 				    command=self.filter_command) | 
					
						
							|  |  |  | 	self.filter_button.pack(side=LEFT, expand=YES) | 
					
						
							|  |  |  | 	self.cancel_button = Button(self.botframe, | 
					
						
							|  |  |  | 				    text="Cancel", | 
					
						
							|  |  |  | 				    command=self.cancel_command) | 
					
						
							|  |  |  | 	self.cancel_button.pack(side=RIGHT) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | 	self.top.protocol('WM_DELETE_WINDOW', self.cancel_command) | 
					
						
							|  |  |  | 	# XXX Are the following okay for a general audience? | 
					
						
							|  |  |  | 	self.top.bind('<Alt-w>', self.cancel_command) | 
					
						
							|  |  |  | 	self.top.bind('<Alt-W>', self.cancel_command) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def go(self, dir_or_file=os.curdir, pattern="*", default="", key=None): | 
					
						
							|  |  |  | 	if key and dialogstates.has_key(key): | 
					
						
							|  |  |  | 	    self.directory, pattern = dialogstates[key] | 
					
						
							|  |  |  | 	else: | 
					
						
							|  |  |  | 	    dir_or_file = os.path.expanduser(dir_or_file) | 
					
						
							|  |  |  | 	    if os.path.isdir(dir_or_file): | 
					
						
							|  |  |  | 		self.directory = dir_or_file | 
					
						
							|  |  |  | 	    else: | 
					
						
							|  |  |  | 		self.directory, default = os.path.split(dir_or_file) | 
					
						
							|  |  |  | 	self.set_filter(self.directory, pattern) | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 	self.set_selection(default) | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | 	self.filter_command() | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 	self.selection.focus_set() | 
					
						
							|  |  |  | 	self.top.grab_set() | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | 	self.how = None | 
					
						
							|  |  |  | 	self.master.mainloop()		# Exited by self.quit(how) | 
					
						
							|  |  |  | 	if key: dialogstates[key] = self.get_filter() | 
					
						
							|  |  |  | 	self.top.destroy() | 
					
						
							|  |  |  | 	return self.how | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def quit(self, how=None): | 
					
						
							|  |  |  | 	self.how = how | 
					
						
							|  |  |  | 	self.master.quit()		# Exit mainloop() | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def dirs_double_event(self, event): | 
					
						
							|  |  |  | 	self.filter_command() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def dirs_select_event(self, event): | 
					
						
							|  |  |  | 	dir, pat = self.get_filter() | 
					
						
							| 
									
										
										
										
											1997-01-03 23:39:26 +00:00
										 |  |  | 	subdir = self.dirs.get('active') | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 	dir = os.path.normpath(os.path.join(self.directory, subdir)) | 
					
						
							|  |  |  | 	self.set_filter(dir, pat) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def files_double_event(self, event): | 
					
						
							|  |  |  | 	self.ok_command() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def files_select_event(self, event): | 
					
						
							| 
									
										
										
										
											1997-01-03 23:39:26 +00:00
										 |  |  | 	file = self.files.get('active') | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 	self.set_selection(file) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def ok_event(self, event): | 
					
						
							|  |  |  | 	self.ok_command() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def ok_command(self): | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | 	self.quit(self.get_selection()) | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def filter_command(self, event=None): | 
					
						
							|  |  |  | 	dir, pat = self.get_filter() | 
					
						
							|  |  |  | 	try: | 
					
						
							|  |  |  | 	    names = os.listdir(dir) | 
					
						
							|  |  |  | 	except os.error: | 
					
						
							|  |  |  | 	    self.master.bell() | 
					
						
							|  |  |  | 	    return | 
					
						
							|  |  |  | 	self.directory = dir | 
					
						
							|  |  |  | 	self.set_filter(dir, pat) | 
					
						
							|  |  |  | 	names.sort() | 
					
						
							|  |  |  | 	subdirs = [os.pardir] | 
					
						
							|  |  |  | 	matchingfiles = [] | 
					
						
							|  |  |  | 	for name in names: | 
					
						
							|  |  |  | 	    fullname = os.path.join(dir, name) | 
					
						
							|  |  |  | 	    if os.path.isdir(fullname): | 
					
						
							|  |  |  | 		subdirs.append(name) | 
					
						
							|  |  |  | 	    elif fnmatch.fnmatch(name, pat): | 
					
						
							|  |  |  | 		matchingfiles.append(name) | 
					
						
							|  |  |  | 	self.dirs.delete(0, END) | 
					
						
							|  |  |  | 	for name in subdirs: | 
					
						
							|  |  |  | 	    self.dirs.insert(END, name) | 
					
						
							|  |  |  | 	self.files.delete(0, END) | 
					
						
							|  |  |  | 	for name in matchingfiles: | 
					
						
							|  |  |  | 	    self.files.insert(END, name) | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | 	head, tail = os.path.split(self.get_selection()) | 
					
						
							| 
									
										
										
										
											1995-09-01 20:36:47 +00:00
										 |  |  | 	if tail == os.curdir: tail = '' | 
					
						
							|  |  |  | 	self.set_selection(tail) | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def get_filter(self): | 
					
						
							|  |  |  | 	filter = self.filter.get() | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | 	filter = os.path.expanduser(filter) | 
					
						
							|  |  |  | 	if filter[-1:] == os.sep or os.path.isdir(filter): | 
					
						
							|  |  |  | 	    filter = os.path.join(filter, "*") | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 	return os.path.split(filter) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  |     def get_selection(self): | 
					
						
							|  |  |  | 	file = self.selection.get() | 
					
						
							|  |  |  | 	file = os.path.expanduser(file) | 
					
						
							|  |  |  | 	return file | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def cancel_command(self, event=None): | 
					
						
							|  |  |  | 	self.quit() | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def set_filter(self, dir, pat): | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | 	if not os.path.isabs(dir): | 
					
						
							|  |  |  | 	    try: | 
					
						
							|  |  |  | 		pwd = os.getcwd() | 
					
						
							|  |  |  | 	    except os.error: | 
					
						
							|  |  |  | 		pwd = None | 
					
						
							|  |  |  | 	    if pwd: | 
					
						
							|  |  |  | 		dir = os.path.join(pwd, dir) | 
					
						
							|  |  |  | 		dir = os.path.normpath(dir) | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 	self.filter.delete(0, END) | 
					
						
							|  |  |  | 	self.filter.insert(END, os.path.join(dir or os.curdir, pat or "*")) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def set_selection(self, file): | 
					
						
							|  |  |  | 	self.selection.delete(0, END) | 
					
						
							|  |  |  | 	self.selection.insert(END, os.path.join(self.directory, file)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class LoadFileDialog(FileDialog): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """File selection dialog which checks that the file exists.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     title = "Load File Selection Dialog" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def ok_command(self): | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | 	file = self.get_selection() | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 	if not os.path.isfile(file): | 
					
						
							|  |  |  | 	    self.master.bell() | 
					
						
							|  |  |  | 	else: | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | 	    self.quit(file) | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class SaveFileDialog(FileDialog): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """File selection dialog which checks that the file may be created.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     title = "Save File Selection Dialog" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def ok_command(self): | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | 	file = self.get_selection() | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 	if os.path.exists(file): | 
					
						
							|  |  |  | 	    if os.path.isdir(file): | 
					
						
							|  |  |  | 		self.master.bell() | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | 	    d = Dialog(self.top, | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 		       title="Overwrite Existing File Question", | 
					
						
							|  |  |  | 		       text="Overwrite existing file %s?" % `file`, | 
					
						
							|  |  |  | 		       bitmap='questhead', | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | 		       default=1, | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 		       strings=("Yes", "Cancel")) | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | 	    if d.num != 0: | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 	else: | 
					
						
							|  |  |  | 	    head, tail = os.path.split(file) | 
					
						
							|  |  |  | 	    if not os.path.isdir(head): | 
					
						
							|  |  |  | 		self.master.bell() | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  | 	self.quit(file) | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def test(): | 
					
						
							|  |  |  |     """Simple test program.""" | 
					
						
							|  |  |  |     root = Tk() | 
					
						
							|  |  |  |     root.withdraw() | 
					
						
							|  |  |  |     fd = LoadFileDialog(root) | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  |     loadfile = fd.go(key="test") | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  |     fd = SaveFileDialog(root) | 
					
						
							| 
									
										
										
										
											1996-05-28 23:14:36 +00:00
										 |  |  |     savefile = fd.go(key="test") | 
					
						
							| 
									
										
										
										
											1995-08-29 23:46:35 +00:00
										 |  |  |     print loadfile, savefile | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  |     test() |