PyXR

c:\python24\lib\lib-tk \ FileDialog.py



0001 """File selection dialog classes.
0002 
0003 Classes:
0004 
0005 - FileDialog
0006 - LoadFileDialog
0007 - SaveFileDialog
0008 
0009 """
0010 
0011 from Tkinter import *
0012 from Dialog import Dialog
0013 
0014 import os
0015 import fnmatch
0016 
0017 
0018 dialogstates = {}
0019 
0020 
0021 class FileDialog:
0022 
0023     """Standard file selection dialog -- no checks on selected file.
0024 
0025     Usage:
0026 
0027         d = FileDialog(master)
0028         fname = d.go(dir_or_file, pattern, default, key)
0029         if fname is None: ...canceled...
0030         else: ...open file...
0031 
0032     All arguments to go() are optional.
0033 
0034     The 'key' argument specifies a key in the global dictionary
0035     'dialogstates', which keeps track of the values for the directory
0036     and pattern arguments, overriding the values passed in (it does
0037     not keep track of the default argument!).  If no key is specified,
0038     the dialog keeps no memory of previous state.  Note that memory is
0039     kept even when the dialog is canceled.  (All this emulates the
0040     behavior of the Macintosh file selection dialogs.)
0041 
0042     """
0043 
0044     title = "File Selection Dialog"
0045 
0046     def __init__(self, master, title=None):
0047         if title is None: title = self.title
0048         self.master = master
0049         self.directory = None
0050 
0051         self.top = Toplevel(master)
0052         self.top.title(title)
0053         self.top.iconname(title)
0054 
0055         self.botframe = Frame(self.top)
0056         self.botframe.pack(side=BOTTOM, fill=X)
0057 
0058         self.selection = Entry(self.top)
0059         self.selection.pack(side=BOTTOM, fill=X)
0060         self.selection.bind('<Return>', self.ok_event)
0061 
0062         self.filter = Entry(self.top)
0063         self.filter.pack(side=TOP, fill=X)
0064         self.filter.bind('<Return>', self.filter_command)
0065 
0066         self.midframe = Frame(self.top)
0067         self.midframe.pack(expand=YES, fill=BOTH)
0068 
0069         self.filesbar = Scrollbar(self.midframe)
0070         self.filesbar.pack(side=RIGHT, fill=Y)
0071         self.files = Listbox(self.midframe, exportselection=0,
0072                              yscrollcommand=(self.filesbar, 'set'))
0073         self.files.pack(side=RIGHT, expand=YES, fill=BOTH)
0074         btags = self.files.bindtags()
0075         self.files.bindtags(btags[1:] + btags[:1])
0076         self.files.bind('<ButtonRelease-1>', self.files_select_event)
0077         self.files.bind('<Double-ButtonRelease-1>', self.files_double_event)
0078         self.filesbar.config(command=(self.files, 'yview'))
0079 
0080         self.dirsbar = Scrollbar(self.midframe)
0081         self.dirsbar.pack(side=LEFT, fill=Y)
0082         self.dirs = Listbox(self.midframe, exportselection=0,
0083                             yscrollcommand=(self.dirsbar, 'set'))
0084         self.dirs.pack(side=LEFT, expand=YES, fill=BOTH)
0085         self.dirsbar.config(command=(self.dirs, 'yview'))
0086         btags = self.dirs.bindtags()
0087         self.dirs.bindtags(btags[1:] + btags[:1])
0088         self.dirs.bind('<ButtonRelease-1>', self.dirs_select_event)
0089         self.dirs.bind('<Double-ButtonRelease-1>', self.dirs_double_event)
0090 
0091         self.ok_button = Button(self.botframe,
0092                                  text="OK",
0093                                  command=self.ok_command)
0094         self.ok_button.pack(side=LEFT)
0095         self.filter_button = Button(self.botframe,
0096                                     text="Filter",
0097                                     command=self.filter_command)
0098         self.filter_button.pack(side=LEFT, expand=YES)
0099         self.cancel_button = Button(self.botframe,
0100                                     text="Cancel",
0101                                     command=self.cancel_command)
0102         self.cancel_button.pack(side=RIGHT)
0103 
0104         self.top.protocol('WM_DELETE_WINDOW', self.cancel_command)
0105         # XXX Are the following okay for a general audience?
0106         self.top.bind('<Alt-w>', self.cancel_command)
0107         self.top.bind('<Alt-W>', self.cancel_command)
0108 
0109     def go(self, dir_or_file=os.curdir, pattern="*", default="", key=None):
0110         if key and dialogstates.has_key(key):
0111             self.directory, pattern = dialogstates[key]
0112         else:
0113             dir_or_file = os.path.expanduser(dir_or_file)
0114             if os.path.isdir(dir_or_file):
0115                 self.directory = dir_or_file
0116             else:
0117                 self.directory, default = os.path.split(dir_or_file)
0118         self.set_filter(self.directory, pattern)
0119         self.set_selection(default)
0120         self.filter_command()
0121         self.selection.focus_set()
0122         self.top.wait_visibility() # window needs to be visible for the grab
0123         self.top.grab_set()
0124         self.how = None
0125         self.master.mainloop()          # Exited by self.quit(how)
0126         if key:
0127             directory, pattern = self.get_filter()
0128             if self.how:
0129                 directory = os.path.dirname(self.how)
0130             dialogstates[key] = directory, pattern
0131         self.top.destroy()
0132         return self.how
0133 
0134     def quit(self, how=None):
0135         self.how = how
0136         self.master.quit()              # Exit mainloop()
0137 
0138     def dirs_double_event(self, event):
0139         self.filter_command()
0140 
0141     def dirs_select_event(self, event):
0142         dir, pat = self.get_filter()
0143         subdir = self.dirs.get('active')
0144         dir = os.path.normpath(os.path.join(self.directory, subdir))
0145         self.set_filter(dir, pat)
0146 
0147     def files_double_event(self, event):
0148         self.ok_command()
0149 
0150     def files_select_event(self, event):
0151         file = self.files.get('active')
0152         self.set_selection(file)
0153 
0154     def ok_event(self, event):
0155         self.ok_command()
0156 
0157     def ok_command(self):
0158         self.quit(self.get_selection())
0159 
0160     def filter_command(self, event=None):
0161         dir, pat = self.get_filter()
0162         try:
0163             names = os.listdir(dir)
0164         except os.error:
0165             self.master.bell()
0166             return
0167         self.directory = dir
0168         self.set_filter(dir, pat)
0169         names.sort()
0170         subdirs = [os.pardir]
0171         matchingfiles = []
0172         for name in names:
0173             fullname = os.path.join(dir, name)
0174             if os.path.isdir(fullname):
0175                 subdirs.append(name)
0176             elif fnmatch.fnmatch(name, pat):
0177                 matchingfiles.append(name)
0178         self.dirs.delete(0, END)
0179         for name in subdirs:
0180             self.dirs.insert(END, name)
0181         self.files.delete(0, END)
0182         for name in matchingfiles:
0183             self.files.insert(END, name)
0184         head, tail = os.path.split(self.get_selection())
0185         if tail == os.curdir: tail = ''
0186         self.set_selection(tail)
0187 
0188     def get_filter(self):
0189         filter = self.filter.get()
0190         filter = os.path.expanduser(filter)
0191         if filter[-1:] == os.sep or os.path.isdir(filter):
0192             filter = os.path.join(filter, "*")
0193         return os.path.split(filter)
0194 
0195     def get_selection(self):
0196         file = self.selection.get()
0197         file = os.path.expanduser(file)
0198         return file
0199 
0200     def cancel_command(self, event=None):
0201         self.quit()
0202 
0203     def set_filter(self, dir, pat):
0204         if not os.path.isabs(dir):
0205             try:
0206                 pwd = os.getcwd()
0207             except os.error:
0208                 pwd = None
0209             if pwd:
0210                 dir = os.path.join(pwd, dir)
0211                 dir = os.path.normpath(dir)
0212         self.filter.delete(0, END)
0213         self.filter.insert(END, os.path.join(dir or os.curdir, pat or "*"))
0214 
0215     def set_selection(self, file):
0216         self.selection.delete(0, END)
0217         self.selection.insert(END, os.path.join(self.directory, file))
0218 
0219 
0220 class LoadFileDialog(FileDialog):
0221 
0222     """File selection dialog which checks that the file exists."""
0223 
0224     title = "Load File Selection Dialog"
0225 
0226     def ok_command(self):
0227         file = self.get_selection()
0228         if not os.path.isfile(file):
0229             self.master.bell()
0230         else:
0231             self.quit(file)
0232 
0233 
0234 class SaveFileDialog(FileDialog):
0235 
0236     """File selection dialog which checks that the file may be created."""
0237 
0238     title = "Save File Selection Dialog"
0239 
0240     def ok_command(self):
0241         file = self.get_selection()
0242         if os.path.exists(file):
0243             if os.path.isdir(file):
0244                 self.master.bell()
0245                 return
0246             d = Dialog(self.top,
0247                        title="Overwrite Existing File Question",
0248                        text="Overwrite existing file %r?" % (file,),
0249                        bitmap='questhead',
0250                        default=1,
0251                        strings=("Yes", "Cancel"))
0252             if d.num != 0:
0253                 return
0254         else:
0255             head, tail = os.path.split(file)
0256             if not os.path.isdir(head):
0257                 self.master.bell()
0258                 return
0259         self.quit(file)
0260 
0261 
0262 def test():
0263     """Simple test program."""
0264     root = Tk()
0265     root.withdraw()
0266     fd = LoadFileDialog(root)
0267     loadfile = fd.go(key="test")
0268     fd = SaveFileDialog(root)
0269     savefile = fd.go(key="test")
0270     print loadfile, savefile
0271 
0272 
0273 if __name__ == '__main__':
0274     test()
0275 

Generated by PyXR 0.9.4
SourceForge.net Logo