#-----------------------------------------------------------------------------
# Name: FileExplorer.py
# Purpose: Classes for filesystem exploring
#
# Author: Riaan Booysen
#
# Created: 2001/03/06
# RCS-ID: $Id: FileExplorer.py,v 1.31 2007/07/02 15:01:10 riaan Exp $
# Copyright: (c) 2001 - 2007 Riaan Booysen
# Licence: GPL
#-----------------------------------------------------------------------------
print 'importing Explorers.FileExplorer'
import os, time, stat, sys
import wx
import Preferences, Utils
from Utils import _
import ExplorerNodes
from Models import Controllers,EditorHelper
from PropEdit import PropertyEditors,InspectorEditorControls
class FileSysCatNode(ExplorerNodes.CategoryNode):
# protocol = 'config.file'
itemProtocol = 'file'
defName, defaultStruct = Preferences.explorerFileSysRootDefault
def __init__(self, clipboard, config, parent, bookmarks):
ExplorerNodes.CategoryNode.__init__(self, _('Filesystem'), ('explorer', 'file'),
clipboard, config, parent)
self.bookmarks = bookmarks
if not self.entries and wx.Platform == '__WXMSW__':
drives = {}
for x in range(ord('C'), ord('Z')+1):
driveName = '%s:\\'%(chr(x))
if os.path.exists(driveName):
drives[driveName] = driveName
self.entries = drives
self.updateConfig()
wx.LogMessage(_('%d drives added to the filesystem definition.')%len(drives))
def createParentNode(self):
return self.parent
def createCatCompanion(self, catNode):
comp = ExplorerNodes.CategoryStringCompanion(catNode.treename, self)
return comp
def createChildNode(self, entry, value, forceFolder=True):
if forceFolder: Node = NonCheckPyFolderNode
else: Node = FileSysNode
node = Node(entry, value, self.clipboard, -1, self, self.bookmarks)
if node.isFolderish():
node.imgIdx = EditorHelper.imgFSDrive
else:
node.imgIdx = Controllers.identifyFile(value #localfs=node.filter == 'BoaFiles'
)[0].imgIdx
return node
## def newItem(self):
## name = ExplorerNodes.CategoryNode.newItem()
## self.entries[name] = copy.copy(self.defaultStruct)
## self.updateConfig()
## return name
def renameItem(self, name, newName):
if self.entries.has_key(newName):
raise Exception, _('Name exists')
self.entries[newName] = newName
del self.entries[name]
self.updateConfig()
def getNodeFromPath(self, respath, forceFolder=True):
cn = self.createChildNode(os.path.basename(respath), respath, forceFolder)
return cn
(wxID_FSOPEN, wxID_FSTEST, wxID_FSNEW, wxID_FSNEWFOLDER, wxID_FSCVS, wxID_FSSVN,
wxID_FSBOOKMARK, wxID_FSFINDINFILES, wxID_FSFINDFILES, wxID_FSFILTERIMAGES,
wxID_FSSETASCWD, wxID_FSNEWZIP, wxID_FSINSPECT,
) = Utils.wxNewIds(13)
(wxID_FSFILTER, wxID_FSFILTERBOAMODULES, wxID_FSFILTERSTDMODULES,
wxID_FSFILTERINTMODULES, wxID_FSFILTERALLMODULES,
) = Utils.wxNewIds(5)
filterDescrOrd = ['BoaFiles', 'StdFiles', 'BoaIntFiles', 'ImageFiles', 'AllFiles']
filterDescr = {'BoaFiles': (_('Boa files'), wxID_FSFILTERBOAMODULES),
'StdFiles': (_('Standard files'), wxID_FSFILTERSTDMODULES),
'BoaIntFiles': (_('Internal files'), wxID_FSFILTERINTMODULES),
'ImageFiles': (_('Image files'), wxID_FSFILTERIMAGES),
'AllFiles': (_('All files'), wxID_FSFILTERALLMODULES)}
# XXX CVS and Zip support must also move to registering
class FileSysController(ExplorerNodes.Controller, ExplorerNodes.ClipboardControllerMix):
bookmarkBmp = 'Images/Shared/Bookmark.png'
findBmp = 'Images/Shared/Find.png'
inspectBmp = 'Images/Shared/Inspector.png'
def __init__(self, editor, list, inspector, controllers):
ExplorerNodes.Controller.__init__(self, editor)
ExplorerNodes.ClipboardControllerMix.__init__(self)
self.editor = editor
self.inspector = inspector
self.list = list
## if controllers.has_key('cvs'):
## self.cvsController = controllers['cvs']
## else:
## self.cvsController = None
self.menu = wx.Menu()
self.fileMenuDef = [
(wxID_FSOPEN, _('Open'), self.OnOpenItems, '-'),
(-1, '-', None, ''),
(wxID_FSINSPECT, _('Inspect'), self.OnInspectItem, self.inspectBmp),
(-1, '-', None, ''),
] + self.clipMenuDef + [
(wxID_FSSETASCWD, _('Set as os.cwd'), self.OnSetAsSysCwd, '-'),
(-1, '-', None, ''),
(wxID_FSFINDINFILES, _('Find'), self.OnFindFSItem, self.findBmp),
]
if controllers.has_key('zip'):
self.newMenuDef.append(
(wxID_FSNEWZIP, _('Empty zip archive'), self.OnEmptyZipArchive, '-') )
if controllers.has_key('tar.gz'):
self.newMenuDef.append(
(wxID_FSNEWZIP, _('Empty tar.gz archive'), self.OnEmptyTarGzipArchive, '-') )
self.setupMenu(self.menu, self.list, self.fileMenuDef)
filters = []
for filter in filterDescrOrd:
descr, wid = filterDescr[filter]
filters.append( (wid, '+'+descr, self.OnFilterFSItems , '-') )
self.fileFilterMenuDef = filters
self.fileFilterMenu = wx.Menu()
self.setupMenu(self.fileFilterMenu, self.list, self.fileFilterMenuDef, False)
# Check default option
self.fileFilterMenu.Check(wxID_FSFILTERBOAMODULES, True)
self.menu.AppendMenu(wxID_FSFILTER, _('Filter'), self.fileFilterMenu)
# XXX this should not be done here
if controllers.has_key('cvs'):
self.menu.AppendMenu(wxID_FSCVS, 'CVS', controllers['cvs'].fileCVSMenu)
if controllers.has_key('svn'):
self.menu.AppendMenu(wxID_FSSVN, 'SVN', controllers['svn'].fileSVNMenu)
self.toolbarMenus = [self.fileMenuDef]
def destroy(self):
ExplorerNodes.ClipboardControllerMix.destroy(self)
self.fileFilterMenuDef = []
self.fileMenuDef = []
self.toolbarMenus = []
self.menu.Destroy()
def OnTest(self, event):
print self.list.node.clipboard.globClip.currentClipboard
def OnFilterFSItems(self, event):
evtid = event.GetId()
self.groupCheckMenu(self.fileFilterMenu, self.fileFilterMenuDef, evtid, True)
for filter in filterDescrOrd:
descr, wid = filterDescr[filter]
if wid == evtid:
self.list.node.setFilter(filter)
self.list.refreshCurrent()
break
def addFindResults(self, pattern, mapResults):
""" mapResult is map of tuples in this form
{'Module': ('Line no', 'Col', 'Text'), ...}
"""
nd = self.list.node
if not isinstance( self.list.node, ResultsFolderNode ):
self.list.node = ResultsFolderNode(_('Results'), nd.resourcepath,
nd.clipboard, -1, nd, nd.bookmarks)
mapFindInFileCount = {}
for oFindRes in mapResults.keys():
if len( mapResults[oFindRes] ):
mapFindInFileCount[oFindRes] = len( mapResults[oFindRes] )
self.list.node.results = map(None, mapFindInFileCount.values(),
mapFindInFileCount.keys() )
self.list.node.lastSearch = pattern
self.list.refreshCurrent()
def OnFindFSItem(self, event):
# XXX This is nasty, redesign
self.list.addFindResults = self.addFindResults
import FindReplaceDlg
dlg = FindReplaceDlg.FindReplaceDlg(self.list, self.editor.finder, self.list, 0)
dlg.SetWorkingFolder(self.list.node.resourcepath)
try:
dlg.ShowModal()
finally:
dlg.Destroy()
def OnSetAsSysCwd(self, event):
node = self.list.getSelection()
if node: path = node.resourcepath
else: path = self.list.node.resourcepath
if os.path.isfile(path): path = os.path.split(path)[0]
os.chdir(path)
self.editor.setStatus(_('Updated os.cwd to %s')%path, ringBell=True)
def OnEmptyZipArchive(self, event):
# must move to zip
files = os.listdir(self.list.node.resourcepath)
newName = Utils.getValidName(files, 'archive', 'zip')
import zipfile
zipfile.ZipFile(os.path.join(self.list.node.resourcepath, newName), 'w',
zipfile.ZIP_DEFLATED).close()
self.list.refreshCurrent()
self.list.selectItemNamed(newName)
self.list.EnsureVisible(self.list.selected)
def OnEmptyTarGzipArchive(self, event):
pass
def OnInspectItem(self, event):
if self.list.node:
item = self.list.getSelection()
if item:
comp = FileSysCompanion(item.name, item)
comp.updateProps()
self.inspector.selectObject(comp, False, focusPage=1)
class FileSysAttrPropEdit(PropertyEditors.PropertyEditor):
def inspectorEdit(self):
self.editorCtrl = InspectorEditorControls.BeveledLabelIEC(self,
self.getValue())
self.editorCtrl.createControl(self.parent, self.idx, self.width)
self.editorCtrl.setValue(self.getValue())
def getDisplayValue(self):
return self.value
class FileSysCompanion(ExplorerNodes.ExplorerCompanion):
def __init__(self, name, fsNode):
ExplorerNodes.ExplorerCompanion.__init__(self, name)
self.fsNode = fsNode
def getPropEditor(self, prop):
return FileSysAttrPropEdit
timeFmt = '%a, %d %b %Y %H:%M:%S'
def getPropertyItems(self):
res = []
attrs = self.fsNode.stdAttrs
for date in ('creation-date', 'modify-date', 'access-date'):
value = attrs[date]
if value:
res.append( (date,
time.strftime(self.timeFmt, time.localtime(value))) )
value = attrs['read-only']
res.append( ('read-only', value and 'True' or 'False') )
value = attrs['size']
if value:
res.append( ('size', str(value)) )
return res
class FileSysExpClipboard(ExplorerNodes.ExplorerClipboard):
def clipPaste_FileSysExpClipboard(self, node, nodes, mode):
# XXX Delayed cut (delete on paste or move) should clear the clipboard
# XXX or refresh clipboard with new paths and clear 'cut' mode
for clipnode in nodes:
if mode == 'cut':
node.moveFileFrom(clipnode)
self.clipNodes = []
elif mode == 'copy':
node.copyFileFrom(clipnode)
clipPaste_DefaultClipboard = clipPaste_FileSysExpClipboard
def _genericFSPaste(self, node, nodes, mode):
for other in nodes:
other.copyToFS(node)
def clipPaste_ZopeEClip(self, node, nodes, mode):
# XXX Pasting a cut from Zope does not delete the cut items from Zope
for zopeNode in nodes:
zopeNode.downloadToFS(os.path.join(node.resourcepath, zopeNode.name))
def clipPaste_FTPExpClipboard(self, node, nodes, mode):
# XXX Pasting a cut from FTP does not delete the cut items from FTP
for file in nodes:
file.ftpConn.download(file.resourcepath,
os.path.join(node.resourcepath, file.name))
clipPaste_SSHExpClipboard = _genericFSPaste
clipPaste_ZipExpClipboard = _genericFSPaste
clipPaste_DAVExpClipboard = _genericFSPaste
class FileSysNode(ExplorerNodes.ExplorerNode):
protocol = 'file'
filter = 'BoaFiles'
lastSearch = ''
subExplorerReg = {'file': [], 'folder': []}
connection = False
pathSep = os.sep
def __init__(self, name, resourcepath, clipboard, imgIdx, parent=None,
bookmarks=None, properties={}):
ExplorerNodes.ExplorerNode.__init__(self, name, resourcepath, clipboard,
imgIdx, parent, properties or {})
self.bookmarks = bookmarks
self.exts = EditorHelper.extMap.keys() + EditorHelper.inspectableFilesReg.keys()
self.entries = []
# XXX not used ?
self.doCVS = True
self.doZip = True
self.allowedProtocols = ['*']
self.updateStdAttrs()
def destroy(self):
self.entries = []
def isDir(self):
return os.path.isdir(self.resourcepath)
def isFolderish(self):
return self.isDir() or filter(lambda se, rp=self.resourcepath,
ap=self.allowedProtocols : (ap == ['*'] or se[0].protocol in ap) and se[1](rp),
self.subExplorerReg['file'])
def createParentNode(self):
parent = os.path.abspath(os.path.join(self.resourcepath, '..'))
if parent[-2:] == '..':
parent = parent[:-2]
return FileSysNode(os.path.basename(parent), parent, self.clipboard,
EditorHelper.imgFolder, self, self.bookmarks)
def createChildNode(self, file, filename = ''):
if not filename:
filename = os.path.join(self.resourcepath, file)
ext = os.path.splitext(filename)[1].lower()
exts, extSubTypes = self.getFilterExts()
# Files
if ('.*' in exts or ext in exts) and os.path.isfile(filename):
for Other, otherIdFunc, imgIdx in self.subExplorerReg['file']:
if '*' in self.allowedProtocols or \
Other.protocol in self.allowedProtocols:
if otherIdFunc(filename):
return 'fol', Other(file, filename, self.clipboard,
imgIdx, self, self.bookmarks)
Model = Controllers.identifyFile(filename)[0]
if extSubTypes.has_key(ext):
for SubTypeModel in extSubTypes[ext]:
if issubclass(Model, SubTypeModel):
break
else:
return '', None
return 'mod', FileSysNode(file, filename, self.clipboard,
Model.imgIdx, self, self.bookmarks, {})
#{'datetime': time.strftime('%a %b %d %H:%M:%S %Y',
# time.gmtime(os.stat(filename)[stat.ST_MTIME]))})
# Directories
elif os.path.isdir(filename):
for other, otherIdFunc, imgIdx in self.subExplorerReg['folder']:
if self.filter == 'BoaFiles' and \
'*' in self.allowedProtocols or '*' in self.allowedProtocols or \
other.protocol in self.allowedProtocols:
if otherIdFunc(filename):
return 'fol', other(file, filename, self.clipboard,
imgIdx, self, self.bookmarks)
return 'fol', FileSysNode(file, filename, self.clipboard,
EditorHelper.imgFolder, self, self.bookmarks)
else:
return '', None
def openList(self):
try:
#----------------------------------------
# A hack for locally-encoded filesystems:
# We need to convert filesystem names
# from local encoding to unicode
if type(self.resourcepath) is str:
files = os.listdir(self.resourcepath.decode(
sys.getfilesystemencoding()))
else: # unicode or other
files = os.listdir(self.resourcepath)
#----------------------------------------
except Exception, err:
raise ExplorerNodes.TransportError(err)
files.sort()
entries = {'mod': [], 'fol': []}
for file in files:
tp, node = self.createChildNode(file)
if node:
entries[tp].append(node)
self.entries = entries['fol'] + entries['mod']
return self.entries
def deleteItems(self, names):
for name in names:
path = os.path.join(self.resourcepath, name)
if os.path.isdir(path):
os.rmdir(path)
else:
os.remove(path)
def renameItem(self, name, newName):
oldfile = os.path.join(self.resourcepath, name)
newfile = os.path.join(self.resourcepath, newName)
os.rename(oldfile, newfile)
def newFolder(self, name):
os.mkdir(os.path.join(self.resourcepath, name))
return name
def newBlankDocument(self, name=''):
newpath = os.path.join(self.resourcepath, name)
if not os.path.exists(newpath):
open(newpath, 'w').write(' ')
return name
def copyFileFrom(self, node):
""" Copy node into self (only called for folders)"""
import shutil
if not node.isDir():
if node.resourcepath == os.path.join(self.resourcepath, node.name):
newNameBase = os.path.join(self.resourcepath, 'copy%s_of_'+node.name)
num = ''
while 1:
newName = newNameBase%num
if os.path.exists(newName):
try: num = str(int(num) + 1)
except: num = '2'
else:
shutil.copy(node.resourcepath, newName)
break
else:
shutil.copy(node.resourcepath, self.resourcepath)
## names = map(lambda n: n.name, self.entries)
## dir, name = os.path.split(self.resourcepath)
## name, ext = os.path.splitext(name)
## name = Util.getValidName(names, name, ext)
## shutil.copy(node.resourcepath, name)
## else:
## shutil.copy(node.resourcepath, self.resourcepath)
else:
shutil.copytree(node.resourcepath, os.path.join(self.resourcepath, node.name))
def moveFileFrom(self, node):
# Moving into directory being moved should not be allowed
sp = os.path.normpath(node.resourcepath)
dp = os.path.normpath(self.resourcepath)
if dp[:len(sp)] == sp:
raise Exception('Cannot move into itself')
self.copyFileFrom(node)
if not node.isFolderish():
os.remove(node.resourcepath)
else:
import shutil
shutil.rmtree(node.resourcepath)
def setFilter(self, filter):
self.__class__.filter = filter
def getFilterExts(self):
return {'BoaFiles': (self.exts, {}),
'StdFiles': (self.exts, {}),
'BoaIntFiles': (EditorHelper.internalFilesReg, {}),
'ImageFiles': (EditorHelper.imageExtReg,
EditorHelper.imageSubTypeExtReg),
'AllFiles': (['.*'], {})}.get(self.filter, (self.exts, {}))
def load(self, mode='rb'):
try:
data = open(self.resourcepath, mode).read()
self.updateStdAttrs()
return data
except IOError, error:
raise ExplorerNodes.TransportLoadError(error, self.resourcepath)
def save(self, filename, data, mode='wb', overwriteNewer=False):
if self.resourcepath != filename:
self.resourcepath = filename
self.name = os.path.basename(self.resourcepath)
try:
if not overwriteNewer and self.fileIsNewer():
raise ExplorerNodes.TransportModifiedSaveError(_('This file has '
'been saved by someone else since it was loaded'),
self.resourcepath)
open(self.resourcepath, mode).write(data)
except IOError, error:
raise ExplorerNodes.TransportSaveError(error, self.resourcepath)
self.updateStdAttrs()
def getNodeFromPath(self, respath):
name = os.path.basename(respath)
return self.createChildNode(name, respath)
def updateStdAttrs(self):
exists = os.path.exists(self.resourcepath)
self.stdAttrs['read-only'] = exists and \
not os.access(self.resourcepath, os.W_OK)
self.stdAttrs['modify-date'] = exists and \
os.stat(self.resourcepath)[stat.ST_MTIME] or 0.0
self.stdAttrs['creation-date'] = exists and \
os.stat(self.resourcepath)[stat.ST_CTIME] or 0.0
self.stdAttrs['access-date'] = exists and \
os.stat(self.resourcepath)[stat.ST_ATIME] or 0.0
self.stdAttrs['size'] = exists and \
os.stat(self.resourcepath)[stat.ST_SIZE] or 0
def setStdAttr(self, attr, value=None):
if attr == 'read-only':
os.chmod(self.resourcepath, value and 0444 or 0666)
self.updateStdAttrs()
def fileIsNewer(self):
return (os.path.exists(self.resourcepath) and \
os.stat(self.resourcepath)[stat.ST_MTIME] or 0.0) > \
self.stdAttrs['modify-date']
class ResultsFolderNode(FileSysNode):
results = []
def openList(self):
self.parentOpensChildren = True
self.results.sort()
self.results.reverse()
entries = []
for occrs, filename in self.results:
tp, node = self.createChildNode('(%d) %s'%(occrs, filename),
os.path.join(self.resourcepath, filename))
if node:
entries.append(node)
self.entries = entries
return self.entries
def openParent(self, editor):
editor.explorer.tree.SelectItem(editor.explorer.tree.GetSelection())
return True
def open(self, node, editor):
mod, cntrl = node.open(editor)
view = mod.getSourceView()
if view:
view.doFind(self.lastSearch)
view.doNextMatch()
return mod, cntrl
def getTitle(self):
return _('Find results for %s in %s') % (self.lastSearch, self.resourcepath)
class NonCheckPyFolderNode(FileSysNode):
def isFolderish(self):
return True
class CurWorkDirNode(FileSysNode):
protocol = 'os.cwd'
def __init__(self, clipboard, parent, bookmarks):
self.cwd = os.path.abspath(os.getcwd())
FileSysNode.__init__(self, 'os.cwd', self.cwd, clipboard,
EditorHelper.imgPathFolder, parent)
self.bookmarks = bookmarks
self.bold = True
#self.setFilter('AllFiles')
def openList(self):
self.cwd = self.resourcepath = os.path.abspath(os.getcwd())
return FileSysNode.openList(self)
def getTitle(self):
return 'os.cwd://%s'%self.cwd
def getURI(self):
return self.getTitle()
def uriSplitFile(filename, filepath):
return 'file', '', filepath, filename
def findFileExplorerNode(category, respath, transports):
for tp in transports.entries:
if tp.itemProtocol == 'file':
return tp.getNodeFromPath(respath, forceFolder=False)
raise ExplorerNodes.TransportError(
_('FileSysCatNode not found in transports %s')%transports.entries)
#-------------------------------------------------------------------------------
ExplorerNodes.register(FileSysNode, clipboard=FileSysExpClipboard,
confdef=('explorer', 'file'), controller=FileSysController,
category=FileSysCatNode)
ExplorerNodes.register(CurWorkDirNode, clipboard='file', controller='file',
root=True)
ExplorerNodes.fileOpenDlgProtReg.append('file')
ExplorerNodes.uriSplitReg[('file', 2)] = uriSplitFile
ExplorerNodes.uriSplitReg[('os.cwd', 2)] = uriSplitFile
ExplorerNodes.transportFindReg['file'] = findFileExplorerNode
|