1
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
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
53 import pypedebug
54 pypedebug.get_traceback(1)
55
56 if a > b:
57 return 1
58 else:
59 return -1
60
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
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
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
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
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()
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()
190
193
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
202
206
209
212
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
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
252 file = self.selection.get()
253 file = os.path.expanduser(file)
254 return file
255
258
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
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
279
280 """File selection dialog which checks that the file exists."""
281
282 title = "Load File ..."
283
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
294
295 """File selection dialog which checks that the file may be created."""
296
297 title = "Save file as ..."
298
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
323
324 """File selection dialog which checks that the file may be created."""
325
326 title = "Save file as ..."
327
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