#-----------------------------------------------------------------------------
# Name: ExplorerNodes.py
# Purpose: Explorer base classes for nodes, controllers and companions
#
# Author: Riaan Booysen
#
# Created: 2001
# RCS-ID: $Id: ExplorerNodes.py,v 1.39 2007/07/02 15:01:10 riaan Exp $
# Copyright: (c) 2001 - 2007 Riaan Booysen
# Licence: GPL
#-----------------------------------------------------------------------------
print 'importing Explorers.ExplorerNodes'
import sys, os, time, stat, copy, pprint
from ConfigParser import ConfigParser
import wx
import Preferences, Utils
from Utils import _
from Models import EditorHelper
import scrm
sensitive_properties = ('passwd', 'scp_pass')
# Folderish objects are creators
# Folderish objects are connected to a clipboard and maintain their children
# XXX Active models open in the editors should be returned on list queries
# XXX define a filtering interface
# XXX remove 'parent' refs
# Guidelines
# Creation of a node should be cheap and not significant resources
# Opening/getting the contents/sublists should start connections/resources
# Accelerator shortcuts
class GlobalClipper:
def __init__(self):
self.currentClipboard = None
class ClipboardException(Exception):
def __init__(self, source, dest):
self.source = source
self.dest = dest
class ExplorerClipboard:
""" """
# XXX Base class should implement recursive traversal by using explorer intf
def __init__(self, globClip):
self.globClip = globClip
self.clipNodes = []
self.clipMode = ''
def clipCut(self, node, nodes):
self.globClip.currentClipboard = self
self.clipNodes = nodes
self.clipMode = 'cut'
def clipCopy(self, node, nodes):
self.globClip.currentClipboard = self
self.clipNodes = nodes
self.clipMode = 'copy'
def clipPaste_Default(self, destNode, sourceNodes, clipMode):
for srcNode in sourceNodes:
destName = destNode.resourcepath+'/'+srcNode.name
newDestNode = destNode.getNodeFromPath(destName)
newDestNode.save(destName, srcNode.load())
if clipMode == 'cut':
# XXX delete items
pass
def clipPaste(self, node):
if self.globClip.currentClipboard:
methName = 'clipPaste_'+self.globClip.currentClipboard.__class__.__name__
if hasattr(self, methName):
clipMeth = getattr(self, methName)
else:
clipMeth = self.clipPaste_Default
clipMeth(node, self.globClip.currentClipboard.clipNodes,
self.globClip.currentClipboard.clipMode)
class Controller:
Node = None
plugins = ()
def __init__(self, editor):
self.editor = editor
self.plugins = [Plugin(self, editor) for Plugin in self.plugins]
def editorUpdateNotify(self, info=''):
pass
def setupMenu(self, menu, win, menus, addPlugins=True):
pluginMenuDefs = []
if addPlugins:
for plugin in self.plugins:
pluginMenuDefs.extend(plugin.menuDefs())
for wId, help, method, bmp in menus + pluginMenuDefs:
if help != '-':
if help[0] == '+':
canCheck = True
help = help[1:]
else:
canCheck = False
if type(method) in (type(()), type([])):
subMenu = wx.Menu()
self.setupMenu(subMenu, win, method)
menu.AppendMenu(wId, help, subMenu)
else:
menu.Append(wId, help, '', canCheck)
win.Bind(wx.EVT_MENU, method, id=wId)
self.editor.Bind(wx.EVT_MENU, method, id=wId)
else:
menu.AppendSeparator()
def destroy(self):
# break circular references here
pass
def groupToggleCheckMenu(self, menu, menuDef, wCheckId):
checked = not menu.IsChecked(wCheckId)
self.groupCheckMenu(menu, menuDef, wCheckId, checked)
def groupCheckMenu(self, menu, menuDef, wCheckId, checked):
for wId, help, method, bmp in menuDef:
if wId == wCheckId:
menu.Check(wId, checked)
else:
menu.Check(wId, not checked)
def getName(self, item):
if item.treename:
return item.treename
elif item.name:
return item.name
def getNamesForSelection(self, idxs):
res = []
for idx in idxs:
res.append(self.getName(self.list.items[idx]))
return res
def getNodesForSelection(self, idxs):
res = []
for idx in idxs:
res.append(self.list.items[idx])
return res
def createNode(self, category, name, resourcepath, uri):
return self.Node(name, resourcepath, None, -1, None, None,
properties = {})
(wxID_CLIPCUT, wxID_CLIPCOPY, wxID_CLIPPASTE, wxID_CLIPDELETE, wxID_CLIPRENAME,
wxID_CLIPNEWFOLDER, wxID_CLIPNEWBLANKDOC, wxID_CLIPRELOAD, wxID_CLIPBOOKMARK,
wxID_CLIPCOPYPATH, wxID_CLIPNEWMENU) = Utils.wxNewIds(11)
# XXX Maybe needs to be called StandardControllerMixin ??
class ClipboardControllerMix:
cutBmp = 'Images/Shared/Cut.png'
copyBmp = 'Images/Shared/Copy.png'
pasteBmp = 'Images/Shared/Paste.png'
deleteBmp = 'Images/Shared/Delete.png'
bookmarkBmp = 'Images/Shared/Bookmark.png'
def __init__(self):
self.newMenuDef = [
(wxID_CLIPNEWFOLDER, 'Folder', self.OnNewFolder, '-'),
(wxID_CLIPNEWBLANKDOC, 'Blank document', self.OnNewBlankDoc, '-'),
]
self.clipMenuDef = [ (wxID_CLIPRELOAD, _('Reload'), self.OnReloadItems, '-'),
(-1, '-', None, '-'),
(wxID_CLIPCUT, _('Cut'), self.OnCutItems, self.cutBmp),
(wxID_CLIPCOPY, _('Copy'), self.OnCopyItems, self.copyBmp),
(wxID_CLIPPASTE, _('Paste'), self.OnPasteItems, self.pasteBmp),
(-1, '-', None, ''),
(wxID_CLIPDELETE, _('Delete'), self.OnDeleteItems, self.deleteBmp),
(wxID_CLIPRENAME, _('Rename'), self.OnRenameItems, '-'),
(-1, '-', None, ''),
(wxID_CLIPNEWMENU, _('New'), self.newMenuDef, '-'),
(-1, '-', None, '-'),
(wxID_CLIPBOOKMARK, _('Bookmark'), self.OnBookmarkItems, self.bookmarkBmp),
(wxID_CLIPCOPYPATH, _('Copy path(s) to clipboard'), self.OnCopyPath, '-'),
]
def destroy(self):
self.clipMenuDef = []
def OnCutItems(self, event):
if self.list.node:
nodes = self.getNodesForSelection(self.list.getMultiSelection())
self.list.node.clipCut(nodes)
def OnCopyItems(self, event):
if self.list.node:
nodes = self.getNodesForSelection(self.list.getMultiSelection())
self.list.node.clipCopy(nodes)
def OnPasteItems(self, event):
if self.list.node:
wx.BeginBusyCursor()
try:
self.list.node.clipPaste()
self.list.refreshCurrent()
finally:
wx.EndBusyCursor()
def OnDeleteItems(self, event):
if self.list.node:
wx.BeginBusyCursor()
try:
idxs = self.list.getMultiSelection()
for item in self.getNodesForSelection(idxs):
self.editor.explorerDeleteNotify(item.getURI())
names = self.getNamesForSelection(idxs)
self.list.node.deleteItems(names)
self.list.refreshCurrent()
finally:
wx.EndBusyCursor()
def OnRenameItems(self, event):
self.list.EditLabel(self.list.selected)
def OnOpenItems(self, event):
if self.list.node:
nodes = self.getNodesForSelection(self.list.getMultiSelection())
for node in nodes:
if not node.isFolderish():
self.list.openNodeInEditor(node, self.editor,
self.editor.explorerStore.recentFiles)
#explorer.tree.recentFiles)
def selectNewItem(self, name):
## # XXX This is broken, select and rename somehow fires before internal
## # XXX states are updated
## return
self.list.selectItemNamed(name)
self.list.EnsureVisible(self.list.selected)
self.list.EditLabel(self.list.selected)
def OnNewFolder(self, event):
if self.list.node:
name = Utils.getValidName(self.list.getAllNames(), 'Folder')
wx.BeginBusyCursor()
try:
self.list.node.newFolder(name)
finally:
wx.EndBusyCursor()
self.list.refreshCurrent()
self.selectNewItem(name)
def OnNewBlankDoc(self, event):
if self.list.node:
name = Utils.getValidName(self.list.getAllNames(), 'BlankDoc')
wx.BeginBusyCursor()
try:
self.list.node.newBlankDocument(name)
finally:
wx.EndBusyCursor()
self.list.refreshCurrent()
self.selectNewItem(name)
def OnReloadItems(self, event):
if self.list.node:
self.list.refreshCurrent()
def OnBookmarkItems(self, event):
if self.list.node:
nodes = self.getNodesForSelection(self.list.getMultiSelection())
for node in nodes:
if node.bookmarks:
node.bookmarks.add(node.getURI())
self.editor.statusBar.setHint(
_('Bookmarked %s')% node.resourcepath, 'Info')
else:
node = self.list.node
if not nodes and node.bookmarks:
node.bookmarks.add(node.getURI())
self.editor.setStatus(_('Bookmarked %s')% node.getURI())
def OnCopyPath(self, event):
if self.list.node:
ms = self.list.getMultiSelection()
nodes = self.getNodesForSelection(ms)
paths = []
for node in nodes:
paths.append(node.getURI())
Utils.writeTextToClipboard(os.linesep.join(paths))
self.editor.setStatus(_('Path(s) copied to clipboard'))
class TransportError(Exception):
def __str__(self):
try:
return str(self.args[0])
except:
return str(self.args)
class TransportLoadError(TransportError):
pass
class TransportSaveError(TransportError):
pass
class TransportModifiedSaveError(TransportSaveError):
pass
class TransportCategoryError(TransportError):
def __init__(self, msg='', filepath=None):
TransportError.__init__(self, msg, filepath)
self.msg = msg
self.filepath = filepath
def __str__(self):
if self.filepath:
return '%s: %s' % (self.msg, self.filepath)
else:
return self.msg
class ExplorerNode:
""" Base class for items in the explorer. """
# Protocol identifier, used to associate with controller
protocol = ''
images = None
viewMode = 'list'
pathSep = '/'
# Is it a stateless protocol or does it require a connection
connection = False
filter = ''
# Should the node keep a reference to it's possible tree item
refTree = False
def __init__(self, name, resourcepath, clipboard, imgIdx, parent=None, properties=None):
self.name = name
self.resourcepath = resourcepath
self.imgIdx = imgIdx
if properties is None: properties = {}
self.properties = properties
self.clipboard = clipboard
self.parent = parent
self.treename = name
self.treeitem = None
self.bold = False
self.colour = None
self.vetoRequery = False
self.vetoSort = False
self.upImgIdx = EditorHelper.imgFolderUp
self.parentOpensChildren = False
self.ignoreParentDir = False
self.category = ''
self.stdAttrs = {'size': 0,
'creation-date': 0.0,
'modify-date': 0.0,
'access-date': 0.0,
'read-only': 0}
## def __del__(self): pass
## print '__del__', self.__class__.__name__
def destroy(self):pass
def createParentNode(self): return self.parent
def createChildNode(self, value): pass
def openList(self): pass
def closeList(self): pass
def isFolderish(self): return False
def getTitle(self):
if self.resourcepath: return self.resourcepath
else: return self.name
def getURI(self):
return '%s://%s%s'%(self.protocol, self.category, self.getTitle())
def getDescription(self):
return self.getURI()
def notifyBeginLabelEdit(self, event):
if event.GetLabel() == '..': event.Veto()
def getNodeFromPath(self, respath):
return None
def setFilter(self, filter):
pass
#---Default item actions--------------------------------------------------------
def open(self, editor):
return editor.openOrGotoModule(self.getURI(), transport = self)
def openParent(self, editor): return False
def checkOpenInEditor(self): return False
#---Methods on sub items--------------------------------------------------------
def deleteItems(self, names): pass
def renameItem(self, name, newName): pass
def newFolder(self, name): pass
def newBlankDocument(self, name): pass
#---Clipboard methods-----------------------------------------------------------
def clipCut(self, nodes):
self.clipboard.clipCut(self, nodes)
def clipCopy(self, nodes):
self.clipboard.clipCopy(self, nodes)
def clipPaste(self):
self.clipboard.clipPaste(self)
def canAdd(self, paletteName):
return False
#---Persistance (loading and saving)--------------------------------------------
def assertFilename(self, filename):
""" Utility function to strip and assert the protocol from the uri """
from Explorers.Explorer import splitURI
prot, cat, res, uri = splitURI(filename)
assert self.protocol==prot, _('Illegal protocol change')
return res
def currentFilename(self):
return self.assertFilename(self.getURI())
def load(self, mode='r'):
""" Return item data from appropriate transport """
return None
def save(self, filename, data, mode='w'):
""" Persist data on appropriate transport. Should handle renames """
pass
#---Standard attrs, read-only, mod date, create date, etc.----------------------
def updateStdAttrs(self): pass
def setStdAttr(self, attr, value): pass
#class NoneExplorerNode(ExplorerNode):
# """ Represents an undefined transport. """
# protocol = 'none'
class CachedNodeMixin:
""" Only read from datasource when uninitialised or invalidated
Not used yet
"""
def __init__(self):
self.valid = False
self.cache = None
def openList(self):
if self.valid:
return self.cache
else:
# define this method
self.cache = self.openList_cache()
self.valid = True
return self.cache
class ContainerNode(ExplorerNode):
protocol = 'fol'
def __init__(self, name, imgIdx):
ExplorerNode.__init__(self, name, '', None, imgIdx, None)
self.entries = []
self.vetoRequery = True
self.vetoSort = True
def destroy(self): pass
def isFolderish(self): return True
def createParentNode(self): return self
def createChildNode(self, value): return value
def openList(self): return self.entries
def getTitle(self): return self.name
def notifyBeginLabelEdit(self, event):
event.Veto()
class RootNode(ContainerNode):
protocol = 'root'
def __init__(self, name, imgIdx=EditorHelper.imgBoaLogo):
ContainerNode.__init__(self, name, imgIdx)
cat_section = 0
cat_option = 1
class CategoryNode(ExplorerNode):
protocol = 'config'
defName = 'config'
defaultStruct = {}
itemProtocol = ''
entries = {}
sharedEntries = {}
def __init__(self, name, resourcepath, clipboard, config, parent, imgIdx=EditorHelper.imgFolder):
ExplorerNode.__init__(self, name, resourcepath, clipboard, imgIdx, parent)
self.config = config
self.bold = True
if not self.sharedEntries.has_key(self.protocol):
self.sharedEntries[self.itemProtocol] = copy.copy(self.entries)
self.entries = self.sharedEntries[self.itemProtocol]
self.refresh()
def destroy(self):
pass
def isFolderish(self):
return True
def getTitle(self):
return self.name
def getConfigValue(self):
try:
return eval(self.config.get(self.resourcepath[cat_section],
self.resourcepath[cat_option]), {})
except ConfigParser.NoOptionError, err:
return self.entries
def refresh(self):
# Important: To keep the explorer list and the inspector in sync,
# the reference to self.entries should only be updated
# and not reassigned
if type(self.entries) == type({}):
self.entries.clear()
self.entries.update(self.getConfigValue())
# unscramble sensitive properties
for item in self.entries.keys():
if type(self.entries[item]) == type({}):
dict = self.entries[item]
for name in dict.keys():
if name in sensitive_properties:
dict[name] = scrm.scramble(dict[name])[2:]
def openList(self):
res = []
entries = self.entries.keys()
entries.sort()
for entry in entries:
node = self.createChildNode(entry, self.entries[entry])
if node:
res.append(node)
return res
def deleteItems(self, names):
for name in names:
try:
del self.entries[name]
except KeyError:
wx.LogWarning(_('Could not find %s in %s for deletion')%(name,
self.entries.keys()))
self.updateConfig()
illegal_substrs = ('://', '::', '/', '\\')
def renameItem(self, name, newName):
for ill_substr in self.illegal_substrs:
if newName.find(ill_substr) != -1:
raise Exception, _('Contains invalid string sequence or char: "%s"')%ill_substr
if self.entries.has_key(newName):
raise Exception, _('Name exists')
self.entries[newName] = self.entries[name]
del self.entries[name]
self.updateConfig()
def newItem(self):
name = Utils.getValidName(self.entries.keys(), self.defName)
self.entries[name] = copy.copy(self.defaultStruct)
self.updateConfig()
return name
def updateConfig(self):
assert type(self.entries) is type(self.__class__.entries), \
_('Entries type %s invalid, expected %s')%(str(type(self.entries)),
str(type(self.__class__.entries)))
self.config.set(self.resourcepath[cat_section],
self.resourcepath[cat_option], pprint.pformat(self.entries))
Utils.writeConfig(self.config)
def copyCatFrom(self, node):
name = Utils.getValidName(self.entries.keys(), node.name or node.treename)
self.entries[name] = copy.copy(node.properties)
self.updateConfig()
(wxID_CATNEW, wxID_CATINSPECT, wxID_CATCOPY, wxID_CATDELETE, wxID_CATRENAME,
wxID_CATRELOAD) = Utils.wxNewIds(6)
class CategoryController(Controller):
newBmp = 'Images/Shared/NewItem.png'
inspectBmp = 'Images/Shared/Inspector.png'
deleteBmp = 'Images/Shared/Delete.png'
copyBmp = 'Images/Shared/Copy.png'
def __init__(self, editor, list, inspector, controllers, menuDefs = []):
Controller.__init__(self, editor)
self.list = list
self.menu = wx.Menu()
self.inspector = inspector
self.catMenuDef = [ (wxID_CATNEW, _('New'), self.OnNewItem, self.newBmp),
(wxID_CATINSPECT, _('Inspect'), self.OnInspectItem, self.inspectBmp),
(wxID_CATRELOAD, _('Reload'), self.OnReloadItems, '-'),
(-1, '-', None, ''),
(wxID_CATCOPY, _('Create copy'), self.OnCreateCopy, self.copyBmp),
(-1, '-', None, ''),
(wxID_CATDELETE, _('Delete'), self.OnDeleteItems, self.deleteBmp),
(wxID_CATRENAME, _('Rename'), self.OnRenameItem, '-') ]
self.setupMenu(self.menu, self.list, self.catMenuDef + menuDefs)
self.toolbarMenus = [self.catMenuDef + menuDefs]
def destroy(self):
self.catMenuDef = ()
self.toolbarMenus = ()
self.menu.Destroy()
def OnInspectItem(self, event):
if self.list.node:
# Create new companion for selection
catItem = self.list.getSelection()
if not catItem: return
catComp = self.list.node.createCatCompanion(catItem)
catComp.updateProps()
self.inspector.selectObject(catComp, False, focusPage=1, restore=True)
def OnNewItem(self, event):
if self.list.node:
name = self.list.node.newItem()
self.list.refreshCurrent()
self.list.selectItemNamed(name)
self.OnInspectItem(event)
#self.list.EditLabel(self.list.selected)
def OnDeleteItems(self, event):
if self.list.node:
ms = self.list.getMultiSelection()
names = self.getNamesForSelection(ms)
self.list.node.deleteItems(names)
self.list.refreshCurrent()
def OnRenameItem(self, event):
self.list.EditLabel(self.list.selected)
def OnReloadItems(self, event):
if self.list.node:
self.list.refreshCurrent()
def OnCreateCopy(self, event):
if self.list.node:
nodes = self.getNodesForSelection(self.list.getMultiSelection())
for node in nodes:
self.list.node.copyCatFrom(node)
self.list.refreshCurrent()
class BookmarksCatNode(CategoryNode):
""" Stores folderish references to any transport protocol """
#protocol = 'config.bookmark'
defName = _('Bookmark')
defaultStruct = Preferences.explorerFileSysRootDefault[1]
refTree = True
def __init__(self, clipboards, config, parent, catTransports, tree=None,
name=_('Bookmarks'), confSpec=('explorer', 'bookmarks')):
CategoryNode.__init__(self, name, confSpec, None, config, parent)
self.catTransports = catTransports
self.tree = tree
self.treeitem = None
self.clipboards = clipboards
self.imgIdx = EditorHelper.imgFolderBookmark
def cleanup(self):
self.catTransports = None
self.tree = None
self.clipboards = None
def createChildNode(self, name, value):
if type(value) == type({}):
return SubBookmarksCatNode(self, name, value)
else:
from Explorers.Explorer import splitURI,getTransport,TransportError
prot, cat, res, uri = splitURI(value)
try:
node = getTransport(prot, cat, res, self.catTransports)
except TransportError:
# XXX should return broken link items
#print 'transport not found %s %s %s' %(prot, cat, res)
return None
if node.isFolderish():
if prot == 'file':
node.imgIdx = EditorHelper.imgFSDrive
elif prot == 'zope':
node.imgIdx = EditorHelper.imgZopeConnection
else:
node.imgIdx = EditorHelper.imgNetDrive
node.treename = name
return node
def getDefault(self):
return self.config.get(self.resourcepath[0], 'defaultbookmark')
def add(self, respath):
respath=str(respath)
if respath[-1] in ('/', '\\'):
name = os.path.splitext(os.path.basename(respath[:-1]))[0]
else:
name = os.path.splitext(os.path.basename(respath))[0]
if self.entries.has_key(name):
name = Utils.getValidName(self.entries.keys(), name)
self.entries[name] = respath
self.updateConfig()
self.refreshTree()
def refreshTree(self):
return
# XXX if under bookmarks when adding bookmarks, tree is rebuilt and
# XXX position in tree is lost
# XXX At least update list when Bookmarks node is selected.
#if self.tree and self.treeitem and self.treeitem.IsOk():
# if self.tree.IsExpanded(self.treeitem):
# self.tree.CollapseAndReset(self.treeitem)
# self.tree.Expand(self.treeitem)
def createCatCompanion(self, catNode):
return BookmarkCategoryStringCompanion(catNode.treename, self)
def copyCatFrom(self, node):
name = Utils.getValidName(self.entries.keys(), node.name or node.treename)
self.entries[name] = node.resourcepath
self.updateConfig()
class SubBookmarksCatNode(BookmarksCatNode):
def __init__(self, parent, name, bookmarks):
self._entries = bookmarks
BookmarksCatNode.__init__(self, parent.clipboards, parent.config,
parent, parent.catTransports, parent.tree)
self.bold = False
self.name = self.treename = name
def refresh(self):
self.entries = self._entries
def getURI(self):
return '%s/%s'%(self.parent.getURI(), self.name)
def updateConfig(self):
self.parent.updateConfig()
class MRUCatNode(BookmarksCatNode):
protocol = 'recent.files'
defName = _('Recent files')
entries = []
defaultStruct = ''
def __init__(self, clipboards, config, parent, catTransports, tree):
BookmarksCatNode.__init__(self, clipboards, config, parent,
catTransports, tree, _('Recent files'), ('explorer', 'recentfiles'))
self.vetoSort = True
self.imgIdx = EditorHelper.imgRecentFiles
self.ignoreParentDir = True
def openList(self):
res = []
for entry in self.entries:
try:
node = self.createChildNode(entry)
except Exception, err:
node = None
if node:
res.append(node)
else:
self.entries.remove(entry)
return res
def add(self, respath):
if respath in self.entries:
self.entries.remove(respath)
self.entries.insert(0, respath)
if len(self.entries) > Preferences.exRecentFilesListSize:
self.entries[Preferences.exRecentFilesListSize:] = []
self.updateConfig()
self.refreshTree()
def createChildNode(self, fullpath):
from Explorers.Explorer import splitURI,getTransport,TransportError
prot, cat, res, uri = splitURI(fullpath)
try:
node = getTransport(prot, cat, res, self.catTransports)
except TransportError:
return None
node.name = node.treename = fullpath
return node
def notifyBeginLabelEdit(self, event):
event.Veto()
def refresh(self):
self.entries[:] = self.getConfigValue()
(wxID_MRUOPEN, wxID_MRURELOAD, wxID_MRUREMOVE) = Utils.wxNewIds(3)
class MRUCatController(Controller):
deleteBmp = 'Images/Shared/Delete.png'
def __init__(self, editor, list, inspector, controllers, menuDefs = []):
Controller.__init__(self, editor)
self.list = list
self.menu = wx.Menu()
self.inspector = inspector
self.mruMenuDef = [
(wxID_MRUOPEN, _('Open'), self.OnOpenItems, '-'),
(-1, '-', None, '-'),
(wxID_MRURELOAD, _('Reload'), self.OnReloadItems, '-'),
(-1, '-', None, ''),
(wxID_MRUREMOVE, _('Remove'), self.OnRemoveItems, self.deleteBmp)
]
self.setupMenu(self.menu, self.list, self.mruMenuDef + menuDefs)
self.toolbarMenus = [self.mruMenuDef + menuDefs]
self.recentItemsMenuIds = {}
def destroy(self):
self.mruMenuDef = ()
self.toolbarMenus = ()
self.menu.Destroy()
def createRecentFilesMenu(self):
# XXX not finished yet
self.recentItemsMenuIds = {}
menu = wx.Menu()
for node in self.list.node.openList():
if node.name not in self.recentItemsMenuIds.values():
wid = wx.NewId()
self.recentItemsMenuIds[wid] = node.name
self.list.Bind(wx.EVT_MENU, self.OnMRUMenuItemSelect, id=wid)
else:
for wid, name in self.recentItemsMenuIds.items():
if name == node.name:
break
else:
continue
menu.Append(wid, node.name)
return menu
def OnOpenItems(self, event):
if self.list.node:
nodes = self.getNodesForSelection(self.list.getMultiSelection())
for node in nodes:
if not node.isFolderish():
node.open(self.editor)
def OnReloadItems(self, event):
if self.list.node:
self.list.refreshCurrent()
def OnRemoveItems(self, event):
if self.list.node:
names = self.list.getMultiSelection()
names.sort()
names.reverse()
self.list.node.deleteItems(names)
self.list.refreshCurrent()
def OnMRUMenuItemSelect(self, event):
wid = event.GetId()
self.recentItemsMenuIds[wid]
#---Companions------------------------------------------------------------------
from Companions.BaseCompanions import Companion
from PropEdit.PropertyEditors import StrConfPropEdit,EvalConfPropEdit,PasswdStrConfPropEdit
import RTTI
import types
class ExplorerCompanion(Companion):
def __init__(self, name):
Companion.__init__(self, name)
# list of (name, value) tuples
self.propItems = []
self.designer = None
self.control = None
self.mutualDepProps = ()
def constructor(self):
return {}
def extraConstrProps(self):
return {}
def events(self):
return ()
def getEvents(self):
return ()
def getPropEditor(self, prop):
return None
def getPropOptions(self, prop):
return ()
def getPropNames(self, prop):
return ()
def checkTriggers(self, name, oldValue, value):
pass
def persistProp(self, name, setterName, value):
pass
def propIsDefault(self, name, setterName):
return True
def persistedPropVal(self, name, setterName):
return ''
def getPropList(self):
propLst = []
for prop in self.propItems:
propLst.append(RTTI.PropertyWrapper(prop[0], 'NameRoute',
self.GetProp, self.SetProp))
return {'constructor':[], 'properties': propLst}
def findProp(self, name):
for idx in range(len(self.propItems)):
if self.propItems[idx][0] == name:
return self.propItems[idx], idx
else:
return None, -1
def GetProp(self, name):
return self.findProp(name)[0][1]
def SetProp(self, name, value):
prop, idx = self.findProp(name)
if self.setPropHook(name, value, prop):
self.propItems[idx] = (name, value) + prop[2:]
def GetClass(self, dummy=None):
# XXX Add protocol from transport
return 'Explorer Item'
def SetClass(self, value):
pass
def updateProps(self):
self.propItems = self.getPropertyItems()
def addProperty(self, name, value, tpe):
pass
def delProperty(self, name):
pass
def setPropHook(self, name, value, oldProp = None):
""" Override to do something before a property is set """
pass
def getPropertyItems(self):
""" Override this to read the properties of the object, and return it
Should return a list of tuples where the first two items are the
property name and value, the rest of the items may store other
propery information. """
return []
class CategoryCompanion(ExplorerCompanion):
""" Inspectable objects, driven from config files """
propMapping = {type('') : StrConfPropEdit,
'password' : PasswdStrConfPropEdit,
'default': EvalConfPropEdit}
try:
propMapping[type(u'')] = StrConfPropEdit
except:
pass
def __init__(self, name, catNode):
ExplorerCompanion.__init__(self, name)
self.catNode = catNode
def getPropEditor(self, prop):
if prop in sensitive_properties:
return self.propMapping['password']
else:
return self.propMapping.get(type(self.GetProp(prop)), self.propMapping['default'])
class CategoryDictCompanion(CategoryCompanion):
def getPropertyItems(self):
return self.catNode.entries[self.name].items()
def setPropHook(self, name, value, oldProp = None):
# scramble sensitive properties before saving
try:
if not self.catNode.entries.has_key(self.name):
raise Exception(_('%s not found in the config, renaming config '
'entries while Inspecting is not allowed.')%self.name)
entry = self.catNode.entries[self.name]
entry[name] = value
finally:
scrams = []
for entry in self.catNode.entries.values():
for key in entry.keys():
if key in sensitive_properties:
val = entry[key]
entry[key] = scrm.scramble(val)
scrams.append((entry, key, val))
self.catNode.updateConfig()
# unscramble sensitive properties
for entry, key, val in scrams:
entry[key] = val
return True
class CategoryStringCompanion(CategoryCompanion):
def getPropertyItems(self):
return [ ('Item', self.catNode.entries[self.name]) ]
def setPropHook(self, name, value, oldProp = None):
self.catNode.entries[self.name] = value
self.catNode.updateConfig()
class BookmarkCategoryStringCompanion(CategoryStringCompanion):
def setPropHook(self, name, value, oldProp = None):
if value == '{}': value = {}
CategoryStringCompanion.setPropHook(self, name, value, oldProp)
def uriSplitNone(filename, filepath):
return 'none', '', filepath, filename
#-Registry for explorer nodes-------------------------------------------------
# Successfully loaded modules from the
# Explorer.*.cfg [explorers] installedtransports import list are recorded here.
# Explorer Plug-ins bypassing the Explorer imports should add themselves
# to this list to have their controller classes hooked into the IDE
installedModules = []
# Dict of modules that failed to load, name: error
failedModules = {}
# Registry for language styles which can be edited under Preferences.Source
langStyleInfoReg = []
# Registry for extra protocols available in the file open dialog
fileOpenDlgProtReg = []
# Registry for splitting uris
uriSplitReg = {('none', 2): uriSplitNone}
# Registry for functions to locate connections
transportFindReg = {}
# Global reference to container for all transport protocols
# The first Explorer Tree created will define this
all_transports = None
# Main registries for ExplorerNode classes
explorerNodeReg = {}
nodeRegByProt = {}
# List of protocols that don't have Category nodes, and must be created
# at the top level of the tree
explorerRootNodesReg = []
def register(Node, clipboard=None, confdef=('', ''), controller=None,
category=None, root=False):
""" Register a new explorer Node.
clipboard : Clipboard class or protocol name (string) of existing clipboard
confdef : (section, option) tuple for the config file
controller : Controller class or protocol name (string) of existing controller
category : Category node class for node when added as a transport to the tree
root : Non category/transport nodes can be installed in the tree root
"""
explorerNodeReg[Node] = {'clipboard': clipboard, 'confdef': confdef,
'controller': controller, 'category': category}
nodeRegByProt[Node.protocol] = Node
if root:
explorerRootNodesReg.append(Node.protocol)
def isTransportAvailable(conf, section, prot):
return conf.has_option(section, prot) and nodeRegByProt.has_key(prot)
#-------------------------------------------------------------------------------
register(CategoryNode, controller=CategoryController)
register(MRUCatNode, controller=MRUCatController)
|