Package pype :: Module filebox
[frames] | no frames]

Source Code for Module pype.filebox

  1  # -*- Mode: Python; tab-width: 4; py-indent-offset: 4; -*- 
  2   
  3  """Open/Save file dialog box 
  4   
  5  Customized dialog boxes derrived from the standard Tkinter 
  6  Dialog class. 
  7   
  8  Author -- James A. Mazer (mazerj@gmail.com) 
  9   
 10  """ 
 11   
 12  from Tkinter import * 
 13  from Dialog import Dialog 
 14   
 15  import os 
 16  import fnmatch 
 17  import string 
 18   
 19  dialogstates = {} 
 20   
21 -def _comparedatafiles(a, b):
22 """Compare two datafile names for sorting 23 24 Try to sort pype datafiles in descending order by file number.. 25 This is highly PYPE-SPECIFIC and is activated by passing keyword 26 argument datafiles=1 to the Open() and SaveAs() functions below 27 28 Pype data file names are of the form:: 29 30 <animal_id><cell_number>.<taskname><taskversion>.<filenumber> 31 32 eg, m0037.hmap7.002, where, 33 34 - animal is "m" 35 36 - task was hmap (version 7) 37 38 - and this is the 3rd (0,1,2) datafile collected for cell m0037 39 40 """ 41 try: 42 if int(a.split('.')[2]) > int(b.split('.')[2]): 43 return -1 44 else: 45 return 1 46 except (IndexError, ValueError): 47 if a > b: 48 return 1 49 else: 50 return -1 51 except: 52 # [[effort to remove all unnamed exceptions: 53 import pypedebug 54 pypedebug.get_traceback(1) 55 # effort to remove all unnamed exceptions:]] 56 if a > b: 57 return 1 58 else: 59 return -1
60
61 -class FileDialog(object):
62 63 """Standard file selection dialog -- no checks on selected file. 64 65 Usage: 66 67 d = FileDialog(master) 68 file = d.go(initialdir, pattern, initialfile, key) 69 if file is None: ...canceled... 70 else: ...open file... 71 72 All arguments to go() are optional. 73 74 The 'key' argument specifies a key in the global dictionary 75 'dialogstates', which keeps track of the values for the directory 76 and pattern arguments, overriding the values passed in (it does 77 not keep track of the initialfile argument!). If no key is specified, 78 the dialog keeps no memory of previous state. Note that memory is 79 kept even when the dialog is canceled. (All this emulates the 80 behavior of the Macintosh file selection dialogs.) 81 82 """ 83 84 title = "File Selection" 85
86 - def __init__(self, master=None, title=None, text=None, sortfn=None):
87 if title is None: 88 title = self.title 89 self.master = master 90 self.directory = None 91 self.mode = None 92 self.sortfn = sortfn 93 94 self.top = Toplevel(master) 95 self.top.title(title) 96 self.top.iconname(title) 97 98 # place filedialog under mouse.. 99 self.top.geometry("+%d+%d" % \ 100 (self.top.winfo_toplevel().winfo_pointerx(), \ 101 self.top.winfo_toplevel().winfo_pointery(),)) 102 103 self.botframe = Frame(self.top) 104 self.botframe.pack(side=BOTTOM, fill=X) 105 106 if text: 107 self.text = Label(self.top, text=text) 108 self.text.pack(side=TOP, pady=15, fill=X) 109 110 # this one's the actual filename box.. 111 self.selection = Entry(self.top, fg='red') 112 self.selection.pack(side=BOTTOM, fill=X) 113 self.selection.bind('<Return>', self.ok_event) 114 115 # directory/pattern box 116 self.filter = Entry(self.top) 117 self.filter.pack(side=TOP, fill=X) 118 self.filter.bind('<Return>', self.filter_command) 119 120 self.midframe = Frame(self.top) 121 self.midframe.pack(expand=YES, fill=BOTH) 122 123 self.filesbar = Scrollbar(self.midframe) 124 self.filesbar.pack(side=RIGHT, fill=Y) 125 self.files = Listbox(self.midframe, exportselection=0, 126 yscrollcommand=(self.filesbar, 'set')) 127 self.files.pack(side=RIGHT, expand=YES, fill=BOTH) 128 btags = self.files.bindtags() 129 self.files.bindtags(btags[1:] + btags[:1]) 130 self.files.bind('<ButtonRelease-1>', self.files_select_event) 131 self.files.bind('<Double-ButtonRelease-1>', self.files_double_event) 132 self.filesbar.config(command=(self.files, 'yview')) 133 134 self.dirsbar = Scrollbar(self.midframe) 135 self.dirsbar.pack(side=LEFT, fill=Y) 136 self.dirs = Listbox(self.midframe, exportselection=0, 137 yscrollcommand=(self.dirsbar, 'set')) 138 self.dirs.pack(side=LEFT, expand=YES, fill=BOTH) 139 self.dirsbar.config(command=(self.dirs, 'yview')) 140 btags = self.dirs.bindtags() 141 self.dirs.bindtags(btags[1:] + btags[:1]) 142 self.dirs.bind('<ButtonRelease-1>', self.dirs_select_event) 143 self.dirs.bind('<Double-ButtonRelease-1>', self.dirs_double_event) 144 145 self.ok_button = Button(self.botframe, 146 text="OK", 147 command=self.ok_command) 148 self.ok_button.pack(side=LEFT) 149 self.filter_button = Button(self.botframe, 150 text="Filter", 151 command=self.filter_command) 152 self.filter_button.pack(side=LEFT, expand=YES) 153 self.cancel_button = Button(self.botframe, 154 text="Cancel", 155 command=self.cancel_command) 156 self.cancel_button.pack(side=RIGHT) 157 158 self.top.protocol('WM_DELETE_WINDOW', self.cancel_command) 159 # XXX Are the following okay for a general audience? 160 self.top.bind('<Alt-w>', self.cancel_command) 161 self.top.bind('<Alt-W>', self.cancel_command)
162
163 - def go(self, initialdir=os.curdir, pattern="*", initialfile="", key=None):
164 if key is not None and key in dialogstates: 165 self.directory, pattern = dialogstates[key] 166 else: 167 initialdir = os.path.expanduser(initialdir) 168 if os.path.isdir(initialdir): 169 self.directory = initialdir 170 else: 171 self.directory, initialfile = os.path.split(initialdir) 172 self.set_filter(self.directory, pattern) 173 self.set_selection(initialfile) 174 self.filter_command() 175 self.selection.focus_set() 176 self.top.grab_set() 177 self.how = None 178 self.top.mainloop() # Exited by self.quit(how) 179 if key: 180 directory, pattern = self.get_filter() 181 if self.how: 182 directory = os.path.dirname(self.how) 183 dialogstates[key] = directory, pattern 184 self.top.destroy() 185 return (self.how, self.mode)
186
187 - def quit(self, how=None):
188 self.how = how 189 self.top.quit() # Exit mainloop()
190
191 - def dirs_double_event(self, event):
192 self.filter_command()
193
194 - def dirs_select_event(self, event):
195 dir, pat = self.get_filter() 196 subdir = self.dirs.get('active') 197 dir = os.path.normpath(os.path.join(self.directory, subdir)) 198 self.set_filter(dir, pat)
199
200 - def files_double_event(self, event):
201 self.ok_command()
202
203 - def files_select_event(self, event):
204 file = self.files.get('active') 205 self.set_selection(file)
206
207 - def ok_event(self, event):
208 self.ok_command()
209
210 - def ok_command(self):
211 self.quit(self.get_selection())
212
213 - def filter_command(self, event=None):
214 dir, pat = self.get_filter() 215 try: 216 names = os.listdir(dir) 217 except os.error: 218 self.top.bell() 219 return 220 self.directory = dir 221 self.set_filter(dir, pat) 222 if self.sortfn: 223 names.sort(self.sortfn) 224 else: 225 names.sort() 226 subdirs = [os.pardir] 227 matchingfiles = [] 228 for name in names: 229 fullname = os.path.join(dir, name) 230 if os.path.isdir(fullname): 231 subdirs.append(name) 232 elif fnmatch.fnmatch(name, pat): 233 matchingfiles.append(name) 234 self.dirs.delete(0, END) 235 for name in subdirs: 236 self.dirs.insert(END, name) 237 self.files.delete(0, END) 238 for name in matchingfiles: 239 self.files.insert(END, name) 240 head, tail = os.path.split(self.get_selection()) 241 if tail == os.curdir: tail = '' 242 self.set_selection(tail)
243
244 - def get_filter(self):
245 filter = self.filter.get() 246 filter = os.path.expanduser(filter) 247 if filter[-1:] == os.sep or os.path.isdir(filter): 248 filter = os.path.join(filter, "*") 249 return os.path.split(filter)
250
251 - def get_selection(self):
252 file = self.selection.get() 253 file = os.path.expanduser(file) 254 return file
255
256 - def cancel_command(self, event=None):
257 self.quit()
258
259 - def set_filter(self, dir, pat):
260 if not os.path.isabs(dir): 261 try: 262 pwd = os.getcwd() 263 except os.error: 264 pwd = None 265 if pwd: 266 dir = os.path.join(pwd, dir) 267 dir = os.path.normpath(dir) 268 self.filter.delete(0, END) 269 self.filter.insert(END, os.path.join(dir or os.curdir, pat or "*"))
270
271 - def set_selection(self, file):
272 self.selection.delete(0, END) 273 self.selection.insert(END, os.path.join(self.directory, file)) 274 self.selection.icursor(END) 275 self.selection.xview(END)
276 277
278 -class LoadFileDialog(FileDialog):
279 280 """File selection dialog which checks that the file exists.""" 281 282 title = "Load File ..." 283
284 - def ok_command(self):
285 file = self.get_selection() 286 if not os.path.isfile(file): 287 self.top.bell() 288 else: 289 self.mode = 'r' 290 self.quit(file)
291 292
293 -class SaveFileDialog_noappend(FileDialog):
294 295 """File selection dialog which checks that the file may be created.""" 296 297 title = "Save file as ..." 298
299 - def ok_command(self):
300 file = self.get_selection() 301 if os.path.exists(file): 302 if os.path.isdir(file): 303 self.top.bell() 304 return 305 d = Dialog(self.top, 306 title="File Exists", 307 text="Overwrite existing file %s?" % `file`, 308 bitmap='questhead', 309 default=1, 310 strings=("Yes", "Cancel")) 311 if d.num != 0: 312 return 313 else: 314 head, tail = os.path.split(file) 315 if not os.path.isdir(head): 316 self.top.bell() 317 return 318 self.mode = 'w' 319 self.quit(file)
320 321
322 -class SaveFileDialog(FileDialog):
323 324 """File selection dialog which checks that the file may be created.""" 325 326 title = "Save file as ..." 327
328 - def ok_command(self):
329 file = self.get_selection() 330 if os.path.exists(file): 331 if os.path.isdir(file): 332 self.top.bell() 333 return 334 d = Dialog(self.top, 335 title="File Exists", 336 text="Overwrite existing file %s?" % `file`, 337 bitmap='questhead', 338 default=1, 339 strings=("Overwrite", "Append", "Cancel")) 340 if d.num == 2: 341 return 342 elif d.num == 0: 343 self.mode = 'w' 344 elif d.num == 1: 345 self.mode = 'a' 346 else: 347 head, tail = os.path.split(file) 348 if not os.path.isdir(head): 349 self.top.bell() 350 return 351 self.mode = 'w' 352 self.quit(file)
353
354 -def Open(initialdir=os.curdir, initialfile='', pattern='*', 355 datafiles=None, text=None):
356 if datafiles: 357 sortfn = _comparedatafiles 358 else: 359 sortfn = None 360 361 return LoadFileDialog(sortfn=sortfn, 362 text=text).go(initialdir=initialdir, 363 initialfile=initialfile, 364 pattern=pattern)
365
366 -def SaveAs(initialdir=os.curdir, initialfile='', pattern='*', 367 append=1, datafiles=None, text=None):
368 if datafiles: 369 sortfn = _comparedatafiles 370 else: 371 sortfn = None 372 373 if append: 374 return SaveFileDialog(sortfn=sortfn, 375 text=text).go(initialdir=initialdir, 376 initialfile=initialfile, 377 pattern=pattern) 378 else: 379 return SaveFileDialog_noappend(sortfn=sortfn, 380 text=text).go(initialdir=initialdir, 381 initialfile=initialfile, 382 pattern=pattern)
383 384 385 if __name__ == '__main__': 386 print Open(initialdir=sys.argv[1], pattern='*') 387