symbian-qemu-0.9.1-12/python-2.6.1/Lib/idlelib/configHandler.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 """Provides access to stored IDLE configuration information.
       
     2 
       
     3 Refer to the comments at the beginning of config-main.def for a description of
       
     4 the available configuration files and the design implemented to update user
       
     5 configuration information.  In particular, user configuration choices which
       
     6 duplicate the defaults will be removed from the user's configuration files,
       
     7 and if a file becomes empty, it will be deleted.
       
     8 
       
     9 The contents of the user files may be altered using the Options/Configure IDLE
       
    10 menu to access the configuration GUI (configDialog.py), or manually.
       
    11 
       
    12 Throughout this module there is an emphasis on returning useable defaults
       
    13 when a problem occurs in returning a requested configuration value back to
       
    14 idle. This is to allow IDLE to continue to function in spite of errors in
       
    15 the retrieval of config information. When a default is returned instead of
       
    16 a requested config value, a message is printed to stderr to aid in
       
    17 configuration problem notification and resolution.
       
    18 
       
    19 """
       
    20 import os
       
    21 import sys
       
    22 import string
       
    23 import macosxSupport
       
    24 from ConfigParser import ConfigParser, NoOptionError, NoSectionError
       
    25 
       
    26 class InvalidConfigType(Exception): pass
       
    27 class InvalidConfigSet(Exception): pass
       
    28 class InvalidFgBg(Exception): pass
       
    29 class InvalidTheme(Exception): pass
       
    30 
       
    31 class IdleConfParser(ConfigParser):
       
    32     """
       
    33     A ConfigParser specialised for idle configuration file handling
       
    34     """
       
    35     def __init__(self, cfgFile, cfgDefaults=None):
       
    36         """
       
    37         cfgFile - string, fully specified configuration file name
       
    38         """
       
    39         self.file=cfgFile
       
    40         ConfigParser.__init__(self,defaults=cfgDefaults)
       
    41 
       
    42     def Get(self, section, option, type=None, default=None, raw=False):
       
    43         """
       
    44         Get an option value for given section/option or return default.
       
    45         If type is specified, return as type.
       
    46         """
       
    47         if not self.has_option(section, option):
       
    48             return default
       
    49         if type=='bool':
       
    50             return self.getboolean(section, option)
       
    51         elif type=='int':
       
    52             return self.getint(section, option)
       
    53         else:
       
    54             return self.get(section, option, raw=raw)
       
    55 
       
    56     def GetOptionList(self,section):
       
    57         """
       
    58         Get an option list for given section
       
    59         """
       
    60         if self.has_section(section):
       
    61             return self.options(section)
       
    62         else:  #return a default value
       
    63             return []
       
    64 
       
    65     def Load(self):
       
    66         """
       
    67         Load the configuration file from disk
       
    68         """
       
    69         self.read(self.file)
       
    70 
       
    71 class IdleUserConfParser(IdleConfParser):
       
    72     """
       
    73     IdleConfigParser specialised for user configuration handling.
       
    74     """
       
    75 
       
    76     def AddSection(self,section):
       
    77         """
       
    78         if section doesn't exist, add it
       
    79         """
       
    80         if not self.has_section(section):
       
    81             self.add_section(section)
       
    82 
       
    83     def RemoveEmptySections(self):
       
    84         """
       
    85         remove any sections that have no options
       
    86         """
       
    87         for section in self.sections():
       
    88             if not self.GetOptionList(section):
       
    89                 self.remove_section(section)
       
    90 
       
    91     def IsEmpty(self):
       
    92         """
       
    93         Remove empty sections and then return 1 if parser has no sections
       
    94         left, else return 0.
       
    95         """
       
    96         self.RemoveEmptySections()
       
    97         if self.sections():
       
    98             return 0
       
    99         else:
       
   100             return 1
       
   101 
       
   102     def RemoveOption(self,section,option):
       
   103         """
       
   104         If section/option exists, remove it.
       
   105         Returns 1 if option was removed, 0 otherwise.
       
   106         """
       
   107         if self.has_section(section):
       
   108             return self.remove_option(section,option)
       
   109 
       
   110     def SetOption(self,section,option,value):
       
   111         """
       
   112         Sets option to value, adding section if required.
       
   113         Returns 1 if option was added or changed, otherwise 0.
       
   114         """
       
   115         if self.has_option(section,option):
       
   116             if self.get(section,option)==value:
       
   117                 return 0
       
   118             else:
       
   119                 self.set(section,option,value)
       
   120                 return 1
       
   121         else:
       
   122             if not self.has_section(section):
       
   123                 self.add_section(section)
       
   124             self.set(section,option,value)
       
   125             return 1
       
   126 
       
   127     def RemoveFile(self):
       
   128         """
       
   129         Removes the user config file from disk if it exists.
       
   130         """
       
   131         if os.path.exists(self.file):
       
   132             os.remove(self.file)
       
   133 
       
   134     def Save(self):
       
   135         """Update user configuration file.
       
   136 
       
   137         Remove empty sections. If resulting config isn't empty, write the file
       
   138         to disk. If config is empty, remove the file from disk if it exists.
       
   139 
       
   140         """
       
   141         if not self.IsEmpty():
       
   142             fname = self.file
       
   143             try:
       
   144                 cfgFile = open(fname, 'w')
       
   145             except IOError:
       
   146                 os.unlink(fname)
       
   147                 cfgFile = open(fname, 'w')
       
   148             self.write(cfgFile)
       
   149         else:
       
   150             self.RemoveFile()
       
   151 
       
   152 class IdleConf:
       
   153     """
       
   154     holds config parsers for all idle config files:
       
   155     default config files
       
   156         (idle install dir)/config-main.def
       
   157         (idle install dir)/config-extensions.def
       
   158         (idle install dir)/config-highlight.def
       
   159         (idle install dir)/config-keys.def
       
   160     user config  files
       
   161         (user home dir)/.idlerc/config-main.cfg
       
   162         (user home dir)/.idlerc/config-extensions.cfg
       
   163         (user home dir)/.idlerc/config-highlight.cfg
       
   164         (user home dir)/.idlerc/config-keys.cfg
       
   165     """
       
   166     def __init__(self):
       
   167         self.defaultCfg={}
       
   168         self.userCfg={}
       
   169         self.cfg={}
       
   170         self.CreateConfigHandlers()
       
   171         self.LoadCfgFiles()
       
   172         #self.LoadCfg()
       
   173 
       
   174     def CreateConfigHandlers(self):
       
   175         """
       
   176         set up a dictionary of config parsers for default and user
       
   177         configurations respectively
       
   178         """
       
   179         #build idle install path
       
   180         if __name__ != '__main__': # we were imported
       
   181             idleDir=os.path.dirname(__file__)
       
   182         else: # we were exec'ed (for testing only)
       
   183             idleDir=os.path.abspath(sys.path[0])
       
   184         userDir=self.GetUserCfgDir()
       
   185         configTypes=('main','extensions','highlight','keys')
       
   186         defCfgFiles={}
       
   187         usrCfgFiles={}
       
   188         for cfgType in configTypes: #build config file names
       
   189             defCfgFiles[cfgType]=os.path.join(idleDir,'config-'+cfgType+'.def')
       
   190             usrCfgFiles[cfgType]=os.path.join(userDir,'config-'+cfgType+'.cfg')
       
   191         for cfgType in configTypes: #create config parsers
       
   192             self.defaultCfg[cfgType]=IdleConfParser(defCfgFiles[cfgType])
       
   193             self.userCfg[cfgType]=IdleUserConfParser(usrCfgFiles[cfgType])
       
   194 
       
   195     def GetUserCfgDir(self):
       
   196         """
       
   197         Creates (if required) and returns a filesystem directory for storing
       
   198         user config files.
       
   199 
       
   200         """
       
   201         cfgDir = '.idlerc'
       
   202         userDir = os.path.expanduser('~')
       
   203         if userDir != '~': # expanduser() found user home dir
       
   204             if not os.path.exists(userDir):
       
   205                 warn = ('\n Warning: os.path.expanduser("~") points to\n '+
       
   206                         userDir+',\n but the path does not exist.\n')
       
   207                 try:
       
   208                     sys.stderr.write(warn)
       
   209                 except IOError:
       
   210                     pass
       
   211                 userDir = '~'
       
   212         if userDir == "~": # still no path to home!
       
   213             # traditionally IDLE has defaulted to os.getcwd(), is this adequate?
       
   214             userDir = os.getcwd()
       
   215         userDir = os.path.join(userDir, cfgDir)
       
   216         if not os.path.exists(userDir):
       
   217             try:
       
   218                 os.mkdir(userDir)
       
   219             except (OSError, IOError):
       
   220                 warn = ('\n Warning: unable to create user config directory\n'+
       
   221                         userDir+'\n Check path and permissions.\n Exiting!\n\n')
       
   222                 sys.stderr.write(warn)
       
   223                 raise SystemExit
       
   224         return userDir
       
   225 
       
   226     def GetOption(self, configType, section, option, default=None, type=None,
       
   227                   warn_on_default=True, raw=False):
       
   228         """
       
   229         Get an option value for given config type and given general
       
   230         configuration section/option or return a default. If type is specified,
       
   231         return as type. Firstly the user configuration is checked, with a
       
   232         fallback to the default configuration, and a final 'catch all'
       
   233         fallback to a useable passed-in default if the option isn't present in
       
   234         either the user or the default configuration.
       
   235         configType must be one of ('main','extensions','highlight','keys')
       
   236         If a default is returned, and warn_on_default is True, a warning is
       
   237         printed to stderr.
       
   238 
       
   239         """
       
   240         if self.userCfg[configType].has_option(section,option):
       
   241             return self.userCfg[configType].Get(section, option,
       
   242                                                 type=type, raw=raw)
       
   243         elif self.defaultCfg[configType].has_option(section,option):
       
   244             return self.defaultCfg[configType].Get(section, option,
       
   245                                                    type=type, raw=raw)
       
   246         else: #returning default, print warning
       
   247             if warn_on_default:
       
   248                 warning = ('\n Warning: configHandler.py - IdleConf.GetOption -\n'
       
   249                            ' problem retrieving configration option %r\n'
       
   250                            ' from section %r.\n'
       
   251                            ' returning default value: %r\n' %
       
   252                            (option, section, default))
       
   253                 try:
       
   254                     sys.stderr.write(warning)
       
   255                 except IOError:
       
   256                     pass
       
   257             return default
       
   258 
       
   259     def SetOption(self, configType, section, option, value):
       
   260         """In user's config file, set section's option to value.
       
   261 
       
   262         """
       
   263         self.userCfg[configType].SetOption(section, option, value)
       
   264 
       
   265     def GetSectionList(self, configSet, configType):
       
   266         """
       
   267         Get a list of sections from either the user or default config for
       
   268         the given config type.
       
   269         configSet must be either 'user' or 'default'
       
   270         configType must be one of ('main','extensions','highlight','keys')
       
   271         """
       
   272         if not (configType in ('main','extensions','highlight','keys')):
       
   273             raise InvalidConfigType, 'Invalid configType specified'
       
   274         if configSet == 'user':
       
   275             cfgParser=self.userCfg[configType]
       
   276         elif configSet == 'default':
       
   277             cfgParser=self.defaultCfg[configType]
       
   278         else:
       
   279             raise InvalidConfigSet, 'Invalid configSet specified'
       
   280         return cfgParser.sections()
       
   281 
       
   282     def GetHighlight(self, theme, element, fgBg=None):
       
   283         """
       
   284         return individual highlighting theme elements.
       
   285         fgBg - string ('fg'or'bg') or None, if None return a dictionary
       
   286         containing fg and bg colours (appropriate for passing to Tkinter in,
       
   287         e.g., a tag_config call), otherwise fg or bg colour only as specified.
       
   288         """
       
   289         if self.defaultCfg['highlight'].has_section(theme):
       
   290             themeDict=self.GetThemeDict('default',theme)
       
   291         else:
       
   292             themeDict=self.GetThemeDict('user',theme)
       
   293         fore=themeDict[element+'-foreground']
       
   294         if element=='cursor': #there is no config value for cursor bg
       
   295             back=themeDict['normal-background']
       
   296         else:
       
   297             back=themeDict[element+'-background']
       
   298         highlight={"foreground": fore,"background": back}
       
   299         if not fgBg: #return dict of both colours
       
   300             return highlight
       
   301         else: #return specified colour only
       
   302             if fgBg == 'fg':
       
   303                 return highlight["foreground"]
       
   304             if fgBg == 'bg':
       
   305                 return highlight["background"]
       
   306             else:
       
   307                 raise InvalidFgBg, 'Invalid fgBg specified'
       
   308 
       
   309     def GetThemeDict(self,type,themeName):
       
   310         """
       
   311         type - string, 'default' or 'user' theme type
       
   312         themeName - string, theme name
       
   313         Returns a dictionary which holds {option:value} for each element
       
   314         in the specified theme. Values are loaded over a set of ultimate last
       
   315         fallback defaults to guarantee that all theme elements are present in
       
   316         a newly created theme.
       
   317         """
       
   318         if type == 'user':
       
   319             cfgParser=self.userCfg['highlight']
       
   320         elif type == 'default':
       
   321             cfgParser=self.defaultCfg['highlight']
       
   322         else:
       
   323             raise InvalidTheme, 'Invalid theme type specified'
       
   324         #foreground and background values are provded for each theme element
       
   325         #(apart from cursor) even though all these values are not yet used
       
   326         #by idle, to allow for their use in the future. Default values are
       
   327         #generally black and white.
       
   328         theme={ 'normal-foreground':'#000000',
       
   329                 'normal-background':'#ffffff',
       
   330                 'keyword-foreground':'#000000',
       
   331                 'keyword-background':'#ffffff',
       
   332                 'builtin-foreground':'#000000',
       
   333                 'builtin-background':'#ffffff',
       
   334                 'comment-foreground':'#000000',
       
   335                 'comment-background':'#ffffff',
       
   336                 'string-foreground':'#000000',
       
   337                 'string-background':'#ffffff',
       
   338                 'definition-foreground':'#000000',
       
   339                 'definition-background':'#ffffff',
       
   340                 'hilite-foreground':'#000000',
       
   341                 'hilite-background':'gray',
       
   342                 'break-foreground':'#ffffff',
       
   343                 'break-background':'#000000',
       
   344                 'hit-foreground':'#ffffff',
       
   345                 'hit-background':'#000000',
       
   346                 'error-foreground':'#ffffff',
       
   347                 'error-background':'#000000',
       
   348                 #cursor (only foreground can be set)
       
   349                 'cursor-foreground':'#000000',
       
   350                 #shell window
       
   351                 'stdout-foreground':'#000000',
       
   352                 'stdout-background':'#ffffff',
       
   353                 'stderr-foreground':'#000000',
       
   354                 'stderr-background':'#ffffff',
       
   355                 'console-foreground':'#000000',
       
   356                 'console-background':'#ffffff' }
       
   357         for element in theme.keys():
       
   358             if not cfgParser.has_option(themeName,element):
       
   359                 #we are going to return a default, print warning
       
   360                 warning=('\n Warning: configHandler.py - IdleConf.GetThemeDict'
       
   361                            ' -\n problem retrieving theme element %r'
       
   362                            '\n from theme %r.\n'
       
   363                            ' returning default value: %r\n' %
       
   364                            (element, themeName, theme[element]))
       
   365                 try:
       
   366                     sys.stderr.write(warning)
       
   367                 except IOError:
       
   368                     pass
       
   369             colour=cfgParser.Get(themeName,element,default=theme[element])
       
   370             theme[element]=colour
       
   371         return theme
       
   372 
       
   373     def CurrentTheme(self):
       
   374         """
       
   375         Returns the name of the currently active theme
       
   376         """
       
   377         return self.GetOption('main','Theme','name',default='')
       
   378 
       
   379     def CurrentKeys(self):
       
   380         """
       
   381         Returns the name of the currently active key set
       
   382         """
       
   383         return self.GetOption('main','Keys','name',default='')
       
   384 
       
   385     def GetExtensions(self, active_only=True, editor_only=False, shell_only=False):
       
   386         """
       
   387         Gets a list of all idle extensions declared in the config files.
       
   388         active_only - boolean, if true only return active (enabled) extensions
       
   389         """
       
   390         extns=self.RemoveKeyBindNames(
       
   391                 self.GetSectionList('default','extensions'))
       
   392         userExtns=self.RemoveKeyBindNames(
       
   393                 self.GetSectionList('user','extensions'))
       
   394         for extn in userExtns:
       
   395             if extn not in extns: #user has added own extension
       
   396                 extns.append(extn)
       
   397         if active_only:
       
   398             activeExtns=[]
       
   399             for extn in extns:
       
   400                 if self.GetOption('extensions', extn, 'enable', default=True,
       
   401                                   type='bool'):
       
   402                     #the extension is enabled
       
   403                     if editor_only or shell_only:
       
   404                         if editor_only:
       
   405                             option = "enable_editor"
       
   406                         else:
       
   407                             option = "enable_shell"
       
   408                         if self.GetOption('extensions', extn,option,
       
   409                                           default=True, type='bool',
       
   410                                           warn_on_default=False):
       
   411                             activeExtns.append(extn)
       
   412                     else:
       
   413                         activeExtns.append(extn)
       
   414             return activeExtns
       
   415         else:
       
   416             return extns
       
   417 
       
   418     def RemoveKeyBindNames(self,extnNameList):
       
   419         #get rid of keybinding section names
       
   420         names=extnNameList
       
   421         kbNameIndicies=[]
       
   422         for name in names:
       
   423             if name.endswith(('_bindings', '_cfgBindings')):
       
   424                 kbNameIndicies.append(names.index(name))
       
   425         kbNameIndicies.sort()
       
   426         kbNameIndicies.reverse()
       
   427         for index in kbNameIndicies: #delete each keybinding section name
       
   428             del(names[index])
       
   429         return names
       
   430 
       
   431     def GetExtnNameForEvent(self,virtualEvent):
       
   432         """
       
   433         Returns the name of the extension that virtualEvent is bound in, or
       
   434         None if not bound in any extension.
       
   435         virtualEvent - string, name of the virtual event to test for, without
       
   436                        the enclosing '<< >>'
       
   437         """
       
   438         extName=None
       
   439         vEvent='<<'+virtualEvent+'>>'
       
   440         for extn in self.GetExtensions(active_only=0):
       
   441             for event in self.GetExtensionKeys(extn).keys():
       
   442                 if event == vEvent:
       
   443                     extName=extn
       
   444         return extName
       
   445 
       
   446     def GetExtensionKeys(self,extensionName):
       
   447         """
       
   448         returns a dictionary of the configurable keybindings for a particular
       
   449         extension,as they exist in the dictionary returned by GetCurrentKeySet;
       
   450         that is, where previously used bindings are disabled.
       
   451         """
       
   452         keysName=extensionName+'_cfgBindings'
       
   453         activeKeys=self.GetCurrentKeySet()
       
   454         extKeys={}
       
   455         if self.defaultCfg['extensions'].has_section(keysName):
       
   456             eventNames=self.defaultCfg['extensions'].GetOptionList(keysName)
       
   457             for eventName in eventNames:
       
   458                 event='<<'+eventName+'>>'
       
   459                 binding=activeKeys[event]
       
   460                 extKeys[event]=binding
       
   461         return extKeys
       
   462 
       
   463     def __GetRawExtensionKeys(self,extensionName):
       
   464         """
       
   465         returns a dictionary of the configurable keybindings for a particular
       
   466         extension, as defined in the configuration files, or an empty dictionary
       
   467         if no bindings are found
       
   468         """
       
   469         keysName=extensionName+'_cfgBindings'
       
   470         extKeys={}
       
   471         if self.defaultCfg['extensions'].has_section(keysName):
       
   472             eventNames=self.defaultCfg['extensions'].GetOptionList(keysName)
       
   473             for eventName in eventNames:
       
   474                 binding=self.GetOption('extensions',keysName,
       
   475                         eventName,default='').split()
       
   476                 event='<<'+eventName+'>>'
       
   477                 extKeys[event]=binding
       
   478         return extKeys
       
   479 
       
   480     def GetExtensionBindings(self,extensionName):
       
   481         """
       
   482         Returns a dictionary of all the event bindings for a particular
       
   483         extension. The configurable keybindings are returned as they exist in
       
   484         the dictionary returned by GetCurrentKeySet; that is, where re-used
       
   485         keybindings are disabled.
       
   486         """
       
   487         bindsName=extensionName+'_bindings'
       
   488         extBinds=self.GetExtensionKeys(extensionName)
       
   489         #add the non-configurable bindings
       
   490         if self.defaultCfg['extensions'].has_section(bindsName):
       
   491             eventNames=self.defaultCfg['extensions'].GetOptionList(bindsName)
       
   492             for eventName in eventNames:
       
   493                 binding=self.GetOption('extensions',bindsName,
       
   494                         eventName,default='').split()
       
   495                 event='<<'+eventName+'>>'
       
   496                 extBinds[event]=binding
       
   497 
       
   498         return extBinds
       
   499 
       
   500     def GetKeyBinding(self, keySetName, eventStr):
       
   501         """
       
   502         returns the keybinding for a specific event.
       
   503         keySetName - string, name of key binding set
       
   504         eventStr - string, the virtual event we want the binding for,
       
   505                    represented as a string, eg. '<<event>>'
       
   506         """
       
   507         eventName=eventStr[2:-2] #trim off the angle brackets
       
   508         binding=self.GetOption('keys',keySetName,eventName,default='').split()
       
   509         return binding
       
   510 
       
   511     def GetCurrentKeySet(self):
       
   512         result = self.GetKeySet(self.CurrentKeys())
       
   513 
       
   514         if macosxSupport.runningAsOSXApp():
       
   515             # We're using AquaTk, replace all keybingings that use the
       
   516             # Alt key by ones that use the Option key because the former
       
   517             # don't work reliably.
       
   518             for k, v in result.items():
       
   519                 v2 = [ x.replace('<Alt-', '<Option-') for x in v ]
       
   520                 if v != v2:
       
   521                     result[k] = v2
       
   522 
       
   523         return result
       
   524 
       
   525     def GetKeySet(self,keySetName):
       
   526         """
       
   527         Returns a dictionary of: all requested core keybindings, plus the
       
   528         keybindings for all currently active extensions. If a binding defined
       
   529         in an extension is already in use, that binding is disabled.
       
   530         """
       
   531         keySet=self.GetCoreKeys(keySetName)
       
   532         activeExtns=self.GetExtensions(active_only=1)
       
   533         for extn in activeExtns:
       
   534             extKeys=self.__GetRawExtensionKeys(extn)
       
   535             if extKeys: #the extension defines keybindings
       
   536                 for event in extKeys.keys():
       
   537                     if extKeys[event] in keySet.values():
       
   538                         #the binding is already in use
       
   539                         extKeys[event]='' #disable this binding
       
   540                     keySet[event]=extKeys[event] #add binding
       
   541         return keySet
       
   542 
       
   543     def IsCoreBinding(self,virtualEvent):
       
   544         """
       
   545         returns true if the virtual event is bound in the core idle keybindings.
       
   546         virtualEvent - string, name of the virtual event to test for, without
       
   547                        the enclosing '<< >>'
       
   548         """
       
   549         return ('<<'+virtualEvent+'>>') in self.GetCoreKeys().keys()
       
   550 
       
   551     def GetCoreKeys(self, keySetName=None):
       
   552         """
       
   553         returns the requested set of core keybindings, with fallbacks if
       
   554         required.
       
   555         Keybindings loaded from the config file(s) are loaded _over_ these
       
   556         defaults, so if there is a problem getting any core binding there will
       
   557         be an 'ultimate last resort fallback' to the CUA-ish bindings
       
   558         defined here.
       
   559         """
       
   560         keyBindings={
       
   561             '<<copy>>': ['<Control-c>', '<Control-C>'],
       
   562             '<<cut>>': ['<Control-x>', '<Control-X>'],
       
   563             '<<paste>>': ['<Control-v>', '<Control-V>'],
       
   564             '<<beginning-of-line>>': ['<Control-a>', '<Home>'],
       
   565             '<<center-insert>>': ['<Control-l>'],
       
   566             '<<close-all-windows>>': ['<Control-q>'],
       
   567             '<<close-window>>': ['<Alt-F4>'],
       
   568             '<<do-nothing>>': ['<Control-x>'],
       
   569             '<<end-of-file>>': ['<Control-d>'],
       
   570             '<<python-docs>>': ['<F1>'],
       
   571             '<<python-context-help>>': ['<Shift-F1>'],
       
   572             '<<history-next>>': ['<Alt-n>'],
       
   573             '<<history-previous>>': ['<Alt-p>'],
       
   574             '<<interrupt-execution>>': ['<Control-c>'],
       
   575             '<<view-restart>>': ['<F6>'],
       
   576             '<<restart-shell>>': ['<Control-F6>'],
       
   577             '<<open-class-browser>>': ['<Alt-c>'],
       
   578             '<<open-module>>': ['<Alt-m>'],
       
   579             '<<open-new-window>>': ['<Control-n>'],
       
   580             '<<open-window-from-file>>': ['<Control-o>'],
       
   581             '<<plain-newline-and-indent>>': ['<Control-j>'],
       
   582             '<<print-window>>': ['<Control-p>'],
       
   583             '<<redo>>': ['<Control-y>'],
       
   584             '<<remove-selection>>': ['<Escape>'],
       
   585             '<<save-copy-of-window-as-file>>': ['<Alt-Shift-S>'],
       
   586             '<<save-window-as-file>>': ['<Alt-s>'],
       
   587             '<<save-window>>': ['<Control-s>'],
       
   588             '<<select-all>>': ['<Alt-a>'],
       
   589             '<<toggle-auto-coloring>>': ['<Control-slash>'],
       
   590             '<<undo>>': ['<Control-z>'],
       
   591             '<<find-again>>': ['<Control-g>', '<F3>'],
       
   592             '<<find-in-files>>': ['<Alt-F3>'],
       
   593             '<<find-selection>>': ['<Control-F3>'],
       
   594             '<<find>>': ['<Control-f>'],
       
   595             '<<replace>>': ['<Control-h>'],
       
   596             '<<goto-line>>': ['<Alt-g>'],
       
   597             '<<smart-backspace>>': ['<Key-BackSpace>'],
       
   598             '<<newline-and-indent>>': ['<Key-Return> <Key-KP_Enter>'],
       
   599             '<<smart-indent>>': ['<Key-Tab>'],
       
   600             '<<indent-region>>': ['<Control-Key-bracketright>'],
       
   601             '<<dedent-region>>': ['<Control-Key-bracketleft>'],
       
   602             '<<comment-region>>': ['<Alt-Key-3>'],
       
   603             '<<uncomment-region>>': ['<Alt-Key-4>'],
       
   604             '<<tabify-region>>': ['<Alt-Key-5>'],
       
   605             '<<untabify-region>>': ['<Alt-Key-6>'],
       
   606             '<<toggle-tabs>>': ['<Alt-Key-t>'],
       
   607             '<<change-indentwidth>>': ['<Alt-Key-u>'],
       
   608             '<<del-word-left>>': ['<Control-Key-BackSpace>'],
       
   609             '<<del-word-right>>': ['<Control-Key-Delete>']
       
   610             }
       
   611         if keySetName:
       
   612             for event in keyBindings.keys():
       
   613                 binding=self.GetKeyBinding(keySetName,event)
       
   614                 if binding:
       
   615                     keyBindings[event]=binding
       
   616                 else: #we are going to return a default, print warning
       
   617                     warning=('\n Warning: configHandler.py - IdleConf.GetCoreKeys'
       
   618                                ' -\n problem retrieving key binding for event %r'
       
   619                                '\n from key set %r.\n'
       
   620                                ' returning default value: %r\n' %
       
   621                                (event, keySetName, keyBindings[event]))
       
   622                     try:
       
   623                         sys.stderr.write(warning)
       
   624                     except IOError:
       
   625                         pass
       
   626         return keyBindings
       
   627 
       
   628     def GetExtraHelpSourceList(self,configSet):
       
   629         """Fetch list of extra help sources from a given configSet.
       
   630 
       
   631         Valid configSets are 'user' or 'default'.  Return a list of tuples of
       
   632         the form (menu_item , path_to_help_file , option), or return the empty
       
   633         list.  'option' is the sequence number of the help resource.  'option'
       
   634         values determine the position of the menu items on the Help menu,
       
   635         therefore the returned list must be sorted by 'option'.
       
   636 
       
   637         """
       
   638         helpSources=[]
       
   639         if configSet=='user':
       
   640             cfgParser=self.userCfg['main']
       
   641         elif configSet=='default':
       
   642             cfgParser=self.defaultCfg['main']
       
   643         else:
       
   644             raise InvalidConfigSet, 'Invalid configSet specified'
       
   645         options=cfgParser.GetOptionList('HelpFiles')
       
   646         for option in options:
       
   647             value=cfgParser.Get('HelpFiles',option,default=';')
       
   648             if value.find(';')==-1: #malformed config entry with no ';'
       
   649                 menuItem='' #make these empty
       
   650                 helpPath='' #so value won't be added to list
       
   651             else: #config entry contains ';' as expected
       
   652                 value=string.split(value,';')
       
   653                 menuItem=value[0].strip()
       
   654                 helpPath=value[1].strip()
       
   655             if menuItem and helpPath: #neither are empty strings
       
   656                 helpSources.append( (menuItem,helpPath,option) )
       
   657         helpSources.sort(self.__helpsort)
       
   658         return helpSources
       
   659 
       
   660     def __helpsort(self, h1, h2):
       
   661         if int(h1[2]) < int(h2[2]):
       
   662             return -1
       
   663         elif int(h1[2]) > int(h2[2]):
       
   664             return 1
       
   665         else:
       
   666             return 0
       
   667 
       
   668     def GetAllExtraHelpSourcesList(self):
       
   669         """
       
   670         Returns a list of tuples containing the details of all additional help
       
   671         sources configured, or an empty list if there are none. Tuples are of
       
   672         the format returned by GetExtraHelpSourceList.
       
   673         """
       
   674         allHelpSources=( self.GetExtraHelpSourceList('default')+
       
   675                 self.GetExtraHelpSourceList('user') )
       
   676         return allHelpSources
       
   677 
       
   678     def LoadCfgFiles(self):
       
   679         """
       
   680         load all configuration files.
       
   681         """
       
   682         for key in self.defaultCfg.keys():
       
   683             self.defaultCfg[key].Load()
       
   684             self.userCfg[key].Load() #same keys
       
   685 
       
   686     def SaveUserCfgFiles(self):
       
   687         """
       
   688         write all loaded user configuration files back to disk
       
   689         """
       
   690         for key in self.userCfg.keys():
       
   691             self.userCfg[key].Save()
       
   692 
       
   693 idleConf=IdleConf()
       
   694 
       
   695 ### module test
       
   696 if __name__ == '__main__':
       
   697     def dumpCfg(cfg):
       
   698         print '\n',cfg,'\n'
       
   699         for key in cfg.keys():
       
   700             sections=cfg[key].sections()
       
   701             print key
       
   702             print sections
       
   703             for section in sections:
       
   704                 options=cfg[key].options(section)
       
   705                 print section
       
   706                 print options
       
   707                 for option in options:
       
   708                     print option, '=', cfg[key].Get(section,option)
       
   709     dumpCfg(idleConf.defaultCfg)
       
   710     dumpCfg(idleConf.userCfg)
       
   711     print idleConf.userCfg['main'].Get('Theme','name')
       
   712     #print idleConf.userCfg['highlight'].GetDefHighlight('Foo','normal')