Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | # |
2 | # FILE: DirBrowser.py | |
3 | # | |
4 | # DESCRIPTION: | |
5 | # This file provides a generic Directory browser selection widget. | |
6 | # | |
7 | # AUTHOR: MontaVista Software, Inc. <source@mvista.com> | |
8 | # | |
9 | # Copyright 2001 MontaVista Software Inc. | |
10 | # | |
11 | # This program is free software; you can redistribute it and/or modify it | |
12 | # under the terms of the GNU General Public License as published by the | |
13 | # Free Software Foundation; either version 2 of the License, or (at your | |
14 | # option) any later version. | |
15 | # | |
16 | # THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
17 | # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
18 | # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | |
19 | # NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
20 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
21 | # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
22 | # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
23 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
24 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
25 | # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
26 | # | |
27 | # You should have received a copy of the GNU General Public License along | |
28 | # with this program; if not, write to the Free Software Foundation, Inc., | |
29 | # 675 Mass Ave, Cambridge, MA 02139, USA. | |
30 | # | |
31 | ||
32 | ||
33 | import os | |
34 | import Tkinter | |
35 | import Pmw | |
36 | ||
37 | ||
38 | class DirBrowserDialog(Pmw.MegaToplevel): | |
39 | def __init__(self, parent = None, **kw): | |
40 | cwd = os.getcwd() | |
41 | # Define the megawidget options. | |
42 | INITOPT = Pmw.INITOPT | |
43 | optiondefs = ( | |
44 | ('path', cwd, None), | |
45 | ('hidedotfiles', 1, INITOPT), | |
46 | ('label', None, INITOPT), | |
47 | #('labelmargin', 0, INITOPT), | |
48 | #('labelpos', None, INITOPT), | |
49 | ('borderx', 20, INITOPT), | |
50 | ('bordery', 20, INITOPT), | |
51 | ) | |
52 | ||
53 | self.defineoptions(kw, optiondefs) | |
54 | ||
55 | # Initialise the base class (after defining the options). | |
56 | Pmw.MegaToplevel.__init__(self, parent) | |
57 | ||
58 | interior = self.interior() | |
59 | ||
60 | self.childframe = self.createcomponent('childframe', (), None, | |
61 | Tkinter.Frame, | |
62 | (interior,), | |
63 | borderwidth = 1, | |
64 | relief = 'raised', | |
65 | ) | |
66 | self.childframe.pack(expand = 1, | |
67 | fill = 'both', | |
68 | ) | |
69 | ||
70 | self.labelframe = self.createcomponent('labelframe', (), None, | |
71 | Tkinter.Frame, | |
72 | (self.childframe,), | |
73 | borderwidth = 2, | |
74 | relief = 'groove', | |
75 | ) | |
76 | self.labelframe.pack(padx = 10, pady = 10, expand = 1, fill = 'both') | |
77 | ||
78 | if self['label']: | |
79 | self.label = self.createcomponent('label', (), None, | |
80 | Tkinter.Label, | |
81 | (self.childframe,), | |
82 | text = self['label'], | |
83 | ) | |
84 | self.label.place(x = (10 + self['borderx']), y = 10, anchor = 'w') | |
85 | ||
86 | ||
87 | self.workframe = self.createcomponent('workframe', (), None, | |
88 | Tkinter.Frame, | |
89 | (self.labelframe,), | |
90 | #borderwidth = 2, | |
91 | #relief = 'groove', | |
92 | ) | |
93 | self.workframe.pack(padx = self['borderx'], | |
94 | pady = self['bordery'], | |
95 | expand = 1, | |
96 | fill = 'both', | |
97 | ) | |
98 | ||
99 | self.buttonframe = self.createcomponent('buttonframe', (), None, | |
100 | Tkinter.Frame, | |
101 | (interior,), | |
102 | borderwidth = 1, | |
103 | relief = 'raised', | |
104 | ) | |
105 | self.buttonframe.pack(expand = 0, | |
106 | fill = 'x', | |
107 | ) | |
108 | ||
109 | self.optbox = self.createcomponent('optbox', (), None, | |
110 | Pmw.OptionMenu, | |
111 | (self.workframe,), | |
112 | command = self.setpath, | |
113 | ) | |
114 | self.optbox.bind('<Configure>', self._setMinimumSize) | |
115 | ||
116 | self.listbox = self.createcomponent('listbox', (), None, | |
117 | Pmw.ScrolledListBox, | |
118 | (self.workframe,), | |
119 | dblclickcommand = self._select, | |
120 | ) | |
121 | ||
122 | path = self['path'] | |
123 | self.entry = self.createcomponent('entryfield', (), None, | |
124 | Pmw.EntryField, | |
125 | (self.workframe,), | |
126 | value = path, | |
127 | command = self.enteredpath, | |
128 | labelpos = 'nw', | |
129 | label_text = 'Current Path:', | |
130 | ) | |
131 | ||
132 | #self.createlabel(self.workframe, childCols = 1, childRows = 3) | |
133 | ||
134 | self.buttonbox = self.createcomponent('buttonbox', (), None, | |
135 | Pmw.ButtonBox, | |
136 | (self.buttonframe,), | |
137 | ) | |
138 | self.buttonbox.add('OK', text = 'OK', | |
139 | command = self.okbutton) | |
140 | self.buttonbox.add('Cancel', text = 'Cancel', | |
141 | command = self.cancelbutton) | |
142 | self.buttonbox.add('New Directory', text = 'New Directory', | |
143 | command = self.newdirbutton) | |
144 | ||
145 | self.buttonbox.alignbuttons() | |
146 | self.buttonbox.pack(expand = 1, fill = 'x') | |
147 | ||
148 | self.optbox.grid(row = 2, column = 2, sticky = 'ew') | |
149 | self.listbox.grid(row = 3, column = 2, sticky = 'news') | |
150 | self.entry.grid(row = 5, column = 2, sticky = 'ew') | |
151 | self.workframe.grid_rowconfigure(3, weight = 1) | |
152 | self.workframe.grid_rowconfigure(4, minsize = 20) | |
153 | self.workframe.grid_columnconfigure(2, weight = 1) | |
154 | ||
155 | ||
156 | self.setpath(self['path']) | |
157 | ||
158 | # Check keywords and initialise options. | |
159 | self.initialiseoptions() | |
160 | ||
161 | def setpath(self, path): | |
162 | path = os.path.abspath(os.path.expanduser(path)) | |
163 | ||
164 | if os.path.isfile(path): | |
165 | path = os.path.dirname(path) | |
166 | ||
167 | dirlist = [] | |
168 | hidedotfiles = self['hidedotfiles'] | |
169 | try: | |
170 | posix = (os.name == 'posix') | |
171 | for entry in os.listdir(path): | |
172 | entryPath = path + '/' + entry | |
173 | if hidedotfiles and entry[0] == '.': | |
174 | # skip dot files if desired | |
175 | continue | |
176 | if not os.path.isdir(entryPath): | |
177 | # skip files | |
178 | continue | |
179 | if not os.access(entryPath, os.R_OK | os.X_OK): | |
180 | # skip directories we can't enter any way | |
181 | continue | |
182 | dirlist.append(entry) | |
183 | ||
184 | except: | |
185 | self.entry.setentry(self['path']) | |
186 | return | |
187 | ||
188 | self.entry.setentry(path) | |
189 | ||
190 | self['path'] = path | |
191 | ||
192 | dirlist.sort() | |
193 | if path != '/': | |
194 | dirlist.insert(0, '..') | |
195 | ||
196 | self.listbox.setlist(dirlist) | |
197 | pathlist = [] | |
198 | while path != '/': | |
199 | pathlist.append(path) | |
200 | path = os.path.dirname(path) | |
201 | pathlist.append('/') | |
202 | self.optbox.setitems(pathlist, 0) | |
203 | ||
204 | def _setMinimumSize(self, event): | |
205 | # If the optionmenu changes width, make sure it does not | |
206 | # shrink later. | |
207 | owidth = self.optbox.winfo_width() | |
208 | self.workframe.grid_columnconfigure(2, minsize = owidth) | |
209 | ||
210 | def _select(self): | |
211 | sel = self.listbox.getcurselection() | |
212 | if self['path'] == '/': | |
213 | self['path'] = '' | |
214 | if len(sel) > 0: | |
215 | if sel[0] == '..': | |
216 | self.setpath(os.path.dirname(self['path'])) | |
217 | else: | |
218 | self.setpath(self['path'] + '/' + sel[0]) | |
219 | ||
220 | ||
221 | def getcurpath(self): | |
222 | return self['path'] | |
223 | ||
224 | def enteredpath(self): | |
225 | self.setpath(self.entry.get()) | |
226 | ||
227 | def okbutton(self): | |
228 | self.deactivate(self['path']) | |
229 | ||
230 | def cancelbutton(self): | |
231 | self.deactivate(None) | |
232 | ||
233 | def newdirbutton(self): | |
234 | CreateDirectoryPopup(self.interior(), self['path']) | |
235 | self.setpath(self['path']) | |
236 | ||
237 | ||
238 | ||
239 | class CreateDirectoryPopup: | |
240 | def __init__(self, parent, path): | |
241 | self.path = path | |
242 | self.parent = parent | |
243 | self.newdirpopup = Pmw.PromptDialog(parent, | |
244 | buttons = ('OK', 'Cancel'), | |
245 | defaultbutton = 'OK', | |
246 | title = 'New Directory', | |
247 | entryfield_labelpos = 'nw', | |
248 | label_text = 'Enter new directory name for:\n%s'%self.path, | |
249 | command = self._buttonpress | |
250 | ) | |
251 | ||
252 | self.newdirpopup.activate() | |
253 | ||
254 | def _buttonpress(self, button): | |
255 | if button == 'OK': | |
256 | newdirname = self.newdirpopup.get() | |
257 | dirlist = os.listdir(self.path) | |
258 | if newdirname in dirlist: | |
259 | ErrorPopup(self.parent, | |
260 | 'Error: "%s", already exists as a file or directory.'%newdirname) | |
261 | else: | |
262 | try: | |
263 | os.mkdir(self.path + '/' + newdirname) | |
264 | except: | |
265 | ErrorPopup(self.parent, | |
266 | 'Error: Could not create directory: "%s"'%newdirname) | |
267 | else: | |
268 | self.newdirpopup.deactivate() | |
269 | else: | |
270 | self.newdirpopup.deactivate() | |
271 | ||
272 | ||
273 | def ErrorPopup(parent, message): | |
274 | error = Pmw.MessageDialog(parent, title = 'Error', | |
275 | message_text = message, | |
276 | defaultbutton = 0, | |
277 | ) | |
278 | error.activate() | |
279 | ||
280 | if __name__ == '__main__': | |
281 | ||
282 | rootWin = Tkinter.Tk() | |
283 | ||
284 | Pmw.initialise() | |
285 | ||
286 | rootWin.title('Directory Browser Dialog Demo') | |
287 | ||
288 | def buildBrowser(): | |
289 | # Create the hierarchical directory browser widget | |
290 | dirBrowserDialog = DirBrowserDialog(rootWin, | |
291 | #labelpos = 'nw', | |
292 | label = 'Select a directory', | |
293 | title = 'Directory Selector', | |
294 | #path = '~', | |
295 | #hidedotfiles = 0, | |
296 | ) | |
297 | dir = dirBrowserDialog.activate() | |
298 | print 'Selected Directory:', dir | |
299 | ||
300 | dirButton = Tkinter.Button(rootWin, text="Browser", command=buildBrowser) | |
301 | dirButton.pack(side = 'left', padx = 10, pady = 10) | |
302 | ||
303 | exitButton = Tkinter.Button(rootWin, text="Quit", command=rootWin.quit) | |
304 | exitButton.pack(side = 'left', padx = 10, pady = 10) | |
305 | ||
306 | rootWin.mainloop() |