1
#-----------------------------------------------------------------------------
2
# Name: PrefsExplorer.py
5
# Author: Riaan Booysen
8
# RCS-ID: $Id: PrefsExplorer.py,v 1.15 2004/08/16 13:22:00 riaan Exp $
9
# Copyright: (c) 2001 - 2004
11
#-----------------------------------------------------------------------------
12
print 'importing Explorers.PrefsExplorer'
13
import os, sys, glob, pprint, imp
16
from wxPython import wx
19
import Preferences, Utils, Plugins
22
from Models import EditorHelper
23
from Views import STCStyleEditor
24
import methodparse, relpath
26
class PreferenceGroupNode(ExplorerNodes.ExplorerNode):
27
""" Represents a group of preference collections """
28
protocol = 'prefs.group'
29
defName = 'PrefsGroup'
30
def __init__(self, name, parent):
31
ExplorerNodes.ExplorerNode.__init__(self, name, name, None,
32
EditorHelper.imgPrefsFolder, None)
37
def isFolderish(self):
41
return self.preferences
43
def notifyBeginLabelEdit(self, event):
46
class BoaPrefGroupNode(PreferenceGroupNode):
47
""" The Preference node in the Explorer """
48
protocol = 'boa.prefs.group'
49
customPrefs = [] # list of tuples ('name', 'file')
50
def __init__(self, parent):
51
PreferenceGroupNode.__init__(self, 'Preferences', parent)
54
prefImgIdx = EditorHelper.imgSystemObj
55
stcPrefImgIdx = EditorHelper.imgPrefsSTCStyles
57
self.source_pref = PreferenceGroupNode('Source', self)
59
self.source_pref.preferences = [
60
UsedModuleSrcBsdPrefColNode('Default settings',
61
Preferences.exportedSTCProps, os.path.join(Preferences.rcPath,
62
'prefs.rc.py'), prefImgIdx, self, Preferences, true)]
64
for name, lang, STCClass, stylesFile in ExplorerNodes.langStyleInfoReg:
65
if not os.path.isabs(stylesFile):
66
stylesFile = os.path.join(Preferences.rcPath, stylesFile)
67
self.source_pref.preferences.append(STCStyleEditPrefsCollNode(
68
name, lang, STCClass, stylesFile, stcPrefImgIdx, self))
69
self.preferences.append(self.source_pref)
71
self.general_pref = UsedModuleSrcBsdPrefColNode('General',
72
Preferences.exportedProperties, os.path.join(Preferences.rcPath,
73
'prefs.rc.py'), prefImgIdx, self, Preferences)
74
self.preferences.append(self.general_pref)
76
self.platform_pref = UsedModuleSrcBsdPrefColNode('Platform specific',
77
Preferences.exportedProperties2, os.path.join(Preferences.rcPath,
78
'prefs.%s.rc.py' % (wx.wxPlatform == '__WXMSW__' and 'msw' or 'gtk')),
79
prefImgIdx, self, Preferences)
80
self.preferences.append(self.platform_pref)
82
self.keys_pref = KeyDefsSrcPrefColNode('Key bindings', ('*',),
83
os.path.join(Preferences.rcPath, 'prefs.keys.rc.py'), prefImgIdx,
84
self, Preferences.keyDefs)
85
self.preferences.append(self.keys_pref)
87
for name, filename in self.customPrefs:
88
if not os.path.isabs(filename):
89
filename = os.path.join(Preferences.rcPath, filename)
90
self.preferences.append(UsedModuleSrcBsdPrefColNode(name,
91
('*',), filename, prefImgIdx, self, Preferences))
93
## self.pychecker_pref = SourceBasedPrefColNode('PyChecker',
94
## ('*',), Preferences.pyPath+'/.pycheckrc', prefImgIdx, self)
95
## self.preferences.append(self.pychecker_pref)
97
self.plugin_pref = PreferenceGroupNode('Plug-ins', self)
99
self.core_plugpref = UsedModuleSrcBsdPrefColNode('Core support',
100
Preferences.exportedCorePluginProps, os.path.join(Preferences.rcPath,
101
'prefs.rc.py'), prefImgIdx, self, Preferences, true)
102
self.plugin_plugpref = UsedModuleSrcBsdPrefColNode('Preferences', Preferences.exportedPluginProps,#('*',),
103
os.path.join(Preferences.rcPath, 'prefs.plug-ins.rc.py'), prefImgIdx,
104
self, Preferences, true)
105
self.files_plugpref = PluginFilesGroupNode()
106
self.transp_plugpref = PreferenceGroupNode('Transports', self)
107
self.transp_plugpref.preferences = [
108
TransportPluginsLoadOrderGroupNode(),
109
TransportPluginsTreeDisplayOrderGroupNode(),
112
self.plugin_pref.preferences = [
114
self.transp_plugpref,
116
self.plugin_plugpref,
119
self.preferences.insert(1, self.plugin_pref)
121
self.help_pref = HelpConfigBooksPGN()
123
self.preferences.insert(2, self.help_pref)
126
class PreferenceCollectionNode(ExplorerNodes.ExplorerNode):
127
""" Represents an inspectable preference collection """
129
def __init__(self, name, props, resourcepath, imgIdx, parent):
130
ExplorerNodes.ExplorerNode.__init__(self, name, resourcepath, None,
133
def open(self, editor):
134
""" Populate inspector with preference items """
135
comp = PreferenceCompanion(self.name, self)
138
# Select in inspector
139
editor.inspector.restore()
140
if editor.inspector.pages.GetSelection() != 1:
141
editor.inspector.pages.SetSelection(1)
142
editor.inspector.selectObject(comp, false)
145
def isFolderish(self):
149
raise 'Not implemented'
151
def save(self, filename, data):
154
def notifyBeginLabelEdit(self, event):
157
class STCStyleEditPrefsCollNode(PreferenceCollectionNode):
158
protocol = 'stc.prefs'
159
def __init__(self, name, lang, STCclass, resourcepath, imgIdx, parent):
160
PreferenceCollectionNode.__init__(self, name, {}, resourcepath, imgIdx, parent)
162
self.STCclass = STCclass
164
def open(self, editor):
165
# build list of all open STC's in the Editor
167
for modPge in editor.modules.values():
168
for view in modPge.model.views.values():
169
if isinstance(view, self.STCclass):
170
openSTCViews.append(view)
172
# also check the shell
173
if Preferences.psPythonShell == 'Shell':
174
if isinstance(editor.shell, self.STCclass):
175
openSTCViews.append(editor.shell)
176
#elif Preferences.psPythonShell == 'PyCrust':
177
# if self.language == 'python':
178
# openSTCViews.append(editor.shell.shellWin)
180
dlg = STCStyleEditor.STCStyleEditDlg(editor, self.name, self.language,
181
self.resourcepath, openSTCViews)
183
finally: dlg.Destroy()
188
return '%s://%s' %(PreferenceCollectionNode.getURI(self), self.language)
191
class SourceBasedPrefColNode(PreferenceCollectionNode):
192
""" Preference collection represented by the global names in python module
194
Only names which are also defined in properties are returned
195
except when properties is a special match all tuple; ('*',)
197
This only applies to names assigned to values ( x = 123 ) not to global
198
names defined by classes functions and imports.
200
def __init__(self, name, props, resourcepath, imgIdx, parent, showBreaks=true):
201
PreferenceCollectionNode.__init__(self, name, props, resourcepath,
203
self.showBreakLines = showBreaks
206
# All preferences are local
209
module = moduleparse.Module(self.name,
210
open(self.resourcepath).readlines())
215
# keep only names defined in the property list
216
for name in module.global_order[:]:
217
if name[0] == '_' or self.properties != ('*',) and \
218
name not in self.properties:
219
module.global_order.remove(name)
220
del module.globals[name]
222
# XXX Should handle multiline assign
223
code = '\n'.join(module.source[\
224
module.globals[name].start-1 : \
225
module.globals[name].end])
230
values.append(code[s+1:].strip())
234
# Read possible comment/help or options
237
idx = module.globals[name].start-2
239
line = module.source[idx].strip()
240
if len(line) > 11 and line[:11] == '## options:':
241
option = line[11:].strip()
243
elif len(line) > 8 and line[:8] == '## type:':
244
option = '##'+line[8:].strip()
246
elif line and line[0] == '#':
247
comment.append(line[1:].lstrip())
252
comments.append('\n'.join(comment))
253
options.append(option)
255
if self.showBreakLines: breaks = module.break_lines
258
return (module.global_order, values, module.globals, comments, options,
261
def save(self, filename, data):
262
""" Updates one property """
263
src = open(self.resourcepath).readlines()
264
src[data[2].start-1] = '%s = %s\n' % (data[0], data[1])
265
open(self.resourcepath, 'w').writelines(src)
267
class UsedModuleSrcBsdPrefColNode(SourceBasedPrefColNode):
268
""" Also update the value of a global attribute of an imported module """
269
def __init__(self, name, props, resourcepath, imgIdx, parent, module,
271
SourceBasedPrefColNode.__init__(self, name, props, resourcepath, imgIdx,
275
def save(self, filename, data):
276
SourceBasedPrefColNode.save(self, filename, data)
277
if hasattr(self.module, data[0]):
278
setattr(self.module, data[0], eval(data[1], vars(Preferences)))
280
class KeyDefsSrcPrefColNode(PreferenceCollectionNode):
281
""" Preference collection representing the key bindings """
282
def __init__(self, name, props, resourcepath, imgIdx, parent, keyDefs):
283
PreferenceCollectionNode.__init__(self, name, props, resourcepath,
285
self.showBreakLines = true
288
def open(self, editor):
289
PreferenceCollectionNode.open(self, editor)
290
self._editor = editor
295
src = open(self.resourcepath).readlines()
296
module = moduleparse.Module(self.name, src)
302
start = end = idx = -1
306
if line == 'keyDefs = {':
308
elif start != -1 and line:
313
colon = line.find(':')
314
if colon == -1: raise Exception('Invalid KeyDef item: %s'%line)
315
name = line[:colon].rstrip()[1:-1]
316
val = line[colon+1:].lstrip()
317
keydefs[name] = moduleparse.CodeBlock(val, idx+1, idx+1)
321
return (names, values, keydefs, ['']*len(keydefs),
322
['## keydef']*len(keydefs), module.break_lines)
324
def save(self, filename, data):
325
""" Updates one key:val in keydefs dict """
328
src = open(self.resourcepath).readlines()
329
src[data[2].start-1] = \
330
" '%s'%s: %s\n" % (data[0], (12 - len(data[0]))*' ', data[1])
331
open(self.resourcepath, 'w').writelines(src)
333
Preferences.keyDefs[data[0]] = eval(data[1], vars(Preferences))[0]
334
# Update editor menus
335
self._editor.setupToolBar()
336
self._editor.updateStaticMenuShortcuts()
337
self._editor.shell.bindShortcuts()
340
class ConfigBasedPrefsColNode(PreferenceCollectionNode):
341
""" Preferences driven by config files """
345
#---Companions------------------------------------------------------------------
347
from PropEdit import PropertyEditors, InspectorEditorControls
349
class KeyDefConfPropEdit(PropertyEditors.ConfPropEdit):
350
def inspectorEdit(self):
351
self.editorCtrl = InspectorEditorControls.ButtonIEC(self, self.value)
352
self.editorCtrl.createControl(self.parent, self.idx, self.width, self.edit)
354
def edit(self, event):
356
dlg = KeyDefsDlg.KeyDefsDialog(self.parent, self.name, self.value)
358
if dlg.ShowModal() == wx.wxID_OK:
359
self.editorCtrl.value = dlg.result
360
self.inspectorPost(false)
364
def getDisplayValue(self):
366
return eval(self.value, wx.__dict__)[0][2]
367
except Exception, err:
370
class PreferenceCompanion(ExplorerNodes.ExplorerCompanion):
371
def __init__(self, name, prefNode, ):
372
ExplorerNodes.ExplorerCompanion.__init__(self, name)
373
self.prefNode = prefNode
378
customTypeMap = {'filepath': PropertyEditors.FilepathConfPropEdit,
379
'dirpath': PropertyEditors.DirpathConfPropEdit,
380
'keydef': KeyDefConfPropEdit}
381
def getPropEditor(self, prop):
382
# XXX Using name equality to identify _breaks' prop edit is ugly !
383
for aProp in self.propItems:
384
if aProp[0] == prop: break
386
raise Exception('Property "%s" not found'%prop)
391
if prop in self._breaks.values():
396
return self.customTypeMap.get(opts[2:].strip(), None)
398
return PropertyEditors.EnumConfPropEdit
400
if srcVal.lower() in ('true', 'false'):
401
return PropertyEditors.BoolConfPropEdit
404
val = eval(srcVal, vars(Preferences))
405
except Exception, error:
406
return PropertyEditors.StrConfPropEdit
408
if isinstance(val, wx.wxColour):
409
return PropertyEditors.ColourConfPropEdit
410
return self.typeMap.get(type(val), PropertyEditors.StrConfPropEdit)
412
def getPropertyHelp(self, propName):
413
for prop in self.propItems:
414
if prop[0] == propName: return prop[3]
418
def getPropertyItems(self):
419
order, vals, props, comments, options, self._breaks = self.prefNode.load()
421
# remove empty break lines (-----------------------)
422
for lineNo in self._breaks.keys():
423
if not self._breaks[lineNo]:
424
del self._breaks[lineNo]
426
breakLinenos = self._breaks.keys()
428
if len(breakLinenos):
434
for name, value, comment, option in map(None, order, vals, comments, options):
435
if breaksIdx is not None:
436
# find closest break above property
437
while breaksIdx < len(breakLinenos)-1 and \
438
props[name].start > breakLinenos[breaksIdx+1]:
441
if breaksIdx >= len(breakLinenos):
444
if breaksIdx is not None and props[name].start > breakLinenos[breaksIdx]:
445
res.append( (self._breaks[breakLinenos[breaksIdx]], '', None, '', '') )
447
#if breaksIdx == len(self._breaks) -1:
450
# breaksIdx = breaksIdx + 1
451
res.append( (name, value, props[name], comment, option) )
454
def setPropHook(self, name, value, oldProp):
457
eval(value, vars(Preferences))
458
except Exception, error:
459
wx.wxLogError('Error: '+str(error))
462
newProp = (name, value) + oldProp[2:]
463
self.prefNode.save(name, newProp)
466
def persistedPropVal(self, name, setterName):
467
if name in self._breaks.values():
468
return 'PROP_CATEGORY'
472
def getPropOptions(self, name):
473
for prop in self.propItems:
476
if strOpts and strOpts[:2] != '##':
477
return self.eval(strOpts)
483
def getPropNames(self, name):
484
for prop in self.propItems:
487
if strOpts and strOpts[:2] != '##':
488
return methodparse.safesplitfields(strOpts, ',')
493
def eval(self, expr):
494
import PaletteMapping
495
return PaletteMapping.evalCtrl(expr, vars(Preferences))
497
## def GetProp(self, name):
498
## ExplorerNodes.ExplorerCompanion.GetProp(self, name)
499
## return self.findProp(name)[0][1]
501
class CorePluginsGroupNode(PreferenceGroupNode):
503
protocol = 'prefs.group.plug-in.core'
504
defName = 'CorePluginPrefsGroup'
506
name = 'Core support'
507
PreferenceGroupNode.__init__(self, name, None)
510
self.preferences = []
512
def isFolderish(self):
516
return self.preferences
518
def notifyBeginLabelEdit(self, event):
521
def getPluginSection(pluginFile):
522
pluginPath = os.path.dirname(pluginFile)
523
return Preferences.pluginSections[
524
Preferences.pluginPaths.index(pluginPath)]
526
class PluginFileExplNode(ExplorerNodes.ExplorerNode):
528
def __init__(self, name, enabled, status, resourcepath, imgIdx):
529
ExplorerNodes.ExplorerNode.__init__(self, name, resourcepath, None,
531
self.pluginEnabled = enabled
532
self.pluginStatus = status
534
def open(self, editor):
536
if self.pluginEnabled:
541
if wx.wxMessageBox('%s %s?'%(msg, self.name), 'Confirm Toggle Plug-in',
542
wx.wxYES_NO | wx.wxICON_QUESTION) == wx.wxYES:
543
section = getPluginSection(self.resourcepath)
544
ordered, disabled = Plugins.readPluginsState(section)
546
if self.pluginEnabled:
547
disabled.append(self.name)
550
disabled.remove(self.name)
554
#Plugins.writeInitPluginGlobals(initPluginPath, initPluginGlobals)
555
Plugins.writePluginsState(section, ordered, disabled)
557
editor.explorer.list.refreshCurrent()
562
return '%s (%s)'%(ExplorerNodes.ExplorerNode.getURI(self),
565
def isFolderish(self):
568
def notifyBeginLabelEdit(self, event):
571
def changeOrder(self, direction):
572
section = getPluginSection(self.resourcepath)
573
#initPluginPath = os.path.dirname(self.resourcepath)
574
ordered, disabled = Plugins.readPluginsState(section)
575
#ordered = initPluginGlobals['__ordered__']
577
idx = ordered.index(self.name)
582
idx = max(idx + direction, 0)
583
if idx <= len(ordered):
584
ordered.insert(idx, self.name)
585
#Plugins.writeInitPluginGlobals(initPluginPath, initPluginGlobals)
586
Plugins.writePluginsState(section, ordered, disabled)
589
class PluginFilesGroupNode(PreferenceGroupNode):
590
""" Represents a group of preference collections """
591
protocol = 'prefs.group.plug-in.files'
592
defName = 'PluginFilesPrefsGroup'
594
name = 'Plug-in files'
595
PreferenceGroupNode.__init__(self, name, None)
599
splitext = os.path.splitext
600
for filename, ordered, enabled in Plugins.buildPluginExecList():
601
if os.path.basename(filename) == '__init__.plug-in.py':
604
name = splitext(splitext(os.path.basename(filename))[0])[0]
606
name = splitext(name)[0]
608
imgIdx = EditorHelper.imgSystemObjDisabled
610
fn = filename.lower()
611
if Preferences.failedPlugins.has_key(fn):
612
kind, msg = Preferences.failedPlugins[fn]
613
if kind == 'Skipped':
614
status = 'Skipped plug-in: %s'% msg
615
imgIdx = EditorHelper.imgSystemObjPending
617
status = 'Broken plug-in: %s'% msg
618
imgIdx = EditorHelper.imgSystemObjBroken
619
elif fn in Preferences.installedPlugins:
621
status = 'Installed, ordered'
622
imgIdx = EditorHelper.imgSystemObjOrdered
625
imgIdx = EditorHelper.imgSystemObj
627
status = 'Pending restart'
628
imgIdx = EditorHelper.imgSystemObjPending
630
res.append(PluginFileExplNode(name, enabled, status, filename, imgIdx))
634
class PluginFilesGroupNodeController(ExplorerNodes.Controller):
635
moveUpBmp = 'Images/Shared/up.png'
636
moveDownBmp = 'Images/Shared/down.png'
640
def __init__(self, editor, list, inspector, controllers):
641
ExplorerNodes.Controller.__init__(self, editor)
643
self.menu = wx.wxMenu()
645
[wxID_PF_TOGGLE, wxID_PF_OPEN, wxID_PF_UP, wxID_PF_DOWN] = Utils.wxNewIds(4)
647
self.transpMenuDef = [ (wxID_PF_TOGGLE, 'Toggle Enable/Disabled',
648
self.OnToggleState, '-'),
649
(wxID_PF_OPEN, 'Open plug-in file',
650
self.OnOpenPlugin, '-'),
652
(wxID_PF_UP, 'Move up',
653
self.OnMovePluginUp, self.moveUpBmp),
654
(wxID_PF_DOWN, 'Move down',
655
self.OnMovePluginDown, self.moveDownBmp),
658
self.setupMenu(self.menu, self.list, self.transpMenuDef)
659
self.toolbarMenus = [self.transpMenuDef]
662
self.transpMenuDef = []
663
self.toolbarMenus = []
666
def OnToggleState(self, event):
668
ms = self.list.getMultiSelection()
669
nodes = self.getNodesForSelection(ms)
671
node.open(self.editor)
673
def OnOpenPlugin(self, event):
675
ms = self.list.getMultiSelection()
676
nodes = self.getNodesForSelection(ms)
678
self.editor.openOrGotoModule(node.resourcepath)
680
def OnMovePluginUp(self, event):
682
ms = self.list.getMultiSelection()
683
nodes = self.getNodesForSelection(ms)
685
wx.wxLogError('Can only move 1 at a time')
688
idx = self.list.items.index(node)
690
wx.wxLogError('Already at the beginning')
694
self.list.refreshCurrent()
695
self.list.selectItemNamed(name)
697
def OnMovePluginDown(self, event):
699
ms = self.list.getMultiSelection()
700
nodes = self.getNodesForSelection(ms)
702
wx.wxLogError('Can only move 1 at a time')
705
idx = self.list.items.index(node)
706
## if idx >= len(self.list.items) -1:
707
## wx.wxLogError('Already at the end')
711
self.list.refreshCurrent()
712
self.list.selectItemNamed(name)
716
class TransportPluginExplNode(ExplorerNodes.ExplorerNode):
718
protocol = 'transport'
719
def __init__(self, name, status, imgIdx):
720
ExplorerNodes.ExplorerNode.__init__(self, name, '%s (%s)'%(name, status),
721
None, imgIdx, None, {})
725
def open(self, editor):
728
class TransportPluginsController(ExplorerNodes.Controller):
729
addItemBmp = 'Images/Shared/NewItem.png'
730
removeItemBmp = 'Images/Shared/DeleteItem.png'
731
moveUpBmp = 'Images/Shared/up.png'
732
moveDownBmp = 'Images/Shared/down.png'
736
def __init__(self, editor, list, inspector, controllers):
737
ExplorerNodes.Controller.__init__(self, editor)
739
self.menu = wx.wxMenu()
741
[wxID_TP_NEW, wxID_TP_DEL, wxID_TP_UP, wxID_TP_DOWN] = Utils.wxNewIds(4)
743
self.transpMenuDef = [ (wxID_TP_NEW, 'Add new '+self.itemDescr,
744
self.OnNewTransport, self.addItemBmp),
745
(wxID_TP_DEL, 'Remove '+self.itemDescr,
746
self.OnDeleteTransport, self.removeItemBmp),
748
(wxID_TP_UP, 'Move up',
749
self.OnMoveTransportUp, self.moveUpBmp),
750
(wxID_TP_DOWN, 'Move down',
751
self.OnMoveTransportDown, self.moveDownBmp),
754
self.setupMenu(self.menu, self.list, self.transpMenuDef)
755
self.toolbarMenus = [self.transpMenuDef]
758
self.transpMenuDef = []
759
self.toolbarMenus = []
762
def editorUpdateNotify(self, info=''):
765
def OnReloadItems(self, event=None):
767
self.list.refreshCurrent()
769
def moveTransport(self, node, idx, direc):
771
for item in self.list.items:
772
names.append(item.name)
776
names.insert(idx + direc, name)
778
self.list.node.updateOrder(names)
780
self.list.refreshCurrent()
781
self.list.selectItemByIdx(idx+direc+1)
783
def OnMoveTransportUp(self, event):
785
ms = self.list.getMultiSelection()
786
nodes = self.getNodesForSelection(ms)
788
wx.wxLogError('Can only move 1 at a time')
791
idx = self.list.items.index(node)
793
wx.wxLogError('Already at the beginning')
795
self.moveTransport(node, idx, -1)
797
def OnMoveTransportDown(self, event):
799
ms = self.list.getMultiSelection()
800
nodes = self.getNodesForSelection(ms)
802
wx.wxLogError('Can only move 1 at a time')
805
idx = self.list.items.index(node)
806
if idx >= len(self.list.items) -1:
807
wx.wxLogError('Already at the end')
809
self.moveTransport(node, idx, 1)
811
def OnNewTransport(self, event):
814
def OnDeleteTransport(self, event):
817
class TransportPluginsLoadOrderController(TransportPluginsController):
818
itemDescr = 'Transport module'
820
def OnNewTransport(self, event):
821
dlg = wx.wxTextEntryDialog(self.list, 'Enter the fully qualified Python '\
822
'object path to \nthe Transport module. E.g. Explorers.FileExplorer',
825
if dlg.ShowModal() != wx.wxID_OK:
827
transportModulePath = dlg.GetValue()
831
if not self.list.node.checkValidModulePath(transportModulePath):
832
if wx.wxMessageBox('Cannot locate the specified module path,\n'\
833
'are you sure you want to continue?',
835
wx.wxYES_NO | wx.wxICON_EXCLAMATION) == wx.wxNO:
839
for item in self.list.items:
840
names.append(item.name)
842
names.append(transportModulePath)
844
self.list.node.updateOrder(names)
846
self.list.refreshCurrent()
848
def OnDeleteTransport(self, event):
849
selNames = self.list.getMultiSelection()
850
nodes = self.getNodesForSelection(selNames)
853
for item in self.list.items:
854
names.append(item.name)
857
names.remove(item.name)
859
self.list.node.updateOrder(names)
861
self.list.refreshCurrent()
863
class TransportPluginsTreeDisplayOrderController(TransportPluginsController):
864
itemDescr = 'Transports tree node'
866
def OnNewTransport(self, event):
867
dlg = wx.wxTextEntryDialog(self.list, 'Enter the protocol identifier. E.g. '\
868
'ftp, ssh', 'New Transports Tree Node', '')
870
if dlg.ShowModal() != wx.wxID_OK:
872
protocol = dlg.GetValue()
877
for item in self.list.items:
878
names.append(item.name)
880
names.append(protocol)
882
self.list.node.updateOrder(names)
883
self.list.node.checkConfigEntry(protocol)
885
self.list.refreshCurrent()
887
def OnDeleteTransport(self, event):
888
selNames = self.list.getMultiSelection()
889
nodes = self.getNodesForSelection(selNames)
892
for item in self.list.items:
893
names.append(item.name)
896
names.remove(item.name)
897
self.list.node.clearEmptyConfigEntry(item.name)
899
self.list.node.updateOrder(names)
901
self.list.refreshCurrent()
904
class TransportPluginsLoadOrderGroupNode(PreferenceGroupNode):
906
protocol = 'prefs.group.plug-in.transport.load-order'
907
defName = 'TransportPluginsPrefsGroup'
909
name = 'Loading order'
910
PreferenceGroupNode.__init__(self, name, None)
913
conf = Utils.createAndReadConfig('Explorer')
915
modules = eval(conf.get('explorer', 'installedtransports'), {})
916
assert isinstance(modules, types.ListType)
920
if mod in ExplorerNodes.installedModules:
922
imgIdx = EditorHelper.imgSystemObjOrdered
923
elif mod in ExplorerNodes.failedModules.keys():
924
status = 'Broken: %s'%ExplorerNodes.failedModules[mod]
925
imgIdx = EditorHelper.imgSystemObjBroken
927
status = 'Pending restart'
928
imgIdx = EditorHelper.imgSystemObjPending
930
res.append(TransportPluginExplNode(mod, status, imgIdx))
933
def updateOrder(self, newOrder):
934
conf = Utils.createAndReadConfig('Explorer')
935
conf.set('explorer', 'installedtransports', pprint.pformat(newOrder))
936
Utils.writeConfig(conf)
938
def checkValidModulePath(self, name):
940
Utils.find_dotted_module(name)
941
except ImportError, err:
948
class TransportPluginsTreeDisplayOrderGroupNode(PreferenceGroupNode):
950
protocol = 'prefs.group.plug-in.transport.tree-order'
951
defName = 'TransportPluginsPrefsGroup'
953
name = 'Tree display order'
954
PreferenceGroupNode.__init__(self, name, None)
957
conf = Utils.createAndReadConfig('Explorer')
959
treeOrder = eval(conf.get('explorer', 'transportstree'), {})
960
assert isinstance(treeOrder, type([]))
963
for prot in treeOrder:
964
if not ExplorerNodes.nodeRegByProt.has_key(prot):
965
status = 'Protocol not installed'
966
imgIdx = EditorHelper.imgSystemObjPending
969
imgIdx = EditorHelper.imgSystemObjOrdered
971
res.append(TransportPluginExplNode(prot, status, imgIdx))
974
def updateOrder(self, newOrder):
975
conf = Utils.createAndReadConfig('Explorer')
976
conf.set('explorer', 'transportstree', pprint.pformat(newOrder))
977
Utils.writeConfig(conf)
979
def checkConfigEntry(self, protocol):
980
conf = Utils.createAndReadConfig('Explorer')
981
if not conf.has_option('explorer', protocol):
982
conf.set('explorer', protocol, '{}')
983
Utils.writeConfig(conf)
985
def clearEmptyConfigEntry(self, protocol):
986
conf = Utils.createAndReadConfig('Explorer')
987
if conf.has_option('explorer', protocol) and \
988
eval(conf.get('explorer', protocol).strip(), {}) == {}:
989
conf.remove_option('explorer', protocol)
990
Utils.writeConfig(conf)
993
class HelpConfigPGN(PreferenceGroupNode):
995
protocol = 'prefs.group.help.config'
996
defName = 'HelpConfigPrefsGroup'
999
PreferenceGroupNode.__init__(self, name, None)
1005
class HelpConfigBooksPGN(PreferenceGroupNode):
1007
protocol = 'prefs.group.help.config.books'
1008
defName = 'HelpConfigBooksPrefsGroup'
1011
PreferenceGroupNode.__init__(self, name, None)
1014
bookPaths = self.readBooks()
1015
return [HelpConfigBookNode(bookPath)
1016
for bookPath in bookPaths]
1019
def readBooks(self):
1020
return eval(Utils.createAndReadConfig('Explorer').get('help', 'books'), {})
1022
def writeBooks(self, books):
1023
conf = Utils.createAndReadConfig('Explorer')
1024
conf.set('help', 'books', pprint.pformat(books))
1025
Utils.writeConfig(conf)
1028
def preparePath(self, path):
1029
helpPath = Preferences.pyPath+'/Docs/'
1031
if path.startswith('file://'):
1034
# Add relative paths for files inside Docs directory
1035
if os.path.normcase(path).startswith(os.path.normcase(helpPath)):
1036
return path[len(helpPath):]
1040
def editBook(self, curPath, newPath):
1041
books = self.readBooks()
1042
books[books.index(curPath)] = self.preparePath(newPath)
1043
self.writeBooks(books)
1045
def addBook(self, path):
1046
path = self.preparePath(path)
1047
self.writeBooks(self.readBooks() + [path])
1049
def removeBook(self, path):
1050
books = self.readBooks()
1052
self.writeBooks(books)
1054
def updateOrder(self, paths):
1055
self.writeBooks(paths)
1058
class HelpConfigBookNode(ExplorerNodes.ExplorerNode):
1060
protocol = 'help.book'
1061
def __init__(self, resourcepath):
1062
fullpath = self.getAbsPath(resourcepath)
1064
name = os.path.basename(resourcepath)
1065
if os.path.splitext(fullpath)[1] == '.hhp':
1066
# Peek at title inside hhp file
1067
for line in open(fullpath).readlines():
1068
if line.startswith('Title'):
1069
name = line.split('=')[1].strip()
1071
ExplorerNodes.ExplorerNode.__init__(self, name, resourcepath, None,
1072
EditorHelper.imgHelpBook, None, {})
1074
def open(self, editor):
1077
## def getURI(self):
1078
## return '%s (%s)'%(ExplorerNodes.ExplorerNode.getURI(self),
1079
## self.pluginStatus)
1081
def isFolderish(self):
1084
def notifyBeginLabelEdit(self, event):
1087
def getAbsPath(self, resourcepath):
1088
if not os.path.isabs(resourcepath):
1089
return os.path.join(Preferences.pyPath, 'Docs', resourcepath)
1095
class HelpConfigBooksController(ExplorerNodes.Controller):
1096
addItemBmp = 'Images/Shared/NewItem.png'
1097
removeItemBmp = 'Images/Shared/DeleteItem.png'
1098
moveUpBmp = 'Images/Shared/up.png'
1099
moveDownBmp = 'Images/Shared/down.png'
1103
def __init__(self, editor, list, inspector, controllers):
1104
ExplorerNodes.Controller.__init__(self, editor)
1106
self.menu = wx.wxMenu()
1108
[wxID_HB_EDIT, wxID_HB_NEW, wxID_HB_DEL, wxID_HB_UP, wxID_HB_DOWN,
1109
wxID_HB_REST, wxID_HB_CLRI, wxID_HB_OPEN] = Utils.wxNewIds(8)
1111
self.helpBooksMenuDef = [ (wxID_HB_EDIT, 'Edit '+self.itemDescr,
1112
self.OnEditBookPath, '-'),
1113
(wxID_HB_NEW, 'Add new '+self.itemDescr,
1114
self.OnNewBook, self.addItemBmp),
1115
(wxID_HB_DEL, 'Remove '+self.itemDescr,
1116
self.OnRemoveBook, self.removeItemBmp),
1117
(-1, '-', None, ''),
1118
(wxID_HB_UP, 'Move up',
1119
self.OnMoveBookUp, self.moveUpBmp),
1120
(wxID_HB_DOWN, 'Move down',
1121
self.OnMoveBookDown, self.moveDownBmp),
1122
(-1, '-', None, '-'),
1123
(wxID_HB_OPEN, 'Open hhp file',
1124
self.OnOpenHHP, '-'),
1125
(-1, '-', None, '-'),
1126
(wxID_HB_REST, 'Restart the help system',
1127
self.OnRestartHelp, '-'),
1128
(wxID_HB_CLRI, 'Clear the help indexes',
1129
self.OnClearHelpIndexes, '-'),
1132
self.setupMenu(self.menu, self.list, self.helpBooksMenuDef)
1133
self.toolbarMenus = [self.helpBooksMenuDef]
1136
self.helpBooksMenuDef = ()
1137
self.toolbarMenus = ()
1140
def editorUpdateNotify(self, info=''):
1141
self.OnReloadItems()
1143
def OnReloadItems(self, event=None):
1145
self.list.refreshCurrent()
1147
def moveBook(self, node, idx, direc):
1148
paths = [item.resourcepath for item in self.list.items]
1152
paths.insert(idx + direc, path)
1154
self.list.node.updateOrder(paths)
1156
self.list.refreshCurrent()
1157
self.list.selectItemByIdx(idx+direc+1)
1159
def OnMoveBookUp(self, event):
1161
ms = self.list.getMultiSelection()
1162
nodes = self.getNodesForSelection(ms)
1164
wx.wxLogError('Can only move 1 at a time')
1167
idx = self.list.items.index(node)
1169
wx.wxLogError('Already at the beginning')
1171
self.moveBook(node, idx, -1)
1173
def OnMoveBookDown(self, event):
1175
ms = self.list.getMultiSelection()
1176
nodes = self.getNodesForSelection(ms)
1178
wx.wxLogError('Can only move 1 at a time')
1181
idx = self.list.items.index(node)
1182
if idx >= len(self.list.items) -1:
1183
wx.wxLogError('Already at the end')
1185
self.moveBook(node, idx, 1)
1187
def OnEditBookPath(self, event):
1189
ms = self.list.getMultiSelection()
1190
for node in self.getNodesForSelection(ms):
1191
if not os.path.isabs(node.resourcepath):
1192
path = os.path.join(Preferences.pyPath,
1193
'Docs', node.resourcepath)
1195
path = node.resourcepath
1197
curpath, curfile = os.path.split(path)
1198
newpath = self.editor.openFileDlg('AllFiles', curdir=curpath)
1200
self.list.node.editBook(node.resourcepath, path)
1201
self.list.refreshCurrent()
1203
def OnNewBook(self, event):
1204
path = self.editor.openFileDlg('AllFiles', curdir=Preferences.pyPath+'/Docs')
1205
if path and self.list.node:
1206
self.list.node.addBook(path)
1207
self.list.refreshCurrent()
1209
def OnRemoveBook(self, event):
1211
ms = self.list.getMultiSelection()
1212
for node in self.getNodesForSelection(ms):
1213
self.list.node.removeBook(node.resourcepath)
1214
self.list.refreshCurrent()
1216
def OnRestartHelp(self, event):
1222
def OnClearHelpIndexes(self, event):
1225
cd = Help.getCacheDir()
1226
for name in os.listdir(cd):
1227
if os.path.splitext(name)[1] == '.cached':
1228
os.remove(os.path.join(cd, name))
1229
wx.wxLogMessage('Deleted %s'%name)
1231
def OnOpenHHP(self, event):
1233
ms = self.list.getMultiSelection()
1234
for node in self.getNodesForSelection(ms):
1235
self.editor.openOrGotoModule(node.getAbsPath(node.resourcepath))
1237
#-------------------------------------------------------------------------------
1240
ExplorerNodes.register(BoaPrefGroupNode)
1241
ExplorerNodes.register(PluginFilesGroupNode,
1242
controller=PluginFilesGroupNodeController)
1243
ExplorerNodes.register(TransportPluginsLoadOrderGroupNode,
1244
controller=TransportPluginsLoadOrderController)
1245
ExplorerNodes.register(TransportPluginsTreeDisplayOrderGroupNode,
1246
controller=TransportPluginsTreeDisplayOrderController)
1247
ExplorerNodes.register(HelpConfigBooksPGN, controller=HelpConfigBooksController)
1
#-----------------------------------------------------------------------------
2
# Name: PrefsExplorer.py
5
# Author: Riaan Booysen
8
# RCS-ID: $Id: PrefsExplorer.py,v 1.18 2005/05/18 12:59:39 riaan Exp $
9
# Copyright: (c) 2001 - 2005
11
#-----------------------------------------------------------------------------
12
print 'importing Explorers.PrefsExplorer'
13
import os, sys, glob, pprint, imp
18
import Preferences, Utils, Plugins
21
from Models import EditorHelper
22
from Views import STCStyleEditor
23
import methodparse, relpath
25
class PreferenceGroupNode(ExplorerNodes.ExplorerNode):
26
""" Represents a group of preference collections """
27
protocol = 'prefs.group'
28
defName = 'PrefsGroup'
29
def __init__(self, name, parent):
30
ExplorerNodes.ExplorerNode.__init__(self, name, name, None,
31
EditorHelper.imgPrefsFolder, None)
36
def isFolderish(self):
40
return self.preferences
42
def notifyBeginLabelEdit(self, event):
45
class BoaPrefGroupNode(PreferenceGroupNode):
46
""" The Preference node in the Explorer """
47
protocol = 'boa.prefs.group'
48
customPrefs = [] # list of tuples ('name', 'file')
49
def __init__(self, parent):
50
PreferenceGroupNode.__init__(self, 'Preferences', parent)
53
prefImgIdx = EditorHelper.imgSystemObj
54
stcPrefImgIdx = EditorHelper.imgPrefsSTCStyles
56
self.source_pref = PreferenceGroupNode('Source', self)
58
self.source_pref.preferences = [
59
UsedModuleSrcBsdPrefColNode('Default settings',
60
Preferences.exportedSTCProps, os.path.join(Preferences.rcPath,
61
'prefs.rc.py'), prefImgIdx, self, Preferences, True)]
63
for name, lang, STCClass, stylesFile in ExplorerNodes.langStyleInfoReg:
64
if not os.path.isabs(stylesFile):
65
stylesFile = os.path.join(Preferences.rcPath, stylesFile)
66
self.source_pref.preferences.append(STCStyleEditPrefsCollNode(
67
name, lang, STCClass, stylesFile, stcPrefImgIdx, self))
68
self.preferences.append(self.source_pref)
70
self.general_pref = UsedModuleSrcBsdPrefColNode('General',
71
Preferences.exportedProperties, os.path.join(Preferences.rcPath,
72
'prefs.rc.py'), prefImgIdx, self, Preferences)
73
self.preferences.append(self.general_pref)
75
self.platform_pref = UsedModuleSrcBsdPrefColNode('Platform specific',
76
Preferences.exportedProperties2, os.path.join(Preferences.rcPath,
77
'prefs.%s.rc.py' % (wx.Platform == '__WXMSW__' and 'msw' or 'gtk')),
78
prefImgIdx, self, Preferences)
79
self.preferences.append(self.platform_pref)
81
self.keys_pref = KeyDefsSrcPrefColNode('Key bindings', ('*',),
82
os.path.join(Preferences.rcPath, 'prefs.keys.rc.py'), prefImgIdx,
83
self, Preferences.keyDefs)
84
self.preferences.append(self.keys_pref)
86
for name, filename in self.customPrefs:
87
if not os.path.isabs(filename):
88
filename = os.path.join(Preferences.rcPath, filename)
89
self.preferences.append(UsedModuleSrcBsdPrefColNode(name,
90
('*',), filename, prefImgIdx, self, Preferences))
92
## self.pychecker_pref = SourceBasedPrefColNode('PyChecker',
93
## ('*',), Preferences.pyPath+'/.pycheckrc', prefImgIdx, self)
94
## self.preferences.append(self.pychecker_pref)
96
self.plugin_pref = PreferenceGroupNode('Plug-ins', self)
98
self.core_plugpref = UsedModuleSrcBsdPrefColNode('Core support',
99
Preferences.exportedCorePluginProps, os.path.join(Preferences.rcPath,
100
'prefs.rc.py'), prefImgIdx, self, Preferences, True)
101
self.plugin_plugpref = UsedModuleSrcBsdPrefColNode('Preferences', Preferences.exportedPluginProps,#('*',),
102
os.path.join(Preferences.rcPath, 'prefs.plug-ins.rc.py'), prefImgIdx,
103
self, Preferences, True)
104
self.files_plugpref = PluginFilesGroupNode()
105
self.transp_plugpref = PreferenceGroupNode('Transports', self)
106
self.transp_plugpref.preferences = [
107
TransportPluginsLoadOrderGroupNode(),
108
TransportPluginsTreeDisplayOrderGroupNode(),
111
self.plugin_pref.preferences = [
113
self.transp_plugpref,
115
self.plugin_plugpref,
118
self.preferences.insert(1, self.plugin_pref)
120
self.help_pref = HelpConfigBooksPGN()
122
self.preferences.insert(2, self.help_pref)
125
class PreferenceCollectionNode(ExplorerNodes.ExplorerNode):
126
""" Represents an inspectable preference collection """
128
def __init__(self, name, props, resourcepath, imgIdx, parent):
129
ExplorerNodes.ExplorerNode.__init__(self, name, resourcepath, None,
132
def open(self, editor):
133
""" Populate inspector with preference items """
134
comp = PreferenceCompanion(self.name, self)
137
# Select in inspector
138
editor.inspector.restore()
139
if editor.inspector.pages.GetSelection() != 1:
140
editor.inspector.pages.SetSelection(1)
141
editor.inspector.selectObject(comp, False)
144
def isFolderish(self):
148
raise 'Not implemented'
150
def save(self, filename, data):
153
def notifyBeginLabelEdit(self, event):
156
class STCStyleEditPrefsCollNode(PreferenceCollectionNode):
157
protocol = 'stc.prefs'
158
def __init__(self, name, lang, STCclass, resourcepath, imgIdx, parent):
159
PreferenceCollectionNode.__init__(self, name, {}, resourcepath, imgIdx, parent)
161
self.STCclass = STCclass
163
def open(self, editor):
164
# build list of all open STC's in the Editor
166
for modPge in editor.modules.values():
167
for view in modPge.model.views.values():
168
if isinstance(view, self.STCclass):
169
openSTCViews.append(view)
171
# also check the shell
172
if Preferences.psPythonShell == 'Shell':
173
if isinstance(editor.shell, self.STCclass):
174
openSTCViews.append(editor.shell)
175
#elif Preferences.psPythonShell == 'PyCrust':
176
# if self.language == 'python':
177
# openSTCViews.append(editor.shell.shellWin)
179
dlg = STCStyleEditor.STCStyleEditDlg(editor, self.name, self.language,
180
self.resourcepath, openSTCViews)
182
finally: dlg.Destroy()
187
return '%s://%s' %(PreferenceCollectionNode.getURI(self), self.language)
190
class SourceBasedPrefColNode(PreferenceCollectionNode):
191
""" Preference collection represented by the global names in python module
193
Only names which are also defined in properties are returned
194
except when properties is a special match all tuple; ('*',)
196
This only applies to names assigned to values ( x = 123 ) not to global
197
names defined by classes functions and imports.
199
def __init__(self, name, props, resourcepath, imgIdx, parent, showBreaks=True):
200
PreferenceCollectionNode.__init__(self, name, props, resourcepath,
202
self.showBreakLines = showBreaks
205
# All preferences are local
208
module = moduleparse.Module(self.name,
209
open(self.resourcepath).readlines())
214
# keep only names defined in the property list
215
for name in module.global_order[:]:
216
if name[0] == '_' or self.properties != ('*',) and \
217
name not in self.properties:
218
module.global_order.remove(name)
219
del module.globals[name]
221
# XXX Should handle multiline assign
222
code = '\n'.join(module.source[\
223
module.globals[name].start-1 : \
224
module.globals[name].end])
229
values.append(code[s+1:].strip())
233
# Read possible comment/help or options
236
idx = module.globals[name].start-2
238
line = module.source[idx].strip()
239
if len(line) > 11 and line[:11] == '## options:':
240
option = line[11:].strip()
242
elif len(line) > 8 and line[:8] == '## type:':
243
option = '##'+line[8:].strip()
245
elif line and line[0] == '#':
246
comment.append(line[1:].lstrip())
251
comments.append('\n'.join(comment))
252
options.append(option)
254
if self.showBreakLines: breaks = module.break_lines
257
return (module.global_order, values, module.globals, comments, options,
260
def save(self, filename, data):
261
""" Updates one property """
262
src = open(self.resourcepath).readlines()
263
src[data[2].start-1] = '%s = %s\n' % (data[0], data[1])
264
open(self.resourcepath, 'w').writelines(src)
266
class UsedModuleSrcBsdPrefColNode(SourceBasedPrefColNode):
267
""" Also update the value of a global attribute of an imported module """
268
def __init__(self, name, props, resourcepath, imgIdx, parent, module,
270
SourceBasedPrefColNode.__init__(self, name, props, resourcepath, imgIdx,
274
def save(self, filename, data):
275
SourceBasedPrefColNode.save(self, filename, data)
276
if hasattr(self.module, data[0]):
277
setattr(self.module, data[0], eval(data[1], vars(Preferences)))
279
class KeyDefsSrcPrefColNode(PreferenceCollectionNode):
280
""" Preference collection representing the key bindings """
281
def __init__(self, name, props, resourcepath, imgIdx, parent, keyDefs):
282
PreferenceCollectionNode.__init__(self, name, props, resourcepath,
284
self.showBreakLines = True
287
def open(self, editor):
288
PreferenceCollectionNode.open(self, editor)
289
self._editor = editor
294
src = open(self.resourcepath).readlines()
295
module = moduleparse.Module(self.name, src)
301
start = end = idx = -1
305
if line == 'keyDefs = {':
307
elif start != -1 and line:
312
colon = line.find(':')
313
if colon == -1: raise Exception('Invalid KeyDef item: %s'%line)
314
name = line[:colon].rstrip()[1:-1]
315
val = line[colon+1:].lstrip()
316
keydefs[name] = moduleparse.CodeBlock(val, idx+1, idx+1)
320
return (names, values, keydefs, ['']*len(keydefs),
321
['## keydef']*len(keydefs), module.break_lines)
323
def save(self, filename, data):
324
""" Updates one key:val in keydefs dict """
327
src = open(self.resourcepath).readlines()
328
src[data[2].start-1] = \
329
" '%s'%s: %s\n" % (data[0], (12 - len(data[0]))*' ', data[1])
330
open(self.resourcepath, 'w').writelines(src)
332
Preferences.keyDefs[data[0]] = eval(data[1], vars(Preferences))[0]
333
# Update editor menus
334
self._editor.setupToolBar()
335
self._editor.updateStaticMenuShortcuts()
336
self._editor.shell.bindShortcuts()
339
class ConfigBasedPrefsColNode(PreferenceCollectionNode):
340
""" Preferences driven by config files """
344
#---Companions------------------------------------------------------------------
346
from PropEdit import PropertyEditors, InspectorEditorControls
348
class KeyDefConfPropEdit(PropertyEditors.ConfPropEdit):
349
def inspectorEdit(self):
350
self.editorCtrl = InspectorEditorControls.ButtonIEC(self, self.value)
351
self.editorCtrl.createControl(self.parent, self.idx, self.width, self.edit)
353
def edit(self, event):
355
dlg = KeyDefsDlg.KeyDefsDialog(self.parent, self.name, self.value)
357
if dlg.ShowModal() == wx.ID_OK:
358
self.editorCtrl.value = dlg.result
359
self.inspectorPost(False)
363
def getDisplayValue(self):
365
return eval(self.value, {'wx': wx})[0][2]
366
except Exception, err:
369
class PreferenceCompanion(ExplorerNodes.ExplorerCompanion):
370
def __init__(self, name, prefNode, ):
371
ExplorerNodes.ExplorerCompanion.__init__(self, name)
372
self.prefNode = prefNode
377
customTypeMap = {'filepath': PropertyEditors.FilepathConfPropEdit,
378
'dirpath': PropertyEditors.DirpathConfPropEdit,
379
'keydef': KeyDefConfPropEdit}
380
def getPropEditor(self, prop):
381
# XXX Using name equality to identify _breaks' prop edit is ugly !
382
for aProp in self.propItems:
383
if aProp[0] == prop: break
385
raise Exception('Property "%s" not found'%prop)
390
if prop in self._breaks.values():
395
return self.customTypeMap.get(opts[2:].strip(), None)
397
return PropertyEditors.EnumConfPropEdit
399
if srcVal.lower() in ('true', 'false'):
400
return PropertyEditors.BoolConfPropEdit
403
val = eval(srcVal, vars(Preferences))
404
except Exception, error:
405
return PropertyEditors.StrConfPropEdit
407
if isinstance(val, wx.Colour):
408
return PropertyEditors.ColourConfPropEdit
409
return self.typeMap.get(type(val), PropertyEditors.StrConfPropEdit)
411
def getPropertyHelp(self, propName):
412
for prop in self.propItems:
413
if prop[0] == propName: return prop[3]
417
def getPropertyItems(self):
418
order, vals, props, comments, options, self._breaks = self.prefNode.load()
420
# remove empty break lines (-----------------------)
421
for lineNo in self._breaks.keys():
422
if not self._breaks[lineNo]:
423
del self._breaks[lineNo]
425
breakLinenos = self._breaks.keys()
427
if len(breakLinenos):
433
for name, value, comment, option in map(None, order, vals, comments, options):
434
if breaksIdx is not None:
435
# find closest break above property
436
while breaksIdx < len(breakLinenos)-1 and \
437
props[name].start > breakLinenos[breaksIdx+1]:
440
if breaksIdx >= len(breakLinenos):
443
if breaksIdx is not None and props[name].start > breakLinenos[breaksIdx]:
444
res.append( (self._breaks[breakLinenos[breaksIdx]], '', None, '', '') )
446
#if breaksIdx == len(self._breaks) -1:
449
# breaksIdx = breaksIdx + 1
450
res.append( (name, value, props[name], comment, option) )
453
def setPropHook(self, name, value, oldProp):
456
eval(value, vars(Preferences))
457
except Exception, error:
458
wx.LogError('Error: '+str(error))
461
newProp = (name, value) + oldProp[2:]
462
self.prefNode.save(name, newProp)
465
def persistedPropVal(self, name, setterName):
466
if name in self._breaks.values():
467
return 'PROP_CATEGORY'
471
def getPropOptions(self, name):
472
for prop in self.propItems:
475
if strOpts and strOpts[:2] != '##':
476
return self.eval(strOpts)
482
def getPropNames(self, name):
483
for prop in self.propItems:
486
if strOpts and strOpts[:2] != '##':
487
return methodparse.safesplitfields(strOpts, ',')
492
def eval(self, expr):
493
import PaletteMapping
494
return PaletteMapping.evalCtrl(expr, vars(Preferences))
496
## def GetProp(self, name):
497
## ExplorerNodes.ExplorerCompanion.GetProp(self, name)
498
## return self.findProp(name)[0][1]
500
class CorePluginsGroupNode(PreferenceGroupNode):
502
protocol = 'prefs.group.plug-in.core'
503
defName = 'CorePluginPrefsGroup'
505
name = 'Core support'
506
PreferenceGroupNode.__init__(self, name, None)
509
self.preferences = []
511
def isFolderish(self):
515
return self.preferences
517
def notifyBeginLabelEdit(self, event):
520
def getPluginSection(pluginFile):
521
pluginPath = os.path.dirname(pluginFile)
522
return Preferences.pluginSections[
523
Preferences.pluginPaths.index(pluginPath)]
525
class PluginFileExplNode(ExplorerNodes.ExplorerNode):
527
def __init__(self, name, enabled, status, resourcepath, imgIdx):
528
ExplorerNodes.ExplorerNode.__init__(self, name, resourcepath, None,
530
self.pluginEnabled = enabled
531
self.pluginStatus = status
533
def open(self, editor):
535
if self.pluginEnabled:
540
if wx.MessageBox('%s %s?'%(msg, self.name), 'Confirm Toggle Plug-in',
541
wx.YES_NO | wx.ICON_QUESTION) == wx.YES:
542
section = getPluginSection(self.resourcepath)
543
ordered, disabled = Plugins.readPluginsState(section)
545
if self.pluginEnabled:
546
disabled.append(self.name)
549
disabled.remove(self.name)
553
#Plugins.writeInitPluginGlobals(initPluginPath, initPluginGlobals)
554
Plugins.writePluginsState(section, ordered, disabled)
556
editor.explorer.list.refreshCurrent()
561
return '%s (%s)'%(ExplorerNodes.ExplorerNode.getURI(self),
564
def isFolderish(self):
567
def notifyBeginLabelEdit(self, event):
570
def changeOrder(self, direction):
571
section = getPluginSection(self.resourcepath)
572
#initPluginPath = os.path.dirname(self.resourcepath)
573
ordered, disabled = Plugins.readPluginsState(section)
574
#ordered = initPluginGlobals['__ordered__']
576
idx = ordered.index(self.name)
581
idx = max(idx + direction, 0)
582
if idx <= len(ordered):
583
ordered.insert(idx, self.name)
584
#Plugins.writeInitPluginGlobals(initPluginPath, initPluginGlobals)
585
Plugins.writePluginsState(section, ordered, disabled)
588
class PluginFilesGroupNode(PreferenceGroupNode):
589
""" Represents a group of preference collections """
590
protocol = 'prefs.group.plug-in.files'
591
defName = 'PluginFilesPrefsGroup'
593
name = 'Plug-in files'
594
PreferenceGroupNode.__init__(self, name, None)
598
splitext = os.path.splitext
599
for filename, ordered, enabled in Plugins.buildPluginExecList():
600
if os.path.basename(filename) == '__init__.plug-in.py':
603
name = splitext(splitext(os.path.basename(filename))[0])[0]
605
name = splitext(name)[0]
607
imgIdx = EditorHelper.imgSystemObjDisabled
609
fn = filename.lower()
610
if Preferences.failedPlugins.has_key(fn):
611
kind, msg = Preferences.failedPlugins[fn]
612
if kind == 'Skipped':
613
status = 'Skipped plug-in: %s'% msg
614
imgIdx = EditorHelper.imgSystemObjPending
616
status = 'Broken plug-in: %s'% msg
617
imgIdx = EditorHelper.imgSystemObjBroken
618
elif fn in Preferences.installedPlugins:
620
status = 'Installed, ordered'
621
imgIdx = EditorHelper.imgSystemObjOrdered
624
imgIdx = EditorHelper.imgSystemObj
626
status = 'Pending restart'
627
imgIdx = EditorHelper.imgSystemObjPending
629
res.append(PluginFileExplNode(name, enabled, status, filename, imgIdx))
633
class PluginFilesGroupNodeController(ExplorerNodes.Controller):
634
moveUpBmp = 'Images/Shared/up.png'
635
moveDownBmp = 'Images/Shared/down.png'
639
def __init__(self, editor, list, inspector, controllers):
640
ExplorerNodes.Controller.__init__(self, editor)
642
self.menu = wx.Menu()
644
[wxID_PF_TOGGLE, wxID_PF_OPEN, wxID_PF_UP, wxID_PF_DOWN] = Utils.wxNewIds(4)
646
self.transpMenuDef = [ (wxID_PF_TOGGLE, 'Toggle Enable/Disabled',
647
self.OnToggleState, '-'),
648
(wxID_PF_OPEN, 'Open plug-in file',
649
self.OnOpenPlugin, '-'),
651
(wxID_PF_UP, 'Move up',
652
self.OnMovePluginUp, self.moveUpBmp),
653
(wxID_PF_DOWN, 'Move down',
654
self.OnMovePluginDown, self.moveDownBmp),
657
self.setupMenu(self.menu, self.list, self.transpMenuDef)
658
self.toolbarMenus = [self.transpMenuDef]
661
self.transpMenuDef = []
662
self.toolbarMenus = []
665
def OnToggleState(self, event):
667
ms = self.list.getMultiSelection()
668
nodes = self.getNodesForSelection(ms)
670
node.open(self.editor)
672
def OnOpenPlugin(self, event):
674
ms = self.list.getMultiSelection()
675
nodes = self.getNodesForSelection(ms)
677
self.editor.openOrGotoModule(node.resourcepath)
679
def OnMovePluginUp(self, event):
681
ms = self.list.getMultiSelection()
682
nodes = self.getNodesForSelection(ms)
684
wx.LogError('Can only move 1 at a time')
687
idx = self.list.items.index(node)
689
wx.LogError('Already at the beginning')
693
self.list.refreshCurrent()
694
self.list.selectItemNamed(name)
696
def OnMovePluginDown(self, event):
698
ms = self.list.getMultiSelection()
699
nodes = self.getNodesForSelection(ms)
701
wx.LogError('Can only move 1 at a time')
704
idx = self.list.items.index(node)
705
## if idx >= len(self.list.items) -1:
706
## wx.LogError('Already at the end')
710
self.list.refreshCurrent()
711
self.list.selectItemNamed(name)
715
class TransportPluginExplNode(ExplorerNodes.ExplorerNode):
717
protocol = 'transport'
718
def __init__(self, name, status, imgIdx):
719
ExplorerNodes.ExplorerNode.__init__(self, name, '%s (%s)'%(name, status),
720
None, imgIdx, None, {})
724
def open(self, editor):
727
class TransportPluginsController(ExplorerNodes.Controller):
728
addItemBmp = 'Images/Shared/NewItem.png'
729
removeItemBmp = 'Images/Shared/DeleteItem.png'
730
moveUpBmp = 'Images/Shared/up.png'
731
moveDownBmp = 'Images/Shared/down.png'
735
def __init__(self, editor, list, inspector, controllers):
736
ExplorerNodes.Controller.__init__(self, editor)
738
self.menu = wx.Menu()
740
[wxID_TP_NEW, wxID_TP_DEL, wxID_TP_UP, wxID_TP_DOWN] = Utils.wxNewIds(4)
742
self.transpMenuDef = [ (wxID_TP_NEW, 'Add new '+self.itemDescr,
743
self.OnNewTransport, self.addItemBmp),
744
(wxID_TP_DEL, 'Remove '+self.itemDescr,
745
self.OnDeleteTransport, self.removeItemBmp),
747
(wxID_TP_UP, 'Move up',
748
self.OnMoveTransportUp, self.moveUpBmp),
749
(wxID_TP_DOWN, 'Move down',
750
self.OnMoveTransportDown, self.moveDownBmp),
753
self.setupMenu(self.menu, self.list, self.transpMenuDef)
754
self.toolbarMenus = [self.transpMenuDef]
757
self.transpMenuDef = []
758
self.toolbarMenus = []
761
def editorUpdateNotify(self, info=''):
764
def OnReloadItems(self, event=None):
766
self.list.refreshCurrent()
768
def moveTransport(self, node, idx, direc):
770
for item in self.list.items:
771
names.append(item.name)
775
names.insert(idx + direc, name)
777
self.list.node.updateOrder(names)
779
self.list.refreshCurrent()
780
self.list.selectItemByIdx(idx+direc+1)
782
def OnMoveTransportUp(self, event):
784
ms = self.list.getMultiSelection()
785
nodes = self.getNodesForSelection(ms)
787
wx.LogError('Can only move 1 at a time')
790
idx = self.list.items.index(node)
792
wx.LogError('Already at the beginning')
794
self.moveTransport(node, idx, -1)
796
def OnMoveTransportDown(self, event):
798
ms = self.list.getMultiSelection()
799
nodes = self.getNodesForSelection(ms)
801
wx.LogError('Can only move 1 at a time')
804
idx = self.list.items.index(node)
805
if idx >= len(self.list.items) -1:
806
wx.LogError('Already at the end')
808
self.moveTransport(node, idx, 1)
810
def OnNewTransport(self, event):
813
def OnDeleteTransport(self, event):
816
class TransportPluginsLoadOrderController(TransportPluginsController):
817
itemDescr = 'Transport module'
819
def OnNewTransport(self, event):
820
dlg = wx.TextEntryDialog(self.list, 'Enter the fully qualified Python '\
821
'object path to \nthe Transport module. E.g. Explorers.FileExplorer',
824
if dlg.ShowModal() != wx.ID_OK:
826
transportModulePath = dlg.GetValue()
830
if not self.list.node.checkValidModulePath(transportModulePath):
831
if wx.MessageBox('Cannot locate the specified module path,\n'\
832
'are you sure you want to continue?',
834
wx.YES_NO | wx.ICON_EXCLAMATION) == wx.NO:
838
for item in self.list.items:
839
names.append(item.name)
841
names.append(transportModulePath)
843
self.list.node.updateOrder(names)
845
self.list.refreshCurrent()
847
def OnDeleteTransport(self, event):
848
selNames = self.list.getMultiSelection()
849
nodes = self.getNodesForSelection(selNames)
852
for item in self.list.items:
853
names.append(item.name)
856
names.remove(item.name)
858
self.list.node.updateOrder(names)
860
self.list.refreshCurrent()
862
class TransportPluginsTreeDisplayOrderController(TransportPluginsController):
863
itemDescr = 'Transports tree node'
865
def OnNewTransport(self, event):
866
dlg = wx.TextEntryDialog(self.list, 'Enter the protocol identifier. E.g. '\
867
'ftp, ssh', 'New Transports Tree Node', '')
869
if dlg.ShowModal() != wx.ID_OK:
871
protocol = dlg.GetValue()
876
for item in self.list.items:
877
names.append(item.name)
879
names.append(protocol)
881
self.list.node.updateOrder(names)
882
self.list.node.checkConfigEntry(protocol)
884
self.list.refreshCurrent()
886
def OnDeleteTransport(self, event):
887
selNames = self.list.getMultiSelection()
888
nodes = self.getNodesForSelection(selNames)
891
for item in self.list.items:
892
names.append(item.name)
895
names.remove(item.name)
896
self.list.node.clearEmptyConfigEntry(item.name)
898
self.list.node.updateOrder(names)
900
self.list.refreshCurrent()
903
class TransportPluginsLoadOrderGroupNode(PreferenceGroupNode):
905
protocol = 'prefs.group.plug-in.transport.load-order'
906
defName = 'TransportPluginsPrefsGroup'
908
name = 'Loading order'
909
PreferenceGroupNode.__init__(self, name, None)
912
conf = Utils.createAndReadConfig('Explorer')
914
modules = eval(conf.get('explorer', 'installedtransports'), {})
915
assert isinstance(modules, types.ListType)
919
if mod in ExplorerNodes.installedModules:
921
imgIdx = EditorHelper.imgSystemObjOrdered
922
elif mod in ExplorerNodes.failedModules.keys():
923
status = 'Broken: %s'%ExplorerNodes.failedModules[mod]
924
imgIdx = EditorHelper.imgSystemObjBroken
926
status = 'Pending restart'
927
imgIdx = EditorHelper.imgSystemObjPending
929
res.append(TransportPluginExplNode(mod, status, imgIdx))
932
def updateOrder(self, newOrder):
933
conf = Utils.createAndReadConfig('Explorer')
934
conf.set('explorer', 'installedtransports', pprint.pformat(newOrder))
935
Utils.writeConfig(conf)
937
def checkValidModulePath(self, name):
939
Utils.find_dotted_module(name)
940
except ImportError, err:
947
class TransportPluginsTreeDisplayOrderGroupNode(PreferenceGroupNode):
949
protocol = 'prefs.group.plug-in.transport.tree-order'
950
defName = 'TransportPluginsPrefsGroup'
952
name = 'Tree display order'
953
PreferenceGroupNode.__init__(self, name, None)
956
conf = Utils.createAndReadConfig('Explorer')
958
treeOrder = eval(conf.get('explorer', 'transportstree'), {})
959
assert isinstance(treeOrder, type([]))
962
for prot in treeOrder:
963
if not ExplorerNodes.nodeRegByProt.has_key(prot):
964
status = 'Protocol not installed'
965
imgIdx = EditorHelper.imgSystemObjPending
968
imgIdx = EditorHelper.imgSystemObjOrdered
970
res.append(TransportPluginExplNode(prot, status, imgIdx))
973
def updateOrder(self, newOrder):
974
conf = Utils.createAndReadConfig('Explorer')
975
conf.set('explorer', 'transportstree', pprint.pformat(newOrder))
976
Utils.writeConfig(conf)
978
def checkConfigEntry(self, protocol):
979
conf = Utils.createAndReadConfig('Explorer')
980
if not conf.has_option('explorer', protocol):
981
conf.set('explorer', protocol, '{}')
982
Utils.writeConfig(conf)
984
def clearEmptyConfigEntry(self, protocol):
985
conf = Utils.createAndReadConfig('Explorer')
986
if conf.has_option('explorer', protocol) and \
987
eval(conf.get('explorer', protocol).strip(), {}) == {}:
988
conf.remove_option('explorer', protocol)
989
Utils.writeConfig(conf)
992
class HelpConfigPGN(PreferenceGroupNode):
994
protocol = 'prefs.group.help.config'
995
defName = 'HelpConfigPrefsGroup'
998
PreferenceGroupNode.__init__(self, name, None)
1004
class HelpConfigBooksPGN(PreferenceGroupNode):
1006
protocol = 'prefs.group.help.config.books'
1007
defName = 'HelpConfigBooksPrefsGroup'
1010
PreferenceGroupNode.__init__(self, name, None)
1013
bookPaths = self.readBooks()
1015
for bookPath in bookPaths:
1017
res.append(HelpConfigBookNode(bookPath))
1018
except IOError, err:
1019
# too disruptive to display an error
1023
# return [HelpConfigBookNode(bookPath)
1024
# for bookPath in bookPaths]
1027
def readBooks(self):
1028
return eval(Utils.createAndReadConfig('Explorer').get('help', 'books'), {})
1030
def writeBooks(self, books):
1031
conf = Utils.createAndReadConfig('Explorer')
1032
conf.set('help', 'books', pprint.pformat(books))
1033
Utils.writeConfig(conf)
1036
def preparePath(self, path):
1037
helpPath = Preferences.pyPath+'/Docs/'
1039
if path.startswith('file://'):
1042
# Add relative paths for files inside Docs directory
1043
if os.path.normcase(path).startswith(os.path.normcase(helpPath)):
1044
return path[len(helpPath):]
1048
def editBook(self, curPath, newPath):
1049
books = self.readBooks()
1050
books[books.index(curPath)] = self.preparePath(newPath)
1051
self.writeBooks(books)
1053
def addBook(self, path):
1054
path = self.preparePath(path)
1055
self.writeBooks(self.readBooks() + [path])
1057
def removeBook(self, path):
1058
books = self.readBooks()
1060
self.writeBooks(books)
1062
def updateOrder(self, paths):
1063
self.writeBooks(paths)
1066
class HelpConfigBookNode(ExplorerNodes.ExplorerNode):
1068
protocol = 'help.book'
1069
def __init__(self, resourcepath):
1070
fullpath = self.getAbsPath(resourcepath)
1072
name = os.path.basename(resourcepath)
1073
if os.path.splitext(fullpath)[1] == '.hhp':
1074
# Peek at title inside hhp file
1075
for line in open(fullpath).readlines():
1076
if line.startswith('Title'):
1077
name = line.split('=')[1].strip()
1079
ExplorerNodes.ExplorerNode.__init__(self, name, resourcepath, None,
1080
EditorHelper.imgHelpBook, None, {})
1082
def open(self, editor):
1085
## def getURI(self):
1086
## return '%s (%s)'%(ExplorerNodes.ExplorerNode.getURI(self),
1087
## self.pluginStatus)
1089
def isFolderish(self):
1092
def notifyBeginLabelEdit(self, event):
1095
def getAbsPath(self, resourcepath):
1096
if not os.path.isabs(resourcepath):
1097
return os.path.join(Preferences.pyPath, 'Docs', resourcepath)
1103
class HelpConfigBooksController(ExplorerNodes.Controller):
1104
addItemBmp = 'Images/Shared/NewItem.png'
1105
removeItemBmp = 'Images/Shared/DeleteItem.png'
1106
moveUpBmp = 'Images/Shared/up.png'
1107
moveDownBmp = 'Images/Shared/down.png'
1111
def __init__(self, editor, list, inspector, controllers):
1112
ExplorerNodes.Controller.__init__(self, editor)
1114
self.menu = wx.Menu()
1116
[wxID_HB_EDIT, wxID_HB_NEW, wxID_HB_DEL, wxID_HB_UP, wxID_HB_DOWN,
1117
wxID_HB_REST, wxID_HB_CLRI, wxID_HB_OPEN] = Utils.wxNewIds(8)
1119
self.helpBooksMenuDef = [ (wxID_HB_EDIT, 'Edit '+self.itemDescr,
1120
self.OnEditBookPath, '-'),
1121
(wxID_HB_NEW, 'Add new '+self.itemDescr,
1122
self.OnNewBook, self.addItemBmp),
1123
(wxID_HB_DEL, 'Remove '+self.itemDescr,
1124
self.OnRemoveBook, self.removeItemBmp),
1125
(-1, '-', None, ''),
1126
(wxID_HB_UP, 'Move up',
1127
self.OnMoveBookUp, self.moveUpBmp),
1128
(wxID_HB_DOWN, 'Move down',
1129
self.OnMoveBookDown, self.moveDownBmp),
1130
(-1, '-', None, '-'),
1131
(wxID_HB_OPEN, 'Open hhp file',
1132
self.OnOpenHHP, '-'),
1133
(-1, '-', None, '-'),
1134
(wxID_HB_REST, 'Restart the help system',
1135
self.OnRestartHelp, '-'),
1136
(wxID_HB_CLRI, 'Clear the help indexes',
1137
self.OnClearHelpIndexes, '-'),
1140
self.setupMenu(self.menu, self.list, self.helpBooksMenuDef)
1141
self.toolbarMenus = [self.helpBooksMenuDef]
1144
self.helpBooksMenuDef = ()
1145
self.toolbarMenus = ()
1148
def editorUpdateNotify(self, info=''):
1149
self.OnReloadItems()
1151
def OnReloadItems(self, event=None):
1153
self.list.refreshCurrent()
1155
def moveBook(self, node, idx, direc):
1156
paths = [item.resourcepath for item in self.list.items]
1160
paths.insert(idx + direc, path)
1162
self.list.node.updateOrder(paths)
1164
self.list.refreshCurrent()
1165
self.list.selectItemByIdx(idx+direc+1)
1167
def OnMoveBookUp(self, event):
1169
ms = self.list.getMultiSelection()
1170
nodes = self.getNodesForSelection(ms)
1172
wx.LogError('Can only move 1 at a time')
1175
idx = self.list.items.index(node)
1177
wx.LogError('Already at the beginning')
1179
self.moveBook(node, idx, -1)
1181
def OnMoveBookDown(self, event):
1183
ms = self.list.getMultiSelection()
1184
nodes = self.getNodesForSelection(ms)
1186
wx.LogError('Can only move 1 at a time')
1189
idx = self.list.items.index(node)
1190
if idx >= len(self.list.items) -1:
1191
wx.LogError('Already at the end')
1193
self.moveBook(node, idx, 1)
1195
def OnEditBookPath(self, event):
1197
ms = self.list.getMultiSelection()
1198
for node in self.getNodesForSelection(ms):
1199
if not os.path.isabs(node.resourcepath):
1200
path = os.path.join(Preferences.pyPath,
1201
'Docs', node.resourcepath)
1203
path = node.resourcepath
1205
curpath, curfile = os.path.split(path)
1206
newpath = self.editor.openFileDlg('AllFiles', curdir=curpath)
1208
self.list.node.editBook(node.resourcepath, path)
1209
self.list.refreshCurrent()
1211
def OnNewBook(self, event):
1212
path = self.editor.openFileDlg('AllFiles', curdir=Preferences.pyPath+'/Docs')
1213
if path and self.list.node:
1214
self.list.node.addBook(path)
1215
self.list.refreshCurrent()
1217
def OnRemoveBook(self, event):
1219
ms = self.list.getMultiSelection()
1220
for node in self.getNodesForSelection(ms):
1221
self.list.node.removeBook(node.resourcepath)
1222
self.list.refreshCurrent()
1224
def OnRestartHelp(self, event):
1230
def OnClearHelpIndexes(self, event):
1233
cd = Help.getCacheDir()
1234
for name in os.listdir(cd):
1235
if os.path.splitext(name)[1] == '.cached':
1236
os.remove(os.path.join(cd, name))
1237
wx.LogMessage('Deleted %s'%name)
1239
def OnOpenHHP(self, event):
1241
ms = self.list.getMultiSelection()
1242
for node in self.getNodesForSelection(ms):
1243
self.editor.openOrGotoModule(node.getAbsPath(node.resourcepath))
1245
#-------------------------------------------------------------------------------
1248
ExplorerNodes.register(BoaPrefGroupNode)
1249
ExplorerNodes.register(PluginFilesGroupNode,
1250
controller=PluginFilesGroupNodeController)
1251
ExplorerNodes.register(TransportPluginsLoadOrderGroupNode,
1252
controller=TransportPluginsLoadOrderController)
1253
ExplorerNodes.register(TransportPluginsTreeDisplayOrderGroupNode,
1254
controller=TransportPluginsTreeDisplayOrderController)
1255
ExplorerNodes.register(HelpConfigBooksPGN, controller=HelpConfigBooksController)