From f9bb90e4539b4443960dc2ab217166fb4635b0bb Mon Sep 17 00:00:00 2001
From: "Steven M. Gava" <elguavas@python.net>
Date: Thu, 24 Jan 2002 06:02:50 +0000
Subject: further work on saving configs

---
 Lib/idlelib/configDialog.py     | 119 ++++++++++++++++++++++++++++++++--------
 Lib/idlelib/configHandler.py    |  91 ++++++++++++++++++++++--------
 Lib/idlelib/keybindingDialog.py |   2 -
 3 files changed, 165 insertions(+), 47 deletions(-)

diff --git a/Lib/idlelib/configDialog.py b/Lib/idlelib/configDialog.py
index b990f23..6664b9f 100644
--- a/Lib/idlelib/configDialog.py
+++ b/Lib/idlelib/configDialog.py
@@ -9,7 +9,7 @@ from configHandler import idleConf
 from dynOptionMenuWidget import DynOptionMenu
 from tabpage import TabPageSet
 from keybindingDialog import GetKeysDialog
-
+from configSectionNameDialog import GetCfgSectionNameDialog
 class ConfigDialog(Toplevel):
     """
     configuration dialog for idle
@@ -222,7 +222,7 @@ class ConfigDialog(Toplevel):
             value=0,text='Background',command=self.SetColourSampleBinding)
         self.fgHilite.set(1)
         buttonSaveCustomTheme=Button(frameCustom, 
-            text='Save as a Custom Theme')
+            text='Save as New Custom Theme')
         #frameTheme
         labelThemeTitle=Label(frameTheme,text='Select a Highlighting Theme')
         labelTypeTitle=Label(frameTheme,text='Select : ')
@@ -287,7 +287,7 @@ class ConfigDialog(Toplevel):
         self.listBindings.config(xscrollcommand=scrollTargetX.set)
         self.buttonNewKeys=Button(frameCustom,text='Get New Keys for Selection',
             command=self.GetNewKeys,state=DISABLED)
-        buttonSaveCustomKeys=Button(frameCustom,text='Save as a Custom Key Set')
+        buttonSaveCustomKeys=Button(frameCustom,text='Save as New Custom Key Set')
         #frameKeySets
         labelKeysTitle=Label(frameKeySets,text='Select a Key Set')
         labelTypeTitle=Label(frameKeySets,text='Select : ')
@@ -496,6 +496,7 @@ class ConfigDialog(Toplevel):
             self.buttonDeleteCustomTheme.config(state=DISABLED)
         else:
             self.optMenuThemeBuiltin.config(state=DISABLED)
+            self.radioThemeCustom.config(state=NORMAL)
             self.optMenuThemeCustom.config(state=NORMAL)
             self.buttonDeleteCustomTheme.config(state=NORMAL)
 
@@ -506,15 +507,79 @@ class ConfigDialog(Toplevel):
             self.buttonDeleteCustomKeys.config(state=DISABLED)
         else:
             self.optMenuKeysBuiltin.config(state=DISABLED)
+            self.radioKeysCustom.config(state=NORMAL)
             self.optMenuKeysCustom.config(state=NORMAL)
             self.buttonDeleteCustomKeys.config(state=NORMAL)
     
+    def GetNewKeys(self):
+        listIndex=self.listBindings.index(ANCHOR)
+        binding=self.listBindings.get(listIndex)
+        bindName=binding.split()[0] #first part, up to first space
+        currentKeySequences=idleConf.GetCurrentKeySet().values()
+        newKeys=GetKeysDialog(self,'Get New Keys',bindName,currentKeySequences)
+        if newKeys.result: #new keys were specified
+            if self.keysAreDefault.get(): #current key set is a built-in
+                message=('Your changes will be saved as a new Custom Key Set. '+
+                        'Enter a name for your new Custom Key Set below.')
+                usedNames=idleConf.GetSectionList('user','keys')
+                newKeySet=GetCfgSectionNameDialog(self,'New Custom Key Set',
+                        message,usedNames)
+                if not newKeySet.result: #user cancelled custom key set creation
+                    self.listBindings.select_set(listIndex)
+                    self.listBindings.select_anchor(listIndex)
+                    return
+                else: #create new custom key set based on previously active key set 
+                    self.CreateNewKeySet(newKeySet.result)    
+            self.listBindings.delete(listIndex)
+            self.listBindings.insert(listIndex,bindName+' - '+newKeys.result)
+            self.listBindings.select_set(listIndex)
+            self.listBindings.select_anchor(listIndex)
+            self.keyBinding.set(newKeys.result)
+        else:
+            self.listBindings.select_set(listIndex)
+            self.listBindings.select_anchor(listIndex)
+
+    def KeyBindingSelected(self,event):
+        self.buttonNewKeys.config(state=NORMAL)
+
+    def CreateNewKeySet(self,newKeySetName):
+        #creates new custom key set based on the previously active key set,
+        #and makes the new key set active
+        if self.keysAreDefault.get(): 
+            keySetName=self.builtinKeys.get()
+        else:  
+            keySetName=self.customKeys.get()
+        prevKeySet=idleConf.GetKeySet(keySetName)
+        #add the new key set to changedItems
+        for event in prevKeySet.keys():
+            eventName=event[2:-2] #trim off the angle brackets
+            self.AddChangedItem('keys',newKeySetName,eventName,
+                    prevKeySet[event])
+        #change gui over to the new key set
+        customKeyList=idleConf.GetSectionList('user','keys')
+        customKeyList.append(newKeySetName)
+        customKeyList.sort()
+        print newKeySetName,customKeyList,self.changedItems['keys'][newKeySetName]
+        self.optMenuKeysCustom.SetMenu(customKeyList,newKeySetName)
+        self.keysAreDefault.set(0)
+        self.SetKeysType()
+    
     def GetColour(self):
         target=self.highlightTarget.get()
         rgbTuplet, colourString = tkColorChooser.askcolor(parent=self,
             title='Pick new colour for : '+target,
             initialcolor=self.frameColourSet.cget('bg'))
         if colourString: #user didn't cancel
+            if self.themeIsBuiltin.get(): #current theme is a built-in
+                message=('Your changes will be saved as a new Custom Theme. '+
+                        'Enter a name for your new Custom Theme below.')
+                usedNames=idleConf.GetSectionList('user','highlight')
+                newTheme=GetCfgSectionNameDialog(self,'New Custom Theme',
+                        message,usedNames)
+                if not newTheme.result: #user cancelled custom theme creation
+                    return
+                else: #create new custom theme based on previously active theme 
+                    self.CreateNewTheme(newTheme.result)    
             self.colour.set(colourString)
             self.frameColourSet.config(bg=colourString)#set sample
             if self.fgHilite.get(): plane='foreground'
@@ -522,6 +587,27 @@ class ConfigDialog(Toplevel):
             apply(self.textHighlightSample.tag_config,
                 (self.themeElements[target][0],),{plane:colourString})
     
+    def CreateNewTheme(self,newThemeName):
+        #creates new custom theme based on the previously active theme,
+        #and makes the new theme active
+        if self.themeIsBuiltin.get(): 
+            themeType='default'
+            themeName=self.builtinTheme.get()
+        else:  
+            themeType='user'
+            themeName=self.customTheme.get()
+        newTheme=idleConf.GetThemeDict(themeType,themeName)
+        #add the new theme to changedItems
+        self.changedItems['highlight'][newThemeName]=newTheme    
+        #change gui over to the new theme
+        customThemeList=idleConf.GetSectionList('user','highlight')
+        customThemeList.append(newThemeName)
+        customThemeList.sort()
+        print newThemeName,customThemeList,newTheme
+        self.optMenuThemeCustom.SetMenu(customThemeList,newThemeName)
+        self.themeIsBuiltin.set(0)
+        self.SetThemeType()
+    
     def OnListFontButtonRelease(self,event):
         self.fontName.set(self.listFontName.get(ANCHOR))
         self.SetFontSample()
@@ -620,8 +706,10 @@ class ConfigDialog(Toplevel):
         ##load available theme option menus
         if self.themeIsBuiltin.get(): #default theme selected
             itemList=idleConf.GetSectionList('default','highlight')
+            itemList.sort()
             self.optMenuThemeBuiltin.SetMenu(itemList,currentOption)
             itemList=idleConf.GetSectionList('user','highlight')
+            itemList.sort()
             if not itemList:
                 self.radioThemeCustom.config(state=DISABLED)
                 self.customTheme.set('- no custom themes -')    
@@ -629,8 +717,10 @@ class ConfigDialog(Toplevel):
                 self.optMenuThemeCustom.SetMenu(itemList,itemList[0])
         else: #user theme selected
             itemList=idleConf.GetSectionList('user','highlight')
+            itemList.sort()
             self.optMenuThemeCustom.SetMenu(itemList,currentOption)
             itemList=idleConf.GetSectionList('default','highlight')
+            itemList.sort()
             self.optMenuThemeBuiltin.SetMenu(itemList,itemList[0])
         self.SetThemeType()
         ##load theme element option menu
@@ -654,8 +744,10 @@ class ConfigDialog(Toplevel):
         ##load available keyset option menus
         if self.keysAreDefault.get(): #default theme selected
             itemList=idleConf.GetSectionList('default','keys')
+            itemList.sort()
             self.optMenuKeysBuiltin.SetMenu(itemList,currentOption)
             itemList=idleConf.GetSectionList('user','keys')
+            itemList.sort()
             if not itemList:
                 self.radioKeysCustom.config(state=DISABLED)    
                 self.customKeys.set('- no custom keys -')    
@@ -663,8 +755,10 @@ class ConfigDialog(Toplevel):
                 self.optMenuKeysCustom.SetMenu(itemList,itemList[0])
         else: #user theme selected
             itemList=idleConf.GetSectionList('user','keys')
+            itemList.sort()
             self.optMenuKeysCustom.SetMenu(itemList,currentOption)
             itemList=idleConf.GetSectionList('default','keys')
+            itemList.sort()
             self.optMenuKeysBuiltin.SetMenu(itemList,itemList[0])
         self.SetKeysType()   
         ##load keyset element list
@@ -676,25 +770,6 @@ class ConfigDialog(Toplevel):
             bindName=bindName[2:-2] #trim off the angle brackets
             self.listBindings.insert(END, bindName+' - '+key)
    
-    def GetNewKeys(self):
-        listIndex=self.listBindings.index(ANCHOR)
-        binding=self.listBindings.get(listIndex)
-        bindName=binding.split()[0] #first part, up to first space
-        currentKeySequences=idleConf.GetCurrentKeySet().values()
-        newKeys=GetKeysDialog(self,'Get New Keys',bindName,currentKeySequences)
-        if newKeys.result: #new keys were specified
-            self.listBindings.delete(listIndex)
-            self.listBindings.insert(listIndex,bindName+' - '+newKeys.result)
-            self.listBindings.select_set(listIndex)
-            self.listBindings.select_anchor(listIndex)
-            self.keyBinding.set(newKeys.result)
-        else:
-            self.listBindings.select_set(listIndex)
-            self.listBindings.select_anchor(listIndex)
-
-    def KeyBindingSelected(self,event):
-        self.buttonNewKeys.config(state=NORMAL)
-
     def LoadGeneralCfg(self):
         #startup state
         self.startupEdit.set(idleConf.GetOption('main','General',
diff --git a/Lib/idlelib/configHandler.py b/Lib/idlelib/configHandler.py
index 196d952..d497eaa 100644
--- a/Lib/idlelib/configHandler.py
+++ b/Lib/idlelib/configHandler.py
@@ -23,7 +23,7 @@ class IdleConfParser(ConfigParser):
         self.file=cfgFile
         ConfigParser.__init__(self,defaults=cfgDefaults)
     
-    def Get(self, section, option, type=None):
+    def Get(self, section, option, type=None, default=None):
         """
         Get an option value for given section/option or return default.
         If type is specified, return as type.
@@ -35,8 +35,10 @@ class IdleConfParser(ConfigParser):
         else: 
             getVal=self.get
         if self.has_option(section,option):
-            #return getVal(section, option, raw, vars)
+            #return getVal(section, option, raw, vars, default)
             return getVal(section, option)
+        else:
+            return default
 
     def GetOptionList(self,section):
         """
@@ -188,21 +190,63 @@ class IdleConf:
             else:    
                 raise 'Invalid fgBg specified'
             
-
-    def GetTheme(self, name=None):
-        """
-        Gets the requested theme or returns a final fallback theme in case 
-        one can't be obtained from either the user or default config files.
-        """
-        pass
-    
+    def GetThemeDict(self,type,themeName):
+        """
+        type - string, 'default' or 'user' theme type
+        themeName - string, theme name
+        Returns a dictionary which holds {option:value} for each element
+        in the specified theme. Values are loaded over a set of ultimate last
+        fallback defaults to guarantee that all theme elements are present in 
+        a newly created theme.
+        """
+        if type == 'user':
+            cfgParser=self.userCfg['highlight']
+        elif type == 'default':
+            cfgParser=self.defaultCfg['highlight']
+        else:
+            raise 'Invalid theme type specified'
+        #foreground and background values are provded for each theme element
+        #(apart from cursor) even though all these values are not yet used
+        #by idle, to allow for their use in the future. Default values are
+        #generally black and white.
+        theme={ 'normal-foreground':'#000000', 
+                'normal-background':'#ffffff', 
+                'keyword-foreground':'#000000', 
+                'keyword-background':'#ffffff', 
+                'comment-foreground':'#000000', 
+                'comment-background':'#ffffff', 
+                'string-foreground':'#000000',
+                'string-background':'#ffffff',
+                'definition-foreground':'#000000', 
+                'definition-background':'#ffffff',
+                'hilite-foreground':'#000000',
+                'hilite-background':'gray',
+                'break-foreground':'#ffffff',
+                'break-background':'#000000',
+                'hit-foreground':'#ffffff',
+                'hit-background':'#000000',
+                'error-foreground':'#ffffff',
+                'error-background':'#000000', 
+                #cursor (only foreground can be set) 
+                'cursor-foreground':'#000000', 
+                #shell window
+                'stdout-foreground':'#000000',
+                'stdout-background':'#ffffff',
+                'stderr-foreground':'#000000',
+                'stderr-background':'#ffffff',
+                'console-foreground':'#000000',
+                'console-background':'#ffffff' }
+        for element in theme.keys():
+            colour=cfgParser.Get(type,themeName,element,default=theme[element])        
+            theme[element]=colour
+        return theme
+        
     def CurrentTheme(self):
         """
         Returns the name of the currently active theme        
         """
         return self.GetOption('main','Theme','name',default='')
         
-
     def CurrentKeys(self):
         """
         Returns the name of the currently active theme        
@@ -299,8 +343,6 @@ class IdleConf:
         
         return extBinds 
         
-    
-    
     def GetKeyBinding(self, keySetName, eventStr):
         """
         returns the keybinding for a specific event.
@@ -313,32 +355,35 @@ class IdleConf:
         return binding
 
     def GetCurrentKeySet(self):
+        return self.GetKeySet(self.CurrentKeys())
+    
+    def GetKeySet(self,keySetName):
         """
-        Returns a dictionary of: all current core keybindings, plus the 
+        Returns a dictionary of: all requested core keybindings, plus the 
         keybindings for all currently active extensions. If a binding defined
         in an extension is already in use, that binding is disabled.
         """
-        currentKeySet=self.GetCoreKeys(keySetName=self.CurrentKeys())
+        keySet=self.GetCoreKeys(keySetName)
         activeExtns=self.GetExtensions(activeOnly=1)
         for extn in activeExtns:
             extKeys=self.__GetRawExtensionKeys(extn)
             if extKeys: #the extension defines keybindings
                 for event in extKeys.keys():
-                    if extKeys[event] in currentKeySet.values():
+                    if extKeys[event] in keySet.values():
                         #the binding is already in use
                         extKeys[event]='' #disable this binding
-                    currentKeySet[event]=extKeys[event] #add binding
-        return currentKeySet
-    
+                    keySet[event]=extKeys[event] #add binding
+        return keySet
+
     def GetCoreKeys(self, keySetName=None):
         """
         returns the requested set of core keybindings, with fallbacks if
         required.
+        Keybindings loaded from the config file(s) are loaded _over_ these
+        defaults, so if there is a problem getting any core binding there will
+        be an 'ultimate last resort fallback' to the CUA-ish bindings
+        defined here.
         """
-        #keybindings loaded from the config file(s) are loaded _over_ these
-        #defaults, so if there is a problem getting any core binding there will
-        #be an 'ultimate last resort fallback' to the CUA-ish bindings
-        #defined here.
         keyBindings={
             '<<Copy>>': ['<Control-c>', '<Control-C>'],
             '<<Cut>>': ['<Control-x>', '<Control-X>'],
diff --git a/Lib/idlelib/keybindingDialog.py b/Lib/idlelib/keybindingDialog.py
index c510257..d226a99 100644
--- a/Lib/idlelib/keybindingDialog.py
+++ b/Lib/idlelib/keybindingDialog.py
@@ -264,8 +264,6 @@ if __name__ == '__main__':
     #test the dialog
     root=Tk()
     def run():
-        #import aboutDialog
-        #aboutDialog.AboutDialog(root,'About')
         keySeq=''
         dlg=GetKeysDialog(root,'Get Keys','find-again',[])
         print dlg.result
-- 
cgit v0.12

