2 __version__ = '$Id: PmwFileDialog.py,v 1.2 2002/08/23 15:03:35 gregm Exp $'
4 # Filename dialogs using Pmw
6 # (C) Rob W.W. Hooft, Nonius BV, 1998
10 # J. Willem M. Nissink, Cambridge Crystallographic Data Centre, 8/2002
11 # Added optional information pane at top of dialog; if option
12 # 'info' is specified, the text given will be shown (in blue).
13 # Modified example to show both file and directory-type dialog
15 # No Guarantees. Distribute Freely.
16 # Please send bug-fixes/patches/features to <r.hooft@euromail.com>
18 ################################################################################
19 import os,fnmatch,time
21 #Pmw.setversion("0.8.5")
23 def _errorpop(master,text):
24 d=Pmw.MessageDialog(master,
28 d.component('message').pack(ipadx=15,ipady=15)
32 class PmwFileDialog(Pmw.Dialog):
33 """File Dialog using Pmw"""
34 def __init__(self, parent = None, **kw):
35 # Define the megawidget options.
37 ('filter', '*', self.newfilter),
38 ('directory', os.getcwd(), self.newdir),
39 ('filename', '', self.newfilename),
40 ('historylen',10, None),
41 ('command', None, None),
44 self.defineoptions(kw, optiondefs)
45 # Initialise base class (after defining options).
46 Pmw.Dialog.__init__(self, parent)
50 # Create the components.
51 interior = self.interior()
53 if self['info'] is not None:
56 dn.grid(row=0,column=0,columnspan=2,padx=3,pady=3)
61 dn.grid(row=0+rowoffset,column=0,columnspan=2,padx=3,pady=3)
64 # Create the directory list component.
66 dnb.grid(row=1+rowoffset,column=0,sticky='news',padx=3,pady=3)
69 # Create the filename list component.
71 fnb.grid(row=1+rowoffset,column=1,sticky='news',padx=3,pady=3)
74 # Create the filter entry
76 ft.grid(row=2+rowoffset,column=0,columnspan=2,padx=3,pady=3)
79 # Create the filename entry
81 fn.grid(row=3+rowoffset,column=0,columnspan=2,padx=3,pady=3)
82 fn.bind('<Return>',self.okbutton)
85 # Buttonbox already exists
86 bb=self.component('buttonbox')
87 bb.add('OK',command=self.okbutton)
88 bb.add('Cancel',command=self.cancelbutton)
91 Pmw.alignlabels([self.component('filename'),
92 self.component('filter'),
93 self.component('dirname')])
96 """ Make information block component at the top """
97 return self.createcomponent(
100 Tkinter.Label, (self.interior(),),
103 foreground='darkblue',
109 """Make directory name component"""
110 return self.createcomponent(
113 Pmw.ComboBox, (self.interior(),),
114 entryfield_value=self['directory'],
115 entryfield_entry_width=40,
116 entryfield_validate=self.dirvalidate,
117 selectioncommand=self.setdir,
119 label_text='Directory:')
122 """Make directory name box"""
123 return self.createcomponent(
126 Pmw.ScrolledListBox, (self.interior(),),
127 label_text='directories',
130 dblclickcommand=self.selectdir)
134 return self.createcomponent(
137 Pmw.ComboBox, (self.interior(),),
138 entryfield_value=self['filter'],
139 entryfield_entry_width=40,
140 selectioncommand=self.setfilter,
142 label_text='Filter:')
145 """Make filename list box"""
146 return self.createcomponent(
149 Pmw.ScrolledListBox, (self.interior(),),
153 selectioncommand=self.singleselectfile,
154 dblclickcommand=self.selectfile)
157 """Make file name entry"""
158 return self.createcomponent(
161 Pmw.ComboBox, (self.interior(),),
162 entryfield_value=self['filename'],
163 entryfield_entry_width=40,
164 entryfield_validate=self.filevalidate,
165 selectioncommand=self.setfilename,
167 label_text='Filename:')
169 def dirvalidate(self,string):
170 if os.path.isdir(string):
175 def filevalidate(self,string):
178 elif os.path.isfile(string):
180 elif os.path.exists(string):
186 """OK action: user thinks he has input valid data and wants to
187 proceed. This is also called by <Return> in the filename entry"""
188 fn=self.component('filename').get()
190 if self.validate(fn):
194 def cancelbutton(self):
195 """Cancel the operation"""
200 """Insert text v into the entry and at the top of the list of
201 the combobox w, remove duplicates"""
204 entry=w.component('entry')
205 entry.delete(0,'end')
207 list=w.component('scrolledlist')
210 while index<list.index('end'):
212 if k==v or index>self['historylen']:
218 def setfilename(self,value):
221 value=os.path.join(self['directory'],value)
222 dir,fil=os.path.split(value)
223 self.configure(directory=dir,filename=value)
229 def newfilename(self):
230 """Make sure a newly set filename makes it into the combobox list"""
231 self.tidy(self.component('filename'),self['filename'])
233 def setfilter(self,value):
234 self.configure(filter=value)
237 """Make sure a newly set filter makes it into the combobox list"""
238 self.tidy(self.component('filter'),self['filter'])
241 def setdir(self,value):
242 self.configure(directory=value)
245 """Make sure a newly set dirname makes it into the combobox list"""
246 self.tidy(self.component('dirname'),self['directory'])
249 def singleselectfile(self):
250 """Single click in file listbox. Move file to "filename" combobox"""
251 cs=self.component('filenamebox').curselection()
253 value=self.component('filenamebox').get(cs)
254 self.setfilename(value)
256 def selectfile(self):
257 """Take the selected file from the filename, normalize it, and OK"""
258 self.singleselectfile()
259 value=self.component('filename').get()
260 self.setfilename(value)
265 """Take selected directory from the dirnamebox into the dirname"""
266 cs=self.component('dirnamebox').curselection()
268 value=self.component('dirnamebox').get(cs)
269 dir=self['directory']
274 dir=os.path.split(dir)[0]
276 dir=os.path.join(dir,value)
277 self.configure(directory=dir)
280 def askfilename(self,directory=None,filter=None):
281 """The actual client function. Activates the dialog, and
282 returns only after a valid filename has been entered
283 (return value is that filename) or when canceled (return
286 self.configure(directory=directory)
288 self.configure(filter=filter)
290 self.canceled=1 # Needed for when user kills dialog window
295 return self.component('filename').get()
301 """Get the directory list and show it in the two listboxes"""
302 # Do not run unnecesarily
303 if self.lastdir==self['directory'] and self.lastfilter==self['filter'] and self.lasttime>os.stat(self.lastdir)[8]:
305 self.lastdir=self['directory']
306 self.lastfilter=self['filter']
307 self.lasttime=time.time()
308 dir=self['directory']
321 if os.path.isdir(os.path.join(dir,f)):
324 filter=self['filter']
327 if fnmatch.fnmatch(f,filter):
329 self.component('filenamebox').setlist(files)
330 self.component('dirnamebox').setlist(dirs)
332 def validate(self,filename):
333 """Validation function. Should return 1 if the filename is valid,
334 0 if invalid. May pop up dialogs to tell user why. Especially
335 suited to subclasses: i.e. only return 1 if the file does/doesn't
339 class PmwDirDialog(PmwFileDialog):
340 """Directory Dialog using Pmw"""
341 def __init__(self, parent = None, **kw):
342 # Define the megawidget options.
344 ('directory', os.getcwd(), self.newdir),
345 ('historylen',10, None),
346 ('command', None, None),
347 ('info', None, None),
349 self.defineoptions(kw, optiondefs)
350 # Initialise base class (after defining options).
351 Pmw.Dialog.__init__(self, parent)
355 # Create the components.
356 interior = self.interior()
358 if self['info'] is not None:
361 dn.grid(row=0,column=0,columnspan=2,padx=3,pady=3)
366 dn.grid(row=1+rowoffset,column=0,columnspan=2,padx=3,pady=3)
367 dn.bind('<Return>',self.okbutton)
370 # Create the directory list component.
372 dnb.grid(row=0+rowoffset,column=0,columnspan=2,sticky='news',padx=3,pady=3)
375 # Buttonbox already exists
376 bb=self.component('buttonbox')
377 bb.add('OK',command=self.okbutton)
378 bb.add('Cancel',command=self.cancelbutton)
383 """Get the directory list and show it in the two listboxes"""
384 # Do not run unnecesarily
385 if self.lastdir==self['directory']:
387 self.lastdir=self['directory']
388 dir=self['directory']
400 if os.path.isdir(os.path.join(dir,f)):
402 self.component('dirnamebox').setlist(dirs)
405 """OK action: user thinks he has input valid data and wants to
406 proceed. This is also called by <Return> in the dirname entry"""
407 fn=self.component('dirname').get()
408 self.configure(directory=fn)
409 if self.validate(fn):
413 def askfilename(self,directory=None):
414 """The actual client function. Activates the dialog, and
415 returns only after a valid filename has been entered
416 (return value is that filename) or when canceled (return
419 self.configure(directory=directory)
425 return self.component('dirname').get()
427 def dirvalidate(self,string):
428 if os.path.isdir(string):
430 elif os.path.exists(string):
435 def validate(self,filename):
436 """Validation function. Should return 1 if the filename is valid,
437 0 if invalid. May pop up dialogs to tell user why. Especially
438 suited to subclasses: i.e. only return 1 if the file does/doesn't
441 _errorpop(self.interior(),"Empty filename")
443 if os.path.isdir(filename) or not os.path.exists(filename):
446 _errorpop(self.interior(),"This is not a directory")
449 class PmwExistingFileDialog(PmwFileDialog):
450 def filevalidate(self,string):
451 if os.path.isfile(string):
456 def validate(self,filename):
457 if os.path.isfile(filename):
459 elif os.path.exists(filename):
460 _errorpop(self.interior(),"This is not a plain file")
463 _errorpop(self.interior(),"Please select an existing file")
466 class PmwExistingDirDialog(PmwDirDialog):
467 def dirvalidate(self,string):
468 if os.path.isdir(string):
473 def validate(self,filename):
474 if os.path.isdir(filename):
476 elif os.path.exists(filename):
477 _errorpop(self.interior(),"This is not a directory")
480 _errorpop(self.interior(),"Please select an existing directory")
482 if __name__=="__main__":
487 f0=PmwFileDialog(root)
488 f0.title('File name dialog')
490 print '\nFilename : ',repr(n),'\n'
492 f1=PmwDirDialog(root,info='This is a directory dialog')
493 f1.title('Directory name dialog')
498 print "Dirname : ",repr(n)