]> SALOME platform Git repositories - tools/eficas.git/blob - Pmw/Pmw_1_2/contrib/PmwFileDialog.py
Salome HOME
Modif V6_4_°
[tools/eficas.git] / Pmw / Pmw_1_2 / contrib / PmwFileDialog.py
1 #
2 __version__ = '$Id: PmwFileDialog.py,v 1.2 2002/08/23 15:03:35 gregm Exp $'
3 #
4 # Filename dialogs using Pmw
5 #
6 # (C) Rob W.W. Hooft, Nonius BV, 1998
7 #
8 # Modifications:
9 #
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
14 #
15 # No Guarantees. Distribute Freely. 
16 # Please send bug-fixes/patches/features to <r.hooft@euromail.com>
17 #
18 ################################################################################
19 import os,fnmatch,time
20 import Tkinter,Pmw
21 #Pmw.setversion("0.8.5")
22
23 def _errorpop(master,text):
24     d=Pmw.MessageDialog(master,
25                         title="Error", 
26                         message_text=text,
27                         buttons=("OK",))
28     d.component('message').pack(ipadx=15,ipady=15)
29     d.activate()
30     d.destroy()
31     
32 class PmwFileDialog(Pmw.Dialog):
33     """File Dialog using Pmw"""
34     def __init__(self, parent = None, **kw):
35         # Define the megawidget options.
36         optiondefs = (
37             ('filter',    '*',              self.newfilter),
38             ('directory', os.getcwd(),      self.newdir),
39             ('filename',  '',               self.newfilename),
40             ('historylen',10,               None),
41             ('command',   None,             None),
42             ('info',      None,             None),
43             )
44         self.defineoptions(kw, optiondefs)
45         # Initialise base class (after defining options).
46         Pmw.Dialog.__init__(self, parent)
47
48         self.withdraw()
49
50         # Create the components.
51         interior = self.interior()
52
53         if self['info'] is not None:
54             rowoffset=1
55             dn = self.infotxt()
56             dn.grid(row=0,column=0,columnspan=2,padx=3,pady=3)
57         else:
58             rowoffset=0
59
60         dn = self.mkdn()
61         dn.grid(row=0+rowoffset,column=0,columnspan=2,padx=3,pady=3)
62         del dn
63
64         # Create the directory list component.
65         dnb = self.mkdnb()
66         dnb.grid(row=1+rowoffset,column=0,sticky='news',padx=3,pady=3)
67         del dnb
68
69         # Create the filename list component.
70         fnb = self.mkfnb()
71         fnb.grid(row=1+rowoffset,column=1,sticky='news',padx=3,pady=3)
72         del fnb
73
74         # Create the filter entry
75         ft = self.mkft()
76         ft.grid(row=2+rowoffset,column=0,columnspan=2,padx=3,pady=3)
77         del ft
78
79         # Create the filename entry
80         fn = self.mkfn()
81         fn.grid(row=3+rowoffset,column=0,columnspan=2,padx=3,pady=3)
82         fn.bind('<Return>',self.okbutton)
83         del fn
84
85         # Buttonbox already exists
86         bb=self.component('buttonbox')
87         bb.add('OK',command=self.okbutton)
88         bb.add('Cancel',command=self.cancelbutton)
89         del bb
90
91         Pmw.alignlabels([self.component('filename'),
92                          self.component('filter'),
93                          self.component('dirname')])
94
95     def infotxt(self):
96         """ Make information block component at the top """
97         return self.createcomponent(
98                 'infobox',
99                 (), None,
100                 Tkinter.Label, (self.interior(),),
101                 width=51,
102                 relief='groove',
103                 foreground='darkblue',
104                 justify='left',
105                 text=self['info']
106             )
107
108     def mkdn(self):
109         """Make directory name component"""
110         return self.createcomponent(
111             'dirname',
112             (), None,
113             Pmw.ComboBox, (self.interior(),),
114             entryfield_value=self['directory'],
115             entryfield_entry_width=40,
116             entryfield_validate=self.dirvalidate,
117             selectioncommand=self.setdir,
118             labelpos='w',
119             label_text='Directory:')
120
121     def mkdnb(self):
122         """Make directory name box"""
123         return self.createcomponent(
124             'dirnamebox',
125             (), None,
126             Pmw.ScrolledListBox, (self.interior(),),
127             label_text='directories',
128             labelpos='n',
129             hscrollmode='none',
130             dblclickcommand=self.selectdir)
131
132     def mkft(self):
133         """Make filter"""
134         return self.createcomponent(
135             'filter',
136             (), None,
137             Pmw.ComboBox, (self.interior(),),
138             entryfield_value=self['filter'],
139             entryfield_entry_width=40,
140             selectioncommand=self.setfilter,
141             labelpos='w',
142             label_text='Filter:')
143
144     def mkfnb(self):
145         """Make filename list box"""
146         return self.createcomponent(
147             'filenamebox',
148             (), None,
149             Pmw.ScrolledListBox, (self.interior(),),
150             label_text='files',
151             labelpos='n',
152             hscrollmode='none',
153             selectioncommand=self.singleselectfile,
154             dblclickcommand=self.selectfile)
155
156     def mkfn(self):
157         """Make file name entry"""
158         return self.createcomponent(
159             'filename',
160             (), None,
161             Pmw.ComboBox, (self.interior(),),
162             entryfield_value=self['filename'],
163             entryfield_entry_width=40,
164             entryfield_validate=self.filevalidate,
165             selectioncommand=self.setfilename,
166             labelpos='w',
167             label_text='Filename:')
168     
169     def dirvalidate(self,string):
170         if os.path.isdir(string):
171             return Pmw.OK
172         else:
173             return Pmw.PARTIAL
174         
175     def filevalidate(self,string):
176         if string=='':
177             return Pmw.PARTIAL
178         elif os.path.isfile(string):
179             return Pmw.OK
180         elif os.path.exists(string):
181             return Pmw.PARTIAL
182         else:
183             return Pmw.OK
184         
185     def okbutton(self):
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()
189         self.setfilename(fn)
190         if self.validate(fn):
191             self.canceled=0
192             self.deactivate()
193
194     def cancelbutton(self):
195         """Cancel the operation"""
196         self.canceled=1
197         self.deactivate()
198
199     def tidy(self,w,v):
200         """Insert text v into the entry and at the top of the list of 
201            the combobox w, remove duplicates"""
202         if not v:
203             return
204         entry=w.component('entry')
205         entry.delete(0,'end')
206         entry.insert(0,v)
207         list=w.component('scrolledlist')
208         list.insert(0,v)
209         index=1
210         while index<list.index('end'):
211             k=list.get(index)
212             if k==v or index>self['historylen']:
213                 list.delete(index)
214             else:
215                 index=index+1
216         w.checkentry()
217
218     def setfilename(self,value):
219         if not value:
220             return
221         value=os.path.join(self['directory'],value)
222         dir,fil=os.path.split(value)
223         self.configure(directory=dir,filename=value)
224         
225         c=self['command']
226         if callable(c):
227             c()
228
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'])
232         
233     def setfilter(self,value):
234         self.configure(filter=value)
235
236     def newfilter(self):
237         """Make sure a newly set filter makes it into the combobox list"""
238         self.tidy(self.component('filter'),self['filter'])
239         self.fillit()
240
241     def setdir(self,value):
242         self.configure(directory=value)
243
244     def newdir(self):
245         """Make sure a newly set dirname makes it into the combobox list"""
246         self.tidy(self.component('dirname'),self['directory'])
247         self.fillit()
248
249     def singleselectfile(self):
250         """Single click in file listbox. Move file to "filename" combobox"""
251         cs=self.component('filenamebox').curselection()
252         if cs!=():
253             value=self.component('filenamebox').get(cs)
254             self.setfilename(value)
255
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)
261         if value:
262             self.okbutton()
263
264     def selectdir(self):
265         """Take selected directory from the dirnamebox into the dirname"""
266         cs=self.component('dirnamebox').curselection()
267         if cs!=():
268             value=self.component('dirnamebox').get(cs)
269             dir=self['directory']
270             if not dir:
271                 dir=os.getcwd()
272             if value:
273                 if value=='..':
274                     dir=os.path.split(dir)[0]
275                 else:
276                     dir=os.path.join(dir,value)
277             self.configure(directory=dir)
278             self.fillit()
279
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 
284            value is None)"""
285         if directory!=None:
286             self.configure(directory=directory)
287         if filter!=None:
288             self.configure(filter=filter)
289         self.fillit()
290         self.canceled=1 # Needed for when user kills dialog window
291         self.activate()
292         if self.canceled:
293             return None
294         else:
295             return self.component('filename').get()
296
297     lastdir=""
298     lastfilter=None
299     lasttime=0
300     def fillit(self):
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]:
304             return
305         self.lastdir=self['directory']
306         self.lastfilter=self['filter']
307         self.lasttime=time.time()
308         dir=self['directory']
309         if not dir:
310             dir=os.getcwd()
311         dirs=['..']
312         files=[]
313         try:
314             fl=os.listdir(dir)
315             fl.sort()
316         except os.error,arg:
317             if arg[0] in (2,20):
318                 return
319             raise
320         for f in fl:
321             if os.path.isdir(os.path.join(dir,f)):
322                 dirs.append(f)
323             else:
324                 filter=self['filter']
325                 if not filter:
326                     filter='*'
327                 if fnmatch.fnmatch(f,filter):
328                     files.append(f)
329         self.component('filenamebox').setlist(files)
330         self.component('dirnamebox').setlist(dirs)
331     
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 
336            exist"""
337         return 1
338
339 class PmwDirDialog(PmwFileDialog):
340     """Directory Dialog using Pmw"""
341     def __init__(self, parent = None, **kw):
342         # Define the megawidget options.
343         optiondefs = (
344             ('directory', os.getcwd(),      self.newdir),
345             ('historylen',10,               None),
346             ('command',   None,             None),
347             ('info',      None,             None),
348             )
349         self.defineoptions(kw, optiondefs)
350         # Initialise base class (after defining options).
351         Pmw.Dialog.__init__(self, parent)
352
353         self.withdraw()
354
355         # Create the components.
356         interior = self.interior()
357
358         if self['info'] is not None:
359             rowoffset=1
360             dn = self.infotxt()
361             dn.grid(row=0,column=0,columnspan=2,padx=3,pady=3)
362         else:
363             rowoffset=0
364
365         dn = self.mkdn()
366         dn.grid(row=1+rowoffset,column=0,columnspan=2,padx=3,pady=3)
367         dn.bind('<Return>',self.okbutton)
368         del dn
369
370         # Create the directory list component.
371         dnb = self.mkdnb()
372         dnb.grid(row=0+rowoffset,column=0,columnspan=2,sticky='news',padx=3,pady=3)
373         del dnb
374
375         # Buttonbox already exists
376         bb=self.component('buttonbox')
377         bb.add('OK',command=self.okbutton)
378         bb.add('Cancel',command=self.cancelbutton)
379         del bb
380
381     lastdir=""
382     def fillit(self):
383         """Get the directory list and show it in the two listboxes"""
384         # Do not run unnecesarily
385         if self.lastdir==self['directory']:
386             return
387         self.lastdir=self['directory']
388         dir=self['directory']
389         if not dir:
390             dir=os.getcwd()
391         dirs=['..']
392         try:
393             fl=os.listdir(dir)
394             fl.sort()
395         except os.error,arg:
396             if arg[0] in (2,20):
397                 return
398             raise
399         for f in fl:
400             if os.path.isdir(os.path.join(dir,f)):
401                 dirs.append(f)
402         self.component('dirnamebox').setlist(dirs)
403
404     def okbutton(self):
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):
410             self.canceled=0
411             self.deactivate()
412     
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 
417            value is None)"""
418         if directory!=None:
419             self.configure(directory=directory)
420         self.fillit()
421         self.activate()
422         if self.canceled:
423             return None
424         else:
425             return self.component('dirname').get()
426
427     def dirvalidate(self,string):
428         if os.path.isdir(string):
429             return Pmw.OK
430         elif os.path.exists(string):
431             return Pmw.PARTIAL
432         else:
433             return Pmw.OK
434
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 
439            exist"""
440         if filename=='':
441             _errorpop(self.interior(),"Empty filename")
442             return 0
443         if os.path.isdir(filename) or not os.path.exists(filename):
444             return 1
445         else:
446             _errorpop(self.interior(),"This is not a directory")
447             return 0
448
449 class PmwExistingFileDialog(PmwFileDialog):
450     def filevalidate(self,string):
451         if os.path.isfile(string):
452             return Pmw.OK
453         else:
454             return Pmw.PARTIAL
455         
456     def validate(self,filename):
457         if os.path.isfile(filename):
458             return 1
459         elif os.path.exists(filename):
460             _errorpop(self.interior(),"This is not a plain file")
461             return 0
462         else:
463             _errorpop(self.interior(),"Please select an existing file")
464             return 0
465
466 class PmwExistingDirDialog(PmwDirDialog):
467     def dirvalidate(self,string):
468         if os.path.isdir(string):
469             return Pmw.OK
470         else:
471             return Pmw.PARTIAL
472
473     def validate(self,filename):
474         if os.path.isdir(filename):
475             return 1
476         elif os.path.exists(filename):
477             _errorpop(self.interior(),"This is not a directory")
478             return 0
479         else:
480             _errorpop(self.interior(),"Please select an existing directory")
481     
482 if __name__=="__main__":
483     root=Tkinter.Tk()
484     root.withdraw()
485     Pmw.initialise()
486
487     f0=PmwFileDialog(root)
488     f0.title('File name dialog')
489     n=f0.askfilename()
490     print '\nFilename : ',repr(n),'\n'
491
492     f1=PmwDirDialog(root,info='This is a directory dialog')
493     f1.title('Directory name dialog')
494     while 1:
495         n=f1.askfilename()
496         if n is None:
497             break
498         print "Dirname : ",repr(n)