307 lines
12 KiB
Python
307 lines
12 KiB
Python
|
#
|
||
|
# FILE: DirBrowser.py
|
||
|
#
|
||
|
# DESCRIPTION:
|
||
|
# This file provides a generic Directory browser selection widget.
|
||
|
#
|
||
|
# AUTHOR: MontaVista Software, Inc. <source@mvista.com>
|
||
|
#
|
||
|
# Copyright 2001 MontaVista Software Inc.
|
||
|
#
|
||
|
# This program is free software; you can redistribute it and/or modify it
|
||
|
# under the terms of the GNU General Public License as published by the
|
||
|
# Free Software Foundation; either version 2 of the License, or (at your
|
||
|
# option) any later version.
|
||
|
#
|
||
|
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||
|
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||
|
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||
|
# NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||
|
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||
|
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||
|
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||
|
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||
|
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
#
|
||
|
# You should have received a copy of the GNU General Public License along
|
||
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||
|
# 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
|
#
|
||
|
|
||
|
|
||
|
import os
|
||
|
import Tkinter
|
||
|
import Pmw
|
||
|
|
||
|
|
||
|
class DirBrowserDialog(Pmw.MegaToplevel):
|
||
|
def __init__(self, parent = None, **kw):
|
||
|
cwd = os.getcwd()
|
||
|
# Define the megawidget options.
|
||
|
INITOPT = Pmw.INITOPT
|
||
|
optiondefs = (
|
||
|
('path', cwd, None),
|
||
|
('hidedotfiles', 1, INITOPT),
|
||
|
('label', None, INITOPT),
|
||
|
#('labelmargin', 0, INITOPT),
|
||
|
#('labelpos', None, INITOPT),
|
||
|
('borderx', 20, INITOPT),
|
||
|
('bordery', 20, INITOPT),
|
||
|
)
|
||
|
|
||
|
self.defineoptions(kw, optiondefs)
|
||
|
|
||
|
# Initialise the base class (after defining the options).
|
||
|
Pmw.MegaToplevel.__init__(self, parent)
|
||
|
|
||
|
interior = self.interior()
|
||
|
|
||
|
self.childframe = self.createcomponent('childframe', (), None,
|
||
|
Tkinter.Frame,
|
||
|
(interior,),
|
||
|
borderwidth = 1,
|
||
|
relief = 'raised',
|
||
|
)
|
||
|
self.childframe.pack(expand = 1,
|
||
|
fill = 'both',
|
||
|
)
|
||
|
|
||
|
self.labelframe = self.createcomponent('labelframe', (), None,
|
||
|
Tkinter.Frame,
|
||
|
(self.childframe,),
|
||
|
borderwidth = 2,
|
||
|
relief = 'groove',
|
||
|
)
|
||
|
self.labelframe.pack(padx = 10, pady = 10, expand = 1, fill = 'both')
|
||
|
|
||
|
if self['label']:
|
||
|
self.label = self.createcomponent('label', (), None,
|
||
|
Tkinter.Label,
|
||
|
(self.childframe,),
|
||
|
text = self['label'],
|
||
|
)
|
||
|
self.label.place(x = (10 + self['borderx']), y = 10, anchor = 'w')
|
||
|
|
||
|
|
||
|
self.workframe = self.createcomponent('workframe', (), None,
|
||
|
Tkinter.Frame,
|
||
|
(self.labelframe,),
|
||
|
#borderwidth = 2,
|
||
|
#relief = 'groove',
|
||
|
)
|
||
|
self.workframe.pack(padx = self['borderx'],
|
||
|
pady = self['bordery'],
|
||
|
expand = 1,
|
||
|
fill = 'both',
|
||
|
)
|
||
|
|
||
|
self.buttonframe = self.createcomponent('buttonframe', (), None,
|
||
|
Tkinter.Frame,
|
||
|
(interior,),
|
||
|
borderwidth = 1,
|
||
|
relief = 'raised',
|
||
|
)
|
||
|
self.buttonframe.pack(expand = 0,
|
||
|
fill = 'x',
|
||
|
)
|
||
|
|
||
|
self.optbox = self.createcomponent('optbox', (), None,
|
||
|
Pmw.OptionMenu,
|
||
|
(self.workframe,),
|
||
|
command = self.setpath,
|
||
|
)
|
||
|
self.optbox.bind('<Configure>', self._setMinimumSize)
|
||
|
|
||
|
self.listbox = self.createcomponent('listbox', (), None,
|
||
|
Pmw.ScrolledListBox,
|
||
|
(self.workframe,),
|
||
|
dblclickcommand = self._select,
|
||
|
)
|
||
|
|
||
|
path = self['path']
|
||
|
self.entry = self.createcomponent('entryfield', (), None,
|
||
|
Pmw.EntryField,
|
||
|
(self.workframe,),
|
||
|
value = path,
|
||
|
command = self.enteredpath,
|
||
|
labelpos = 'nw',
|
||
|
label_text = 'Current Path:',
|
||
|
)
|
||
|
|
||
|
#self.createlabel(self.workframe, childCols = 1, childRows = 3)
|
||
|
|
||
|
self.buttonbox = self.createcomponent('buttonbox', (), None,
|
||
|
Pmw.ButtonBox,
|
||
|
(self.buttonframe,),
|
||
|
)
|
||
|
self.buttonbox.add('OK', text = 'OK',
|
||
|
command = self.okbutton)
|
||
|
self.buttonbox.add('Cancel', text = 'Cancel',
|
||
|
command = self.cancelbutton)
|
||
|
self.buttonbox.add('New Directory', text = 'New Directory',
|
||
|
command = self.newdirbutton)
|
||
|
|
||
|
self.buttonbox.alignbuttons()
|
||
|
self.buttonbox.pack(expand = 1, fill = 'x')
|
||
|
|
||
|
self.optbox.grid(row = 2, column = 2, sticky = 'ew')
|
||
|
self.listbox.grid(row = 3, column = 2, sticky = 'news')
|
||
|
self.entry.grid(row = 5, column = 2, sticky = 'ew')
|
||
|
self.workframe.grid_rowconfigure(3, weight = 1)
|
||
|
self.workframe.grid_rowconfigure(4, minsize = 20)
|
||
|
self.workframe.grid_columnconfigure(2, weight = 1)
|
||
|
|
||
|
|
||
|
self.setpath(self['path'])
|
||
|
|
||
|
# Check keywords and initialise options.
|
||
|
self.initialiseoptions()
|
||
|
|
||
|
def setpath(self, path):
|
||
|
path = os.path.abspath(os.path.expanduser(path))
|
||
|
|
||
|
if os.path.isfile(path):
|
||
|
path = os.path.dirname(path)
|
||
|
|
||
|
dirlist = []
|
||
|
hidedotfiles = self['hidedotfiles']
|
||
|
try:
|
||
|
posix = (os.name == 'posix')
|
||
|
for entry in os.listdir(path):
|
||
|
entryPath = path + '/' + entry
|
||
|
if hidedotfiles and entry[0] == '.':
|
||
|
# skip dot files if desired
|
||
|
continue
|
||
|
if not os.path.isdir(entryPath):
|
||
|
# skip files
|
||
|
continue
|
||
|
if not os.access(entryPath, os.R_OK | os.X_OK):
|
||
|
# skip directories we can't enter any way
|
||
|
continue
|
||
|
dirlist.append(entry)
|
||
|
|
||
|
except:
|
||
|
self.entry.setentry(self['path'])
|
||
|
return
|
||
|
|
||
|
self.entry.setentry(path)
|
||
|
|
||
|
self['path'] = path
|
||
|
|
||
|
dirlist.sort()
|
||
|
if path != '/':
|
||
|
dirlist.insert(0, '..')
|
||
|
|
||
|
self.listbox.setlist(dirlist)
|
||
|
pathlist = []
|
||
|
while path != '/':
|
||
|
pathlist.append(path)
|
||
|
path = os.path.dirname(path)
|
||
|
pathlist.append('/')
|
||
|
self.optbox.setitems(pathlist, 0)
|
||
|
|
||
|
def _setMinimumSize(self, event):
|
||
|
# If the optionmenu changes width, make sure it does not
|
||
|
# shrink later.
|
||
|
owidth = self.optbox.winfo_width()
|
||
|
self.workframe.grid_columnconfigure(2, minsize = owidth)
|
||
|
|
||
|
def _select(self):
|
||
|
sel = self.listbox.getcurselection()
|
||
|
if self['path'] == '/':
|
||
|
self['path'] = ''
|
||
|
if len(sel) > 0:
|
||
|
if sel[0] == '..':
|
||
|
self.setpath(os.path.dirname(self['path']))
|
||
|
else:
|
||
|
self.setpath(self['path'] + '/' + sel[0])
|
||
|
|
||
|
|
||
|
def getcurpath(self):
|
||
|
return self['path']
|
||
|
|
||
|
def enteredpath(self):
|
||
|
self.setpath(self.entry.get())
|
||
|
|
||
|
def okbutton(self):
|
||
|
self.deactivate(self['path'])
|
||
|
|
||
|
def cancelbutton(self):
|
||
|
self.deactivate(None)
|
||
|
|
||
|
def newdirbutton(self):
|
||
|
CreateDirectoryPopup(self.interior(), self['path'])
|
||
|
self.setpath(self['path'])
|
||
|
|
||
|
|
||
|
|
||
|
class CreateDirectoryPopup:
|
||
|
def __init__(self, parent, path):
|
||
|
self.path = path
|
||
|
self.parent = parent
|
||
|
self.newdirpopup = Pmw.PromptDialog(parent,
|
||
|
buttons = ('OK', 'Cancel'),
|
||
|
defaultbutton = 'OK',
|
||
|
title = 'New Directory',
|
||
|
entryfield_labelpos = 'nw',
|
||
|
label_text = 'Enter new directory name for:\n%s'%self.path,
|
||
|
command = self._buttonpress
|
||
|
)
|
||
|
|
||
|
self.newdirpopup.activate()
|
||
|
|
||
|
def _buttonpress(self, button):
|
||
|
if button == 'OK':
|
||
|
newdirname = self.newdirpopup.get()
|
||
|
dirlist = os.listdir(self.path)
|
||
|
if newdirname in dirlist:
|
||
|
ErrorPopup(self.parent,
|
||
|
'Error: "%s", already exists as a file or directory.'%newdirname)
|
||
|
else:
|
||
|
try:
|
||
|
os.mkdir(self.path + '/' + newdirname)
|
||
|
except:
|
||
|
ErrorPopup(self.parent,
|
||
|
'Error: Could not create directory: "%s"'%newdirname)
|
||
|
else:
|
||
|
self.newdirpopup.deactivate()
|
||
|
else:
|
||
|
self.newdirpopup.deactivate()
|
||
|
|
||
|
|
||
|
def ErrorPopup(parent, message):
|
||
|
error = Pmw.MessageDialog(parent, title = 'Error',
|
||
|
message_text = message,
|
||
|
defaultbutton = 0,
|
||
|
)
|
||
|
error.activate()
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
|
||
|
rootWin = Tkinter.Tk()
|
||
|
|
||
|
Pmw.initialise()
|
||
|
|
||
|
rootWin.title('Directory Browser Dialog Demo')
|
||
|
|
||
|
def buildBrowser():
|
||
|
# Create the hierarchical directory browser widget
|
||
|
dirBrowserDialog = DirBrowserDialog(rootWin,
|
||
|
#labelpos = 'nw',
|
||
|
label = 'Select a directory',
|
||
|
title = 'Directory Selector',
|
||
|
#path = '~',
|
||
|
#hidedotfiles = 0,
|
||
|
)
|
||
|
dir = dirBrowserDialog.activate()
|
||
|
print 'Selected Directory:', dir
|
||
|
|
||
|
dirButton = Tkinter.Button(rootWin, text="Browser", command=buildBrowser)
|
||
|
dirButton.pack(side = 'left', padx = 10, pady = 10)
|
||
|
|
||
|
exitButton = Tkinter.Button(rootWin, text="Quit", command=rootWin.quit)
|
||
|
exitButton.pack(side = 'left', padx = 10, pady = 10)
|
||
|
|
||
|
rootWin.mainloop()
|