#----------------------------------------------------------------------------- # Name: PrefsExplorer.py # Purpose: # # Author: Riaan Booysen # # Created: 2001/06/08 # RCS-ID: $Id: PrefsExplorer.py,v 1.18 2005/05/18 12:59:39 riaan Exp $ # Copyright: (c) 2001 - 2005 # Licence: GPL #----------------------------------------------------------------------------- print 'importing Explorers.PrefsExplorer' import os, sys, glob, pprint, imp import types import wx import Preferences, Utils, Plugins import ExplorerNodes from Models import EditorHelper from Views import STCStyleEditor import methodparse, relpath class PreferenceGroupNode(ExplorerNodes.ExplorerNode): """ Represents a group of preference collections """ protocol = 'prefs.group' defName = 'PrefsGroup' def __init__(self, name, parent): ExplorerNodes.ExplorerNode.__init__(self, name, name, None, EditorHelper.imgPrefsFolder, None) self.vetoSort = True self.preferences = [] def isFolderish(self): return True def openList(self): return self.preferences def notifyBeginLabelEdit(self, event): event.Veto() class BoaPrefGroupNode(PreferenceGroupNode): """ The Preference node in the Explorer """ protocol = 'boa.prefs.group' customPrefs = [] # list of tuples ('name', 'file') def __init__(self, parent): PreferenceGroupNode.__init__(self, 'Preferences', parent) self.bold = True prefImgIdx = EditorHelper.imgSystemObj stcPrefImgIdx = EditorHelper.imgPrefsSTCStyles self.source_pref = PreferenceGroupNode('Source', self) self.source_pref.preferences = [ UsedModuleSrcBsdPrefColNode('Default settings', Preferences.exportedSTCProps, os.path.join(Preferences.rcPath, 'prefs.rc.py'), prefImgIdx, self, Preferences, True)] for name, lang, STCClass, stylesFile in ExplorerNodes.langStyleInfoReg: if not os.path.isabs(stylesFile): stylesFile = os.path.join(Preferences.rcPath, stylesFile) self.source_pref.preferences.append(STCStyleEditPrefsCollNode( name, lang, STCClass, stylesFile, stcPrefImgIdx, self)) self.preferences.append(self.source_pref) self.general_pref = UsedModuleSrcBsdPrefColNode('General', Preferences.exportedProperties, os.path.join(Preferences.rcPath, 'prefs.rc.py'), prefImgIdx, self, Preferences) self.preferences.append(self.general_pref) self.platform_pref = UsedModuleSrcBsdPrefColNode('Platform specific', Preferences.exportedProperties2, os.path.join(Preferences.rcPath, 'prefs.%s.rc.py' % (wx.Platform == '__WXMSW__' and 'msw' or 'gtk')), prefImgIdx, self, Preferences) self.preferences.append(self.platform_pref) self.keys_pref = KeyDefsSrcPrefColNode('Key bindings', ('*',), os.path.join(Preferences.rcPath, 'prefs.keys.rc.py'), prefImgIdx, self, Preferences.keyDefs) self.preferences.append(self.keys_pref) for name, filename in self.customPrefs: if not os.path.isabs(filename): filename = os.path.join(Preferences.rcPath, filename) self.preferences.append(UsedModuleSrcBsdPrefColNode(name, ('*',), filename, prefImgIdx, self, Preferences)) ## self.pychecker_pref = SourceBasedPrefColNode('PyChecker', ## ('*',), Preferences.pyPath+'/.pycheckrc', prefImgIdx, self) ## self.preferences.append(self.pychecker_pref) self.plugin_pref = PreferenceGroupNode('Plug-ins', self) self.core_plugpref = UsedModuleSrcBsdPrefColNode('Core support', Preferences.exportedCorePluginProps, os.path.join(Preferences.rcPath, 'prefs.rc.py'), prefImgIdx, self, Preferences, True) self.plugin_plugpref = UsedModuleSrcBsdPrefColNode('Preferences', Preferences.exportedPluginProps,#('*',), os.path.join(Preferences.rcPath, 'prefs.plug-ins.rc.py'), prefImgIdx, self, Preferences, True) self.files_plugpref = PluginFilesGroupNode() self.transp_plugpref = PreferenceGroupNode('Transports', self) self.transp_plugpref.preferences = [ TransportPluginsLoadOrderGroupNode(), TransportPluginsTreeDisplayOrderGroupNode(), ] self.plugin_pref.preferences = [ self.files_plugpref, self.transp_plugpref, self.core_plugpref, self.plugin_plugpref, ] self.preferences.insert(1, self.plugin_pref) self.help_pref = HelpConfigBooksPGN() self.preferences.insert(2, self.help_pref) class PreferenceCollectionNode(ExplorerNodes.ExplorerNode): """ Represents an inspectable preference collection """ protocol = 'prefs' def __init__(self, name, props, resourcepath, imgIdx, parent): ExplorerNodes.ExplorerNode.__init__(self, name, resourcepath, None, imgIdx, None, props) def open(self, editor): """ Populate inspector with preference items """ comp = PreferenceCompanion(self.name, self) comp.updateProps() # Select in inspector editor.inspector.restore() if editor.inspector.pages.GetSelection() != 1: editor.inspector.pages.SetSelection(1) editor.inspector.selectObject(comp, False) return None, None def isFolderish(self): return False def load(self): raise 'Not implemented' def save(self, filename, data): pass def notifyBeginLabelEdit(self, event): event.Veto() class STCStyleEditPrefsCollNode(PreferenceCollectionNode): protocol = 'stc.prefs' def __init__(self, name, lang, STCclass, resourcepath, imgIdx, parent): PreferenceCollectionNode.__init__(self, name, {}, resourcepath, imgIdx, parent) self.language = lang self.STCclass = STCclass def open(self, editor): # build list of all open STC's in the Editor openSTCViews = [] for modPge in editor.modules.values(): for view in modPge.model.views.values(): if isinstance(view, self.STCclass): openSTCViews.append(view) # also check the shell if Preferences.psPythonShell == 'Shell': if isinstance(editor.shell, self.STCclass): openSTCViews.append(editor.shell) #elif Preferences.psPythonShell == 'PyCrust': # if self.language == 'python': # openSTCViews.append(editor.shell.shellWin) dlg = STCStyleEditor.STCStyleEditDlg(editor, self.name, self.language, self.resourcepath, openSTCViews) try: dlg.ShowModal() finally: dlg.Destroy() return None, None def getURI(self): return '%s://%s' %(PreferenceCollectionNode.getURI(self), self.language) class SourceBasedPrefColNode(PreferenceCollectionNode): """ Preference collection represented by the global names in python module Only names which are also defined in properties are returned except when properties is a special match all tuple; ('*',) This only applies to names assigned to values ( x = 123 ) not to global names defined by classes functions and imports. """ def __init__(self, name, props, resourcepath, imgIdx, parent, showBreaks=True): PreferenceCollectionNode.__init__(self, name, props, resourcepath, imgIdx, parent) self.showBreakLines = showBreaks def load(self): # All preferences are local import moduleparse module = moduleparse.Module(self.name, open(self.resourcepath).readlines()) values = [] comments = [] options = [] # keep only names defined in the property list for name in module.global_order[:]: if name[0] == '_' or self.properties != ('*',) and \ name not in self.properties: module.global_order.remove(name) del module.globals[name] else: # XXX Should handle multiline assign code = '\n'.join(module.source[\ module.globals[name].start-1 : \ module.globals[name].end]) # Extract value s = code.find('=') if s != -1: values.append(code[s+1:].strip()) else: values.append('') # Read possible comment/help or options comment = [] option = '' idx = module.globals[name].start-2 while idx >= 0: line = module.source[idx].strip() if len(line) > 11 and line[:11] == '## options:': option = line[11:].strip() idx = idx - 1 elif len(line) > 8 and line[:8] == '## type:': option = '##'+line[8:].strip() idx = idx - 1 elif line and line[0] == '#': comment.append(line[1:].lstrip()) idx = idx - 1 else: break comment.reverse() comments.append('\n'.join(comment)) options.append(option) if self.showBreakLines: breaks = module.break_lines else: breaks = {} return (module.global_order, values, module.globals, comments, options, breaks) def save(self, filename, data): """ Updates one property """ src = open(self.resourcepath).readlines() src[data[2].start-1] = '%s = %s\n' % (data[0], data[1]) open(self.resourcepath, 'w').writelines(src) class UsedModuleSrcBsdPrefColNode(SourceBasedPrefColNode): """ Also update the value of a global attribute of an imported module """ def __init__(self, name, props, resourcepath, imgIdx, parent, module, showBreaks=True): SourceBasedPrefColNode.__init__(self, name, props, resourcepath, imgIdx, parent, showBreaks) self.module = module def save(self, filename, data): SourceBasedPrefColNode.save(self, filename, data) if hasattr(self.module, data[0]): setattr(self.module, data[0], eval(data[1], vars(Preferences))) class KeyDefsSrcPrefColNode(PreferenceCollectionNode): """ Preference collection representing the key bindings """ def __init__(self, name, props, resourcepath, imgIdx, parent, keyDefs): PreferenceCollectionNode.__init__(self, name, props, resourcepath, imgIdx, parent) self.showBreakLines = True self._editor = None def open(self, editor): PreferenceCollectionNode.open(self, editor) self._editor = editor def load(self): import moduleparse src = open(self.resourcepath).readlines() module = moduleparse.Module(self.name, src) # find keydefs keydefs = {} names = [] values = [] start = end = idx = -1 for line in src: idx = idx + 1 line = line.strip() if line == 'keyDefs = {': start = idx elif start != -1 and line: if line[-1] == '}': end = idx break elif line[0] != '#': colon = line.find(':') if colon == -1: raise Exception('Invalid KeyDef item: %s'%line) name = line[:colon].rstrip()[1:-1] val = line[colon+1:].lstrip() keydefs[name] = moduleparse.CodeBlock(val, idx+1, idx+1) names.append(name) values.append(val) return (names, values, keydefs, ['']*len(keydefs), ['## keydef']*len(keydefs), module.break_lines) def save(self, filename, data): """ Updates one key:val in keydefs dict """ # Update source file src = open(self.resourcepath).readlines() src[data[2].start-1] = \ " '%s'%s: %s\n" % (data[0], (12 - len(data[0]))*' ', data[1]) open(self.resourcepath, 'w').writelines(src) # Update dictionary Preferences.keyDefs[data[0]] = eval(data[1], vars(Preferences))[0] # Update editor menus self._editor.setupToolBar() self._editor.updateStaticMenuShortcuts() self._editor.shell.bindShortcuts() class ConfigBasedPrefsColNode(PreferenceCollectionNode): """ Preferences driven by config files """ pass #---Companions------------------------------------------------------------------ from PropEdit import PropertyEditors, InspectorEditorControls class KeyDefConfPropEdit(PropertyEditors.ConfPropEdit): def inspectorEdit(self): self.editorCtrl = InspectorEditorControls.ButtonIEC(self, self.value) self.editorCtrl.createControl(self.parent, self.idx, self.width, self.edit) def edit(self, event): import KeyDefsDlg dlg = KeyDefsDlg.KeyDefsDialog(self.parent, self.name, self.value) try: if dlg.ShowModal() == wx.ID_OK: self.editorCtrl.value = dlg.result self.inspectorPost(False) finally: dlg.Destroy() def getDisplayValue(self): try: return eval(self.value, {'wx': wx})[0][2] except Exception, err: return str(err) class PreferenceCompanion(ExplorerNodes.ExplorerCompanion): def __init__(self, name, prefNode, ): ExplorerNodes.ExplorerCompanion.__init__(self, name) self.prefNode = prefNode self._breaks = {} typeMap = {} customTypeMap = {'filepath': PropertyEditors.FilepathConfPropEdit, 'dirpath': PropertyEditors.DirpathConfPropEdit, 'keydef': KeyDefConfPropEdit} def getPropEditor(self, prop): # XXX Using name equality to identify _breaks' prop edit is ugly ! for aProp in self.propItems: if aProp[0] == prop: break else: raise Exception('Property "%s" not found'%prop) srcVal = aProp[1] opts = aProp[4] if prop in self._breaks.values(): return None if opts: if opts[:2] == '##': return self.customTypeMap.get(opts[2:].strip(), None) else: return PropertyEditors.EnumConfPropEdit if srcVal.lower() in ('true', 'false'): return PropertyEditors.BoolConfPropEdit try: val = eval(srcVal, vars(Preferences)) except Exception, error: return PropertyEditors.StrConfPropEdit if isinstance(val, wx.Colour): return PropertyEditors.ColourConfPropEdit return self.typeMap.get(type(val), PropertyEditors.StrConfPropEdit) def getPropertyHelp(self, propName): for prop in self.propItems: if prop[0] == propName: return prop[3] else: return propName def getPropertyItems(self): order, vals, props, comments, options, self._breaks = self.prefNode.load() # remove empty break lines (-----------------------) for lineNo in self._breaks.keys(): if not self._breaks[lineNo]: del self._breaks[lineNo] breakLinenos = self._breaks.keys() breakLinenos.sort() if len(breakLinenos): breaksIdx = 0 else: breaksIdx = None res = [] for name, value, comment, option in map(None, order, vals, comments, options): if breaksIdx is not None: # find closest break above property while breaksIdx < len(breakLinenos)-1 and \ props[name].start > breakLinenos[breaksIdx+1]: breaksIdx += 1 if breaksIdx >= len(breakLinenos): breaksIdx = None if breaksIdx is not None and props[name].start > breakLinenos[breaksIdx]: res.append( (self._breaks[breakLinenos[breaksIdx]], '', None, '', '') ) breaksIdx += 1 #if breaksIdx == len(self._breaks) -1: # breaksIdx = None #else: # breaksIdx = breaksIdx + 1 res.append( (name, value, props[name], comment, option) ) return res def setPropHook(self, name, value, oldProp): # XXX validate etc. try: eval(value, vars(Preferences)) except Exception, error: wx.LogError('Error: '+str(error)) return False else: newProp = (name, value) + oldProp[2:] self.prefNode.save(name, newProp) return True def persistedPropVal(self, name, setterName): if name in self._breaks.values(): return 'PROP_CATEGORY' else: return None def getPropOptions(self, name): for prop in self.propItems: if prop[0] == name: strOpts = prop[4] if strOpts and strOpts[:2] != '##': return self.eval(strOpts) else: return () else: return () def getPropNames(self, name): for prop in self.propItems: if prop[0] == name: strOpts = prop[4] if strOpts and strOpts[:2] != '##': return methodparse.safesplitfields(strOpts, ',') else: return () else: return () def eval(self, expr): import PaletteMapping return PaletteMapping.evalCtrl(expr, vars(Preferences)) ## def GetProp(self, name): ## ExplorerNodes.ExplorerCompanion.GetProp(self, name) ## return self.findProp(name)[0][1] class CorePluginsGroupNode(PreferenceGroupNode): """ """ protocol = 'prefs.group.plug-in.core' defName = 'CorePluginPrefsGroup' def __init__(self): name = 'Core support' PreferenceGroupNode.__init__(self, name, None) self.vetoSort = True self.preferences = [] def isFolderish(self): return True def openList(self): return self.preferences def notifyBeginLabelEdit(self, event): event.Veto() def getPluginSection(pluginFile): pluginPath = os.path.dirname(pluginFile) return Preferences.pluginSections[ Preferences.pluginPaths.index(pluginPath)] class PluginFileExplNode(ExplorerNodes.ExplorerNode): """ """ def __init__(self, name, enabled, status, resourcepath, imgIdx): ExplorerNodes.ExplorerNode.__init__(self, name, resourcepath, None, imgIdx, None, {}) self.pluginEnabled = enabled self.pluginStatus = status def open(self, editor): """ """ if self.pluginEnabled: msg = 'Disable' else: msg = 'Enable' if wx.MessageBox('%s %s?'%(msg, self.name), 'Confirm Toggle Plug-in', wx.YES_NO | wx.ICON_QUESTION) == wx.YES: section = getPluginSection(self.resourcepath) ordered, disabled = Plugins.readPluginsState(section) if self.pluginEnabled: disabled.append(self.name) else: try: disabled.remove(self.name) except ValueError: pass #Plugins.writeInitPluginGlobals(initPluginPath, initPluginGlobals) Plugins.writePluginsState(section, ordered, disabled) editor.explorer.list.refreshCurrent() return None, None def getURI(self): return '%s (%s)'%(ExplorerNodes.ExplorerNode.getURI(self), self.pluginStatus) def isFolderish(self): return False def notifyBeginLabelEdit(self, event): event.Veto() def changeOrder(self, direction): section = getPluginSection(self.resourcepath) #initPluginPath = os.path.dirname(self.resourcepath) ordered, disabled = Plugins.readPluginsState(section) #ordered = initPluginGlobals['__ordered__'] try: idx = ordered.index(self.name) except ValueError: idx = len(ordered)+1 else: del ordered[idx] idx = max(idx + direction, 0) if idx <= len(ordered): ordered.insert(idx, self.name) #Plugins.writeInitPluginGlobals(initPluginPath, initPluginGlobals) Plugins.writePluginsState(section, ordered, disabled) class PluginFilesGroupNode(PreferenceGroupNode): """ Represents a group of preference collections """ protocol = 'prefs.group.plug-in.files' defName = 'PluginFilesPrefsGroup' def __init__(self): name = 'Plug-in files' PreferenceGroupNode.__init__(self, name, None) def openList(self): res = [] splitext = os.path.splitext for filename, ordered, enabled in Plugins.buildPluginExecList(): if os.path.basename(filename) == '__init__.plug-in.py': continue name = splitext(splitext(os.path.basename(filename))[0])[0] if not enabled: name = splitext(name)[0] status = 'Disabled' imgIdx = EditorHelper.imgSystemObjDisabled else: fn = filename.lower() if Preferences.failedPlugins.has_key(fn): kind, msg = Preferences.failedPlugins[fn] if kind == 'Skipped': status = 'Skipped plug-in: %s'% msg imgIdx = EditorHelper.imgSystemObjPending else: status = 'Broken plug-in: %s'% msg imgIdx = EditorHelper.imgSystemObjBroken elif fn in Preferences.installedPlugins: if ordered: status = 'Installed, ordered' imgIdx = EditorHelper.imgSystemObjOrdered else: status = 'Installed' imgIdx = EditorHelper.imgSystemObj else: status = 'Pending restart' imgIdx = EditorHelper.imgSystemObjPending res.append(PluginFileExplNode(name, enabled, status, filename, imgIdx)) return res class PluginFilesGroupNodeController(ExplorerNodes.Controller): moveUpBmp = 'Images/Shared/up.png' moveDownBmp = 'Images/Shared/down.png' itemDescr = 'item' def __init__(self, editor, list, inspector, controllers): ExplorerNodes.Controller.__init__(self, editor) self.list = list self.menu = wx.Menu() [wxID_PF_TOGGLE, wxID_PF_OPEN, wxID_PF_UP, wxID_PF_DOWN] = Utils.wxNewIds(4) self.transpMenuDef = [ (wxID_PF_TOGGLE, 'Toggle Enable/Disabled', self.OnToggleState, '-'), (wxID_PF_OPEN, 'Open plug-in file', self.OnOpenPlugin, '-'), (-1, '-', None, ''), (wxID_PF_UP, 'Move up', self.OnMovePluginUp, self.moveUpBmp), (wxID_PF_DOWN, 'Move down', self.OnMovePluginDown, self.moveDownBmp), ] self.setupMenu(self.menu, self.list, self.transpMenuDef) self.toolbarMenus = [self.transpMenuDef] def destroy(self): self.transpMenuDef = [] self.toolbarMenus = [] self.menu.Destroy() def OnToggleState(self, event): if self.list.node: ms = self.list.getMultiSelection() nodes = self.getNodesForSelection(ms) for node in nodes: node.open(self.editor) def OnOpenPlugin(self, event): if self.list.node: ms = self.list.getMultiSelection() nodes = self.getNodesForSelection(ms) for node in nodes: self.editor.openOrGotoModule(node.resourcepath) def OnMovePluginUp(self, event): if self.list.node: ms = self.list.getMultiSelection() nodes = self.getNodesForSelection(ms) if len(nodes) != 1: wx.LogError('Can only move 1 at a time') else: node = nodes[0] idx = self.list.items.index(node) if idx == 0: wx.LogError('Already at the beginning') else: name = node.name node.changeOrder(-1) self.list.refreshCurrent() self.list.selectItemNamed(name) def OnMovePluginDown(self, event): if self.list.node: ms = self.list.getMultiSelection() nodes = self.getNodesForSelection(ms) if len(nodes) != 1: wx.LogError('Can only move 1 at a time') else: node = nodes[0] idx = self.list.items.index(node) ## if idx >= len(self.list.items) -1: ## wx.LogError('Already at the end') ## else: name = node.name node.changeOrder(1) self.list.refreshCurrent() self.list.selectItemNamed(name) class TransportPluginExplNode(ExplorerNodes.ExplorerNode): """ """ protocol = 'transport' def __init__(self, name, status, imgIdx): ExplorerNodes.ExplorerNode.__init__(self, name, '%s (%s)'%(name, status), None, imgIdx, None, {}) self.status = status def open(self, editor): return None, None class TransportPluginsController(ExplorerNodes.Controller): addItemBmp = 'Images/Shared/NewItem.png' removeItemBmp = 'Images/Shared/DeleteItem.png' moveUpBmp = 'Images/Shared/up.png' moveDownBmp = 'Images/Shared/down.png' itemDescr = 'item' def __init__(self, editor, list, inspector, controllers): ExplorerNodes.Controller.__init__(self, editor) self.list = list self.menu = wx.Menu() [wxID_TP_NEW, wxID_TP_DEL, wxID_TP_UP, wxID_TP_DOWN] = Utils.wxNewIds(4) self.transpMenuDef = [ (wxID_TP_NEW, 'Add new '+self.itemDescr, self.OnNewTransport, self.addItemBmp), (wxID_TP_DEL, 'Remove '+self.itemDescr, self.OnDeleteTransport, self.removeItemBmp), (-1, '-', None, ''), (wxID_TP_UP, 'Move up', self.OnMoveTransportUp, self.moveUpBmp), (wxID_TP_DOWN, 'Move down', self.OnMoveTransportDown, self.moveDownBmp), ] self.setupMenu(self.menu, self.list, self.transpMenuDef) self.toolbarMenus = [self.transpMenuDef] def destroy(self): self.transpMenuDef = [] self.toolbarMenus = [] self.menu.Destroy() def editorUpdateNotify(self, info=''): self.OnReloadItems() def OnReloadItems(self, event=None): if self.list.node: self.list.refreshCurrent() def moveTransport(self, node, idx, direc): names = [] for item in self.list.items: names.append(item.name) name = names[idx] del names[idx] names.insert(idx + direc, name) self.list.node.updateOrder(names) self.list.refreshCurrent() self.list.selectItemByIdx(idx+direc+1) def OnMoveTransportUp(self, event): if self.list.node: ms = self.list.getMultiSelection() nodes = self.getNodesForSelection(ms) if len(nodes) != 1: wx.LogError('Can only move 1 at a time') else: node = nodes[0] idx = self.list.items.index(node) if idx == 0: wx.LogError('Already at the beginning') else: self.moveTransport(node, idx, -1) def OnMoveTransportDown(self, event): if self.list.node: ms = self.list.getMultiSelection() nodes = self.getNodesForSelection(ms) if len(nodes) != 1: wx.LogError('Can only move 1 at a time') else: node = nodes[0] idx = self.list.items.index(node) if idx >= len(self.list.items) -1: wx.LogError('Already at the end') else: self.moveTransport(node, idx, 1) def OnNewTransport(self, event): pass def OnDeleteTransport(self, event): pass class TransportPluginsLoadOrderController(TransportPluginsController): itemDescr = 'Transport module' def OnNewTransport(self, event): dlg = wx.TextEntryDialog(self.list, 'Enter the fully qualified Python '\ 'object path to \nthe Transport module. E.g. Explorers.FileExplorer', 'New Transport', '') try: if dlg.ShowModal() != wx.ID_OK: return transportModulePath = dlg.GetValue() finally: dlg.Destroy() if not self.list.node.checkValidModulePath(transportModulePath): if wx.MessageBox('Cannot locate the specified module path,\n'\ 'are you sure you want to continue?', 'Module not found', wx.YES_NO | wx.ICON_EXCLAMATION) == wx.NO: return names = [] for item in self.list.items: names.append(item.name) names.append(transportModulePath) self.list.node.updateOrder(names) self.list.refreshCurrent() def OnDeleteTransport(self, event): selNames = self.list.getMultiSelection() nodes = self.getNodesForSelection(selNames) names = [] for item in self.list.items: names.append(item.name) for item in nodes: names.remove(item.name) self.list.node.updateOrder(names) self.list.refreshCurrent() class TransportPluginsTreeDisplayOrderController(TransportPluginsController): itemDescr = 'Transports tree node' def OnNewTransport(self, event): dlg = wx.TextEntryDialog(self.list, 'Enter the protocol identifier. E.g. '\ 'ftp, ssh', 'New Transports Tree Node', '') try: if dlg.ShowModal() != wx.ID_OK: return protocol = dlg.GetValue() finally: dlg.Destroy() names = [] for item in self.list.items: names.append(item.name) names.append(protocol) self.list.node.updateOrder(names) self.list.node.checkConfigEntry(protocol) self.list.refreshCurrent() def OnDeleteTransport(self, event): selNames = self.list.getMultiSelection() nodes = self.getNodesForSelection(selNames) names = [] for item in self.list.items: names.append(item.name) for item in nodes: names.remove(item.name) self.list.node.clearEmptyConfigEntry(item.name) self.list.node.updateOrder(names) self.list.refreshCurrent() class TransportPluginsLoadOrderGroupNode(PreferenceGroupNode): """ """ protocol = 'prefs.group.plug-in.transport.load-order' defName = 'TransportPluginsPrefsGroup' def __init__(self): name = 'Loading order' PreferenceGroupNode.__init__(self, name, None) def openList(self): conf = Utils.createAndReadConfig('Explorer') modules = eval(conf.get('explorer', 'installedtransports'), {}) assert isinstance(modules, types.ListType) res = [] for mod in modules: if mod in ExplorerNodes.installedModules: status = 'Installed' imgIdx = EditorHelper.imgSystemObjOrdered elif mod in ExplorerNodes.failedModules.keys(): status = 'Broken: %s'%ExplorerNodes.failedModules[mod] imgIdx = EditorHelper.imgSystemObjBroken else: status = 'Pending restart' imgIdx = EditorHelper.imgSystemObjPending res.append(TransportPluginExplNode(mod, status, imgIdx)) return res def updateOrder(self, newOrder): conf = Utils.createAndReadConfig('Explorer') conf.set('explorer', 'installedtransports', pprint.pformat(newOrder)) Utils.writeConfig(conf) def checkValidModulePath(self, name): try: Utils.find_dotted_module(name) except ImportError, err: #print str(err) return False else: return True class TransportPluginsTreeDisplayOrderGroupNode(PreferenceGroupNode): """ """ protocol = 'prefs.group.plug-in.transport.tree-order' defName = 'TransportPluginsPrefsGroup' def __init__(self): name = 'Tree display order' PreferenceGroupNode.__init__(self, name, None) def openList(self): conf = Utils.createAndReadConfig('Explorer') treeOrder = eval(conf.get('explorer', 'transportstree'), {}) assert isinstance(treeOrder, type([])) res = [] for prot in treeOrder: if not ExplorerNodes.nodeRegByProt.has_key(prot): status = 'Protocol not installed' imgIdx = EditorHelper.imgSystemObjPending else: status = 'Installed' imgIdx = EditorHelper.imgSystemObjOrdered res.append(TransportPluginExplNode(prot, status, imgIdx)) return res def updateOrder(self, newOrder): conf = Utils.createAndReadConfig('Explorer') conf.set('explorer', 'transportstree', pprint.pformat(newOrder)) Utils.writeConfig(conf) def checkConfigEntry(self, protocol): conf = Utils.createAndReadConfig('Explorer') if not conf.has_option('explorer', protocol): conf.set('explorer', protocol, '{}') Utils.writeConfig(conf) def clearEmptyConfigEntry(self, protocol): conf = Utils.createAndReadConfig('Explorer') if conf.has_option('explorer', protocol) and \ eval(conf.get('explorer', protocol).strip(), {}) == {}: conf.remove_option('explorer', protocol) Utils.writeConfig(conf) class HelpConfigPGN(PreferenceGroupNode): """ """ protocol = 'prefs.group.help.config' defName = 'HelpConfigPrefsGroup' def __init__(self): name = 'Help system' PreferenceGroupNode.__init__(self, name, None) def openList(self): return class HelpConfigBooksPGN(PreferenceGroupNode): """ """ protocol = 'prefs.group.help.config.books' defName = 'HelpConfigBooksPrefsGroup' def __init__(self): name = 'Help books' PreferenceGroupNode.__init__(self, name, None) def openList(self): bookPaths = self.readBooks() res = [] for bookPath in bookPaths: try: res.append(HelpConfigBookNode(bookPath)) except IOError, err: # too disruptive to display an error pass return res # return [HelpConfigBookNode(bookPath) # for bookPath in bookPaths] def readBooks(self): return eval(Utils.createAndReadConfig('Explorer').get('help', 'books'), {}) def writeBooks(self, books): conf = Utils.createAndReadConfig('Explorer') conf.set('help', 'books', pprint.pformat(books)) Utils.writeConfig(conf) def preparePath(self, path): helpPath = Preferences.pyPath+'/Docs/' if path.startswith('file://'): path = path[7:] # Add relative paths for files inside Docs directory if os.path.normcase(path).startswith(os.path.normcase(helpPath)): return path[len(helpPath):] else: return path def editBook(self, curPath, newPath): books = self.readBooks() books[books.index(curPath)] = self.preparePath(newPath) self.writeBooks(books) def addBook(self, path): path = self.preparePath(path) self.writeBooks(self.readBooks() + [path]) def removeBook(self, path): books = self.readBooks() books.remove(path) self.writeBooks(books) def updateOrder(self, paths): self.writeBooks(paths) class HelpConfigBookNode(ExplorerNodes.ExplorerNode): """ """ protocol = 'help.book' def __init__(self, resourcepath): fullpath = self.getAbsPath(resourcepath) name = os.path.basename(resourcepath) if os.path.splitext(fullpath)[1] == '.hhp': # Peek at title inside hhp file for line in open(fullpath).readlines(): if line.startswith('Title'): name = line.split('=')[1].strip() ExplorerNodes.ExplorerNode.__init__(self, name, resourcepath, None, EditorHelper.imgHelpBook, None, {}) def open(self, editor): return None, None ## def getURI(self): ## return '%s (%s)'%(ExplorerNodes.ExplorerNode.getURI(self), ## self.pluginStatus) def isFolderish(self): return False def notifyBeginLabelEdit(self, event): event.Veto() def getAbsPath(self, resourcepath): if not os.path.isabs(resourcepath): return os.path.join(Preferences.pyPath, 'Docs', resourcepath) else: return resourcepath class HelpConfigBooksController(ExplorerNodes.Controller): addItemBmp = 'Images/Shared/NewItem.png' removeItemBmp = 'Images/Shared/DeleteItem.png' moveUpBmp = 'Images/Shared/up.png' moveDownBmp = 'Images/Shared/down.png' itemDescr = 'item' def __init__(self, editor, list, inspector, controllers): ExplorerNodes.Controller.__init__(self, editor) self.list = list self.menu = wx.Menu() [wxID_HB_EDIT, wxID_HB_NEW, wxID_HB_DEL, wxID_HB_UP, wxID_HB_DOWN, wxID_HB_REST, wxID_HB_CLRI, wxID_HB_OPEN] = Utils.wxNewIds(8) self.helpBooksMenuDef = [ (wxID_HB_EDIT, 'Edit '+self.itemDescr, self.OnEditBookPath, '-'), (wxID_HB_NEW, 'Add new '+self.itemDescr, self.OnNewBook, self.addItemBmp), (wxID_HB_DEL, 'Remove '+self.itemDescr, self.OnRemoveBook, self.removeItemBmp), (-1, '-', None, ''), (wxID_HB_UP, 'Move up', self.OnMoveBookUp, self.moveUpBmp), (wxID_HB_DOWN, 'Move down', self.OnMoveBookDown, self.moveDownBmp), (-1, '-', None, '-'), (wxID_HB_OPEN, 'Open hhp file', self.OnOpenHHP, '-'), (-1, '-', None, '-'), (wxID_HB_REST, 'Restart the help system', self.OnRestartHelp, '-'), (wxID_HB_CLRI, 'Clear the help indexes', self.OnClearHelpIndexes, '-'), ] self.setupMenu(self.menu, self.list, self.helpBooksMenuDef) self.toolbarMenus = [self.helpBooksMenuDef] def destroy(self): self.helpBooksMenuDef = () self.toolbarMenus = () self.menu.Destroy() def editorUpdateNotify(self, info=''): self.OnReloadItems() def OnReloadItems(self, event=None): if self.list.node: self.list.refreshCurrent() def moveBook(self, node, idx, direc): paths = [item.resourcepath for item in self.list.items] path = paths[idx] del paths[idx] paths.insert(idx + direc, path) self.list.node.updateOrder(paths) self.list.refreshCurrent() self.list.selectItemByIdx(idx+direc+1) def OnMoveBookUp(self, event): if self.list.node: ms = self.list.getMultiSelection() nodes = self.getNodesForSelection(ms) if len(nodes) != 1: wx.LogError('Can only move 1 at a time') else: node = nodes[0] idx = self.list.items.index(node) if idx == 0: wx.LogError('Already at the beginning') else: self.moveBook(node, idx, -1) def OnMoveBookDown(self, event): if self.list.node: ms = self.list.getMultiSelection() nodes = self.getNodesForSelection(ms) if len(nodes) != 1: wx.LogError('Can only move 1 at a time') else: node = nodes[0] idx = self.list.items.index(node) if idx >= len(self.list.items) -1: wx.LogError('Already at the end') else: self.moveBook(node, idx, 1) def OnEditBookPath(self, event): if self.list.node: ms = self.list.getMultiSelection() for node in self.getNodesForSelection(ms): if not os.path.isabs(node.resourcepath): path = os.path.join(Preferences.pyPath, 'Docs', node.resourcepath) else: path = node.resourcepath curpath, curfile = os.path.split(path) newpath = self.editor.openFileDlg('AllFiles', curdir=curpath) if newpath: self.list.node.editBook(node.resourcepath, path) self.list.refreshCurrent() def OnNewBook(self, event): path = self.editor.openFileDlg('AllFiles', curdir=Preferences.pyPath+'/Docs') if path and self.list.node: self.list.node.addBook(path) self.list.refreshCurrent() def OnRemoveBook(self, event): if self.list.node: ms = self.list.getMultiSelection() for node in self.getNodesForSelection(ms): self.list.node.removeBook(node.resourcepath) self.list.refreshCurrent() def OnRestartHelp(self, event): import Help Help.delHelp() wx.Yield() Help.initHelp() def OnClearHelpIndexes(self, event): import Help cd = Help.getCacheDir() for name in os.listdir(cd): if os.path.splitext(name)[1] == '.cached': os.remove(os.path.join(cd, name)) wx.LogMessage('Deleted %s'%name) def OnOpenHHP(self, event): if self.list.node: ms = self.list.getMultiSelection() for node in self.getNodesForSelection(ms): self.editor.openOrGotoModule(node.getAbsPath(node.resourcepath)) #------------------------------------------------------------------------------- ExplorerNodes.register(BoaPrefGroupNode) ExplorerNodes.register(PluginFilesGroupNode, controller=PluginFilesGroupNodeController) ExplorerNodes.register(TransportPluginsLoadOrderGroupNode, controller=TransportPluginsLoadOrderController) ExplorerNodes.register(TransportPluginsTreeDisplayOrderGroupNode, controller=TransportPluginsTreeDisplayOrderController) ExplorerNodes.register(HelpConfigBooksPGN, controller=HelpConfigBooksController)