symbian-qemu-0.9.1-12/python-2.6.1/Lib/idlelib/configDialog.py
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 """IDLE Configuration Dialog: support user customization of IDLE by GUI
       
     2 
       
     3 Customize font faces, sizes, and colorization attributes.  Set indentation
       
     4 defaults.  Customize keybindings.  Colorization and keybindings can be
       
     5 saved as user defined sets.  Select startup options including shell/editor
       
     6 and default window size.  Define additional help sources.
       
     7 
       
     8 Note that tab width in IDLE is currently fixed at eight due to Tk issues.
       
     9 Refer to comments in EditorWindow autoindent code for details.
       
    10 
       
    11 """
       
    12 from Tkinter import *
       
    13 import tkMessageBox, tkColorChooser, tkFont
       
    14 import string
       
    15 
       
    16 from configHandler import idleConf
       
    17 from dynOptionMenuWidget import DynOptionMenu
       
    18 from tabbedpages import TabbedPageSet
       
    19 from keybindingDialog import GetKeysDialog
       
    20 from configSectionNameDialog import GetCfgSectionNameDialog
       
    21 from configHelpSourceEdit import GetHelpSourceDialog
       
    22 
       
    23 class ConfigDialog(Toplevel):
       
    24 
       
    25     def __init__(self,parent,title):
       
    26         Toplevel.__init__(self, parent)
       
    27         self.wm_withdraw()
       
    28 
       
    29         self.configure(borderwidth=5)
       
    30         self.geometry("+%d+%d" % (parent.winfo_rootx()+20,
       
    31                 parent.winfo_rooty()+30))
       
    32         #Theme Elements. Each theme element key is its display name.
       
    33         #The first value of the tuple is the sample area tag name.
       
    34         #The second value is the display name list sort index.
       
    35         self.themeElements={'Normal Text':('normal','00'),
       
    36             'Python Keywords':('keyword','01'),
       
    37             'Python Definitions':('definition','02'),
       
    38             'Python Builtins':('builtin', '03'),
       
    39             'Python Comments':('comment','04'),
       
    40             'Python Strings':('string','05'),
       
    41             'Selected Text':('hilite','06'),
       
    42             'Found Text':('hit','07'),
       
    43             'Cursor':('cursor','08'),
       
    44             'Error Text':('error','09'),
       
    45             'Shell Normal Text':('console','10'),
       
    46             'Shell Stdout Text':('stdout','11'),
       
    47             'Shell Stderr Text':('stderr','12'),
       
    48             }
       
    49         self.ResetChangedItems() #load initial values in changed items dict
       
    50         self.CreateWidgets()
       
    51         self.resizable(height=FALSE,width=FALSE)
       
    52         self.transient(parent)
       
    53         self.grab_set()
       
    54         self.protocol("WM_DELETE_WINDOW", self.Cancel)
       
    55         self.parent = parent
       
    56         self.tabPages.focus_set()
       
    57         #key bindings for this dialog
       
    58         #self.bind('<Escape>',self.Cancel) #dismiss dialog, no save
       
    59         #self.bind('<Alt-a>',self.Apply) #apply changes, save
       
    60         #self.bind('<F1>',self.Help) #context help
       
    61         self.LoadConfigs()
       
    62         self.AttachVarCallbacks() #avoid callbacks during LoadConfigs
       
    63 
       
    64         self.wm_deiconify()
       
    65         self.wait_window()
       
    66 
       
    67     def CreateWidgets(self):
       
    68         self.tabPages = TabbedPageSet(self,
       
    69                 page_names=['Fonts/Tabs','Highlighting','Keys','General'])
       
    70         frameActionButtons = Frame(self,pady=2)
       
    71         #action buttons
       
    72         self.buttonHelp = Button(frameActionButtons,text='Help',
       
    73                 command=self.Help,takefocus=FALSE,
       
    74                 padx=6,pady=3)
       
    75         self.buttonOk = Button(frameActionButtons,text='Ok',
       
    76                 command=self.Ok,takefocus=FALSE,
       
    77                 padx=6,pady=3)
       
    78         self.buttonApply = Button(frameActionButtons,text='Apply',
       
    79                 command=self.Apply,takefocus=FALSE,
       
    80                 padx=6,pady=3)
       
    81         self.buttonCancel = Button(frameActionButtons,text='Cancel',
       
    82                 command=self.Cancel,takefocus=FALSE,
       
    83                 padx=6,pady=3)
       
    84         self.CreatePageFontTab()
       
    85         self.CreatePageHighlight()
       
    86         self.CreatePageKeys()
       
    87         self.CreatePageGeneral()
       
    88         self.buttonHelp.pack(side=RIGHT,padx=5)
       
    89         self.buttonOk.pack(side=LEFT,padx=5)
       
    90         self.buttonApply.pack(side=LEFT,padx=5)
       
    91         self.buttonCancel.pack(side=LEFT,padx=5)
       
    92         frameActionButtons.pack(side=BOTTOM)
       
    93         Frame(self, height=2, borderwidth=0).pack(side=BOTTOM)
       
    94         self.tabPages.pack(side=TOP,expand=TRUE,fill=BOTH)
       
    95 
       
    96     def CreatePageFontTab(self):
       
    97         #tkVars
       
    98         self.fontSize=StringVar(self)
       
    99         self.fontBold=BooleanVar(self)
       
   100         self.fontName=StringVar(self)
       
   101         self.spaceNum=IntVar(self)
       
   102         self.editFont=tkFont.Font(self,('courier',10,'normal'))
       
   103         ##widget creation
       
   104         #body frame
       
   105         frame=self.tabPages.pages['Fonts/Tabs'].frame
       
   106         #body section frames
       
   107         frameFont=LabelFrame(frame,borderwidth=2,relief=GROOVE,
       
   108                              text=' Base Editor Font ')
       
   109         frameIndent=LabelFrame(frame,borderwidth=2,relief=GROOVE,
       
   110                                text=' Indentation Width ')
       
   111         #frameFont
       
   112         frameFontName=Frame(frameFont)
       
   113         frameFontParam=Frame(frameFont)
       
   114         labelFontNameTitle=Label(frameFontName,justify=LEFT,
       
   115                 text='Font Face :')
       
   116         self.listFontName=Listbox(frameFontName,height=5,takefocus=FALSE,
       
   117                 exportselection=FALSE)
       
   118         self.listFontName.bind('<ButtonRelease-1>',self.OnListFontButtonRelease)
       
   119         scrollFont=Scrollbar(frameFontName)
       
   120         scrollFont.config(command=self.listFontName.yview)
       
   121         self.listFontName.config(yscrollcommand=scrollFont.set)
       
   122         labelFontSizeTitle=Label(frameFontParam,text='Size :')
       
   123         self.optMenuFontSize=DynOptionMenu(frameFontParam,self.fontSize,None,
       
   124             command=self.SetFontSample)
       
   125         checkFontBold=Checkbutton(frameFontParam,variable=self.fontBold,
       
   126             onvalue=1,offvalue=0,text='Bold',command=self.SetFontSample)
       
   127         frameFontSample=Frame(frameFont,relief=SOLID,borderwidth=1)
       
   128         self.labelFontSample=Label(frameFontSample,
       
   129                 text='AaBbCcDdEe\nFfGgHhIiJjK\n1234567890\n#:+=(){}[]',
       
   130                 justify=LEFT,font=self.editFont)
       
   131         #frameIndent
       
   132         frameIndentSize=Frame(frameIndent)
       
   133         labelSpaceNumTitle=Label(frameIndentSize, justify=LEFT,
       
   134                                  text='Python Standard: 4 Spaces!')
       
   135         self.scaleSpaceNum=Scale(frameIndentSize, variable=self.spaceNum,
       
   136                                  orient='horizontal',
       
   137                                  tickinterval=2, from_=2, to=16)
       
   138         #widget packing
       
   139         #body
       
   140         frameFont.pack(side=LEFT,padx=5,pady=5,expand=TRUE,fill=BOTH)
       
   141         frameIndent.pack(side=LEFT,padx=5,pady=5,fill=Y)
       
   142         #frameFont
       
   143         frameFontName.pack(side=TOP,padx=5,pady=5,fill=X)
       
   144         frameFontParam.pack(side=TOP,padx=5,pady=5,fill=X)
       
   145         labelFontNameTitle.pack(side=TOP,anchor=W)
       
   146         self.listFontName.pack(side=LEFT,expand=TRUE,fill=X)
       
   147         scrollFont.pack(side=LEFT,fill=Y)
       
   148         labelFontSizeTitle.pack(side=LEFT,anchor=W)
       
   149         self.optMenuFontSize.pack(side=LEFT,anchor=W)
       
   150         checkFontBold.pack(side=LEFT,anchor=W,padx=20)
       
   151         frameFontSample.pack(side=TOP,padx=5,pady=5,expand=TRUE,fill=BOTH)
       
   152         self.labelFontSample.pack(expand=TRUE,fill=BOTH)
       
   153         #frameIndent
       
   154         frameIndentSize.pack(side=TOP,fill=X)
       
   155         labelSpaceNumTitle.pack(side=TOP,anchor=W,padx=5)
       
   156         self.scaleSpaceNum.pack(side=TOP,padx=5,fill=X)
       
   157         return frame
       
   158 
       
   159     def CreatePageHighlight(self):
       
   160         self.builtinTheme=StringVar(self)
       
   161         self.customTheme=StringVar(self)
       
   162         self.fgHilite=BooleanVar(self)
       
   163         self.colour=StringVar(self)
       
   164         self.fontName=StringVar(self)
       
   165         self.themeIsBuiltin=BooleanVar(self)
       
   166         self.highlightTarget=StringVar(self)
       
   167         ##widget creation
       
   168         #body frame
       
   169         frame=self.tabPages.pages['Highlighting'].frame
       
   170         #body section frames
       
   171         frameCustom=LabelFrame(frame,borderwidth=2,relief=GROOVE,
       
   172                                text=' Custom Highlighting ')
       
   173         frameTheme=LabelFrame(frame,borderwidth=2,relief=GROOVE,
       
   174                               text=' Highlighting Theme ')
       
   175         #frameCustom
       
   176         self.textHighlightSample=Text(frameCustom,relief=SOLID,borderwidth=1,
       
   177             font=('courier',12,''),cursor='hand2',width=21,height=10,
       
   178             takefocus=FALSE,highlightthickness=0,wrap=NONE)
       
   179         text=self.textHighlightSample
       
   180         text.bind('<Double-Button-1>',lambda e: 'break')
       
   181         text.bind('<B1-Motion>',lambda e: 'break')
       
   182         textAndTags=(('#you can click here','comment'),('\n','normal'),
       
   183             ('#to choose items','comment'),('\n','normal'),('def','keyword'),
       
   184             (' ','normal'),('func','definition'),('(param):','normal'),
       
   185             ('\n  ','normal'),('"""string"""','string'),('\n  var0 = ','normal'),
       
   186             ("'string'",'string'),('\n  var1 = ','normal'),("'selected'",'hilite'),
       
   187             ('\n  var2 = ','normal'),("'found'",'hit'),
       
   188             ('\n  var3 = ','normal'),('list', 'builtin'), ('(','normal'),
       
   189             ('None', 'builtin'),(')\n\n','normal'),
       
   190             (' error ','error'),(' ','normal'),('cursor |','cursor'),
       
   191             ('\n ','normal'),('shell','console'),(' ','normal'),('stdout','stdout'),
       
   192             (' ','normal'),('stderr','stderr'),('\n','normal'))
       
   193         for txTa in textAndTags:
       
   194             text.insert(END,txTa[0],txTa[1])
       
   195         for element in self.themeElements.keys():
       
   196             text.tag_bind(self.themeElements[element][0],'<ButtonPress-1>',
       
   197                 lambda event,elem=element: event.widget.winfo_toplevel()
       
   198                 .highlightTarget.set(elem))
       
   199         text.config(state=DISABLED)
       
   200         self.frameColourSet=Frame(frameCustom,relief=SOLID,borderwidth=1)
       
   201         frameFgBg=Frame(frameCustom)
       
   202         buttonSetColour=Button(self.frameColourSet,text='Choose Colour for :',
       
   203             command=self.GetColour,highlightthickness=0)
       
   204         self.optMenuHighlightTarget=DynOptionMenu(self.frameColourSet,
       
   205             self.highlightTarget,None,highlightthickness=0)#,command=self.SetHighlightTargetBinding
       
   206         self.radioFg=Radiobutton(frameFgBg,variable=self.fgHilite,
       
   207             value=1,text='Foreground',command=self.SetColourSampleBinding)
       
   208         self.radioBg=Radiobutton(frameFgBg,variable=self.fgHilite,
       
   209             value=0,text='Background',command=self.SetColourSampleBinding)
       
   210         self.fgHilite.set(1)
       
   211         buttonSaveCustomTheme=Button(frameCustom,
       
   212             text='Save as New Custom Theme',command=self.SaveAsNewTheme)
       
   213         #frameTheme
       
   214         labelTypeTitle=Label(frameTheme,text='Select : ')
       
   215         self.radioThemeBuiltin=Radiobutton(frameTheme,variable=self.themeIsBuiltin,
       
   216             value=1,command=self.SetThemeType,text='a Built-in Theme')
       
   217         self.radioThemeCustom=Radiobutton(frameTheme,variable=self.themeIsBuiltin,
       
   218             value=0,command=self.SetThemeType,text='a Custom Theme')
       
   219         self.optMenuThemeBuiltin=DynOptionMenu(frameTheme,
       
   220             self.builtinTheme,None,command=None)
       
   221         self.optMenuThemeCustom=DynOptionMenu(frameTheme,
       
   222             self.customTheme,None,command=None)
       
   223         self.buttonDeleteCustomTheme=Button(frameTheme,text='Delete Custom Theme',
       
   224                 command=self.DeleteCustomTheme)
       
   225         ##widget packing
       
   226         #body
       
   227         frameCustom.pack(side=LEFT,padx=5,pady=5,expand=TRUE,fill=BOTH)
       
   228         frameTheme.pack(side=LEFT,padx=5,pady=5,fill=Y)
       
   229         #frameCustom
       
   230         self.frameColourSet.pack(side=TOP,padx=5,pady=5,expand=TRUE,fill=X)
       
   231         frameFgBg.pack(side=TOP,padx=5,pady=0)
       
   232         self.textHighlightSample.pack(side=TOP,padx=5,pady=5,expand=TRUE,
       
   233             fill=BOTH)
       
   234         buttonSetColour.pack(side=TOP,expand=TRUE,fill=X,padx=8,pady=4)
       
   235         self.optMenuHighlightTarget.pack(side=TOP,expand=TRUE,fill=X,padx=8,pady=3)
       
   236         self.radioFg.pack(side=LEFT,anchor=E)
       
   237         self.radioBg.pack(side=RIGHT,anchor=W)
       
   238         buttonSaveCustomTheme.pack(side=BOTTOM,fill=X,padx=5,pady=5)
       
   239         #frameTheme
       
   240         labelTypeTitle.pack(side=TOP,anchor=W,padx=5,pady=5)
       
   241         self.radioThemeBuiltin.pack(side=TOP,anchor=W,padx=5)
       
   242         self.radioThemeCustom.pack(side=TOP,anchor=W,padx=5,pady=2)
       
   243         self.optMenuThemeBuiltin.pack(side=TOP,fill=X,padx=5,pady=5)
       
   244         self.optMenuThemeCustom.pack(side=TOP,fill=X,anchor=W,padx=5,pady=5)
       
   245         self.buttonDeleteCustomTheme.pack(side=TOP,fill=X,padx=5,pady=5)
       
   246         return frame
       
   247 
       
   248     def CreatePageKeys(self):
       
   249         #tkVars
       
   250         self.bindingTarget=StringVar(self)
       
   251         self.builtinKeys=StringVar(self)
       
   252         self.customKeys=StringVar(self)
       
   253         self.keysAreBuiltin=BooleanVar(self)
       
   254         self.keyBinding=StringVar(self)
       
   255         ##widget creation
       
   256         #body frame
       
   257         frame=self.tabPages.pages['Keys'].frame
       
   258         #body section frames
       
   259         frameCustom=LabelFrame(frame,borderwidth=2,relief=GROOVE,
       
   260                                text=' Custom Key Bindings ')
       
   261         frameKeySets=LabelFrame(frame,borderwidth=2,relief=GROOVE,
       
   262                            text=' Key Set ')
       
   263         #frameCustom
       
   264         frameTarget=Frame(frameCustom)
       
   265         labelTargetTitle=Label(frameTarget,text='Action - Key(s)')
       
   266         scrollTargetY=Scrollbar(frameTarget)
       
   267         scrollTargetX=Scrollbar(frameTarget,orient=HORIZONTAL)
       
   268         self.listBindings=Listbox(frameTarget,takefocus=FALSE,
       
   269                 exportselection=FALSE)
       
   270         self.listBindings.bind('<ButtonRelease-1>',self.KeyBindingSelected)
       
   271         scrollTargetY.config(command=self.listBindings.yview)
       
   272         scrollTargetX.config(command=self.listBindings.xview)
       
   273         self.listBindings.config(yscrollcommand=scrollTargetY.set)
       
   274         self.listBindings.config(xscrollcommand=scrollTargetX.set)
       
   275         self.buttonNewKeys=Button(frameCustom,text='Get New Keys for Selection',
       
   276             command=self.GetNewKeys,state=DISABLED)
       
   277         #frameKeySets
       
   278         frames = [Frame(frameKeySets, padx=2, pady=2, borderwidth=0)
       
   279                   for i in range(2)]
       
   280         self.radioKeysBuiltin=Radiobutton(frames[0],variable=self.keysAreBuiltin,
       
   281             value=1,command=self.SetKeysType,text='Use a Built-in Key Set')
       
   282         self.radioKeysCustom=Radiobutton(frames[0],variable=self.keysAreBuiltin,
       
   283             value=0,command=self.SetKeysType,text='Use a Custom Key Set')
       
   284         self.optMenuKeysBuiltin=DynOptionMenu(frames[0],
       
   285             self.builtinKeys,None,command=None)
       
   286         self.optMenuKeysCustom=DynOptionMenu(frames[0],
       
   287             self.customKeys,None,command=None)
       
   288         self.buttonDeleteCustomKeys=Button(frames[1],text='Delete Custom Key Set',
       
   289                 command=self.DeleteCustomKeys)
       
   290         buttonSaveCustomKeys=Button(frames[1],
       
   291                 text='Save as New Custom Key Set',command=self.SaveAsNewKeySet)
       
   292         ##widget packing
       
   293         #body
       
   294         frameCustom.pack(side=BOTTOM,padx=5,pady=5,expand=TRUE,fill=BOTH)
       
   295         frameKeySets.pack(side=BOTTOM,padx=5,pady=5,fill=BOTH)
       
   296         #frameCustom
       
   297         self.buttonNewKeys.pack(side=BOTTOM,fill=X,padx=5,pady=5)
       
   298         frameTarget.pack(side=LEFT,padx=5,pady=5,expand=TRUE,fill=BOTH)
       
   299         #frame target
       
   300         frameTarget.columnconfigure(0,weight=1)
       
   301         frameTarget.rowconfigure(1,weight=1)
       
   302         labelTargetTitle.grid(row=0,column=0,columnspan=2,sticky=W)
       
   303         self.listBindings.grid(row=1,column=0,sticky=NSEW)
       
   304         scrollTargetY.grid(row=1,column=1,sticky=NS)
       
   305         scrollTargetX.grid(row=2,column=0,sticky=EW)
       
   306         #frameKeySets
       
   307         self.radioKeysBuiltin.grid(row=0, column=0, sticky=W+NS)
       
   308         self.radioKeysCustom.grid(row=1, column=0, sticky=W+NS)
       
   309         self.optMenuKeysBuiltin.grid(row=0, column=1, sticky=NSEW)
       
   310         self.optMenuKeysCustom.grid(row=1, column=1, sticky=NSEW)
       
   311         self.buttonDeleteCustomKeys.pack(side=LEFT,fill=X,expand=True,padx=2)
       
   312         buttonSaveCustomKeys.pack(side=LEFT,fill=X,expand=True,padx=2)
       
   313         frames[0].pack(side=TOP, fill=BOTH, expand=True)
       
   314         frames[1].pack(side=TOP, fill=X, expand=True, pady=2)
       
   315         return frame
       
   316 
       
   317     def CreatePageGeneral(self):
       
   318         #tkVars
       
   319         self.winWidth=StringVar(self)
       
   320         self.winHeight=StringVar(self)
       
   321         self.paraWidth=StringVar(self)
       
   322         self.startupEdit=IntVar(self)
       
   323         self.autoSave=IntVar(self)
       
   324         self.encoding=StringVar(self)
       
   325         self.userHelpBrowser=BooleanVar(self)
       
   326         self.helpBrowser=StringVar(self)
       
   327         #widget creation
       
   328         #body
       
   329         frame=self.tabPages.pages['General'].frame
       
   330         #body section frames
       
   331         frameRun=LabelFrame(frame,borderwidth=2,relief=GROOVE,
       
   332                             text=' Startup Preferences ')
       
   333         frameSave=LabelFrame(frame,borderwidth=2,relief=GROOVE,
       
   334                              text=' Autosave Preferences ')
       
   335         frameWinSize=Frame(frame,borderwidth=2,relief=GROOVE)
       
   336         frameParaSize=Frame(frame,borderwidth=2,relief=GROOVE)
       
   337         frameEncoding=Frame(frame,borderwidth=2,relief=GROOVE)
       
   338         frameHelp=LabelFrame(frame,borderwidth=2,relief=GROOVE,
       
   339                              text=' Additional Help Sources ')
       
   340         #frameRun
       
   341         labelRunChoiceTitle=Label(frameRun,text='At Startup')
       
   342         radioStartupEdit=Radiobutton(frameRun,variable=self.startupEdit,
       
   343             value=1,command=self.SetKeysType,text="Open Edit Window")
       
   344         radioStartupShell=Radiobutton(frameRun,variable=self.startupEdit,
       
   345             value=0,command=self.SetKeysType,text='Open Shell Window')
       
   346         #frameSave
       
   347         labelRunSaveTitle=Label(frameSave,text='At Start of Run (F5)  ')
       
   348         radioSaveAsk=Radiobutton(frameSave,variable=self.autoSave,
       
   349             value=0,command=self.SetKeysType,text="Prompt to Save")
       
   350         radioSaveAuto=Radiobutton(frameSave,variable=self.autoSave,
       
   351             value=1,command=self.SetKeysType,text='No Prompt')
       
   352         #frameWinSize
       
   353         labelWinSizeTitle=Label(frameWinSize,text='Initial Window Size'+
       
   354                 '  (in characters)')
       
   355         labelWinWidthTitle=Label(frameWinSize,text='Width')
       
   356         entryWinWidth=Entry(frameWinSize,textvariable=self.winWidth,
       
   357                 width=3)
       
   358         labelWinHeightTitle=Label(frameWinSize,text='Height')
       
   359         entryWinHeight=Entry(frameWinSize,textvariable=self.winHeight,
       
   360                 width=3)
       
   361         #paragraphFormatWidth
       
   362         labelParaWidthTitle=Label(frameParaSize,text='Paragraph reformat'+
       
   363                 ' width (in characters)')
       
   364         entryParaWidth=Entry(frameParaSize,textvariable=self.paraWidth,
       
   365                 width=3)
       
   366         #frameEncoding
       
   367         labelEncodingTitle=Label(frameEncoding,text="Default Source Encoding")
       
   368         radioEncLocale=Radiobutton(frameEncoding,variable=self.encoding,
       
   369             value="locale",text="Locale-defined")
       
   370         radioEncUTF8=Radiobutton(frameEncoding,variable=self.encoding,
       
   371             value="utf-8",text="UTF-8")
       
   372         radioEncNone=Radiobutton(frameEncoding,variable=self.encoding,
       
   373             value="none",text="None")
       
   374         #frameHelp
       
   375         frameHelpList=Frame(frameHelp)
       
   376         frameHelpListButtons=Frame(frameHelpList)
       
   377         scrollHelpList=Scrollbar(frameHelpList)
       
   378         self.listHelp=Listbox(frameHelpList,height=5,takefocus=FALSE,
       
   379                 exportselection=FALSE)
       
   380         scrollHelpList.config(command=self.listHelp.yview)
       
   381         self.listHelp.config(yscrollcommand=scrollHelpList.set)
       
   382         self.listHelp.bind('<ButtonRelease-1>',self.HelpSourceSelected)
       
   383         self.buttonHelpListEdit=Button(frameHelpListButtons,text='Edit',
       
   384                 state=DISABLED,width=8,command=self.HelpListItemEdit)
       
   385         self.buttonHelpListAdd=Button(frameHelpListButtons,text='Add',
       
   386                 width=8,command=self.HelpListItemAdd)
       
   387         self.buttonHelpListRemove=Button(frameHelpListButtons,text='Remove',
       
   388                 state=DISABLED,width=8,command=self.HelpListItemRemove)
       
   389         #widget packing
       
   390         #body
       
   391         frameRun.pack(side=TOP,padx=5,pady=5,fill=X)
       
   392         frameSave.pack(side=TOP,padx=5,pady=5,fill=X)
       
   393         frameWinSize.pack(side=TOP,padx=5,pady=5,fill=X)
       
   394         frameParaSize.pack(side=TOP,padx=5,pady=5,fill=X)
       
   395         frameEncoding.pack(side=TOP,padx=5,pady=5,fill=X)
       
   396         frameHelp.pack(side=TOP,padx=5,pady=5,expand=TRUE,fill=BOTH)
       
   397         #frameRun
       
   398         labelRunChoiceTitle.pack(side=LEFT,anchor=W,padx=5,pady=5)
       
   399         radioStartupShell.pack(side=RIGHT,anchor=W,padx=5,pady=5)
       
   400         radioStartupEdit.pack(side=RIGHT,anchor=W,padx=5,pady=5)
       
   401         #frameSave
       
   402         labelRunSaveTitle.pack(side=LEFT,anchor=W,padx=5,pady=5)
       
   403         radioSaveAuto.pack(side=RIGHT,anchor=W,padx=5,pady=5)
       
   404         radioSaveAsk.pack(side=RIGHT,anchor=W,padx=5,pady=5)
       
   405         #frameWinSize
       
   406         labelWinSizeTitle.pack(side=LEFT,anchor=W,padx=5,pady=5)
       
   407         entryWinHeight.pack(side=RIGHT,anchor=E,padx=10,pady=5)
       
   408         labelWinHeightTitle.pack(side=RIGHT,anchor=E,pady=5)
       
   409         entryWinWidth.pack(side=RIGHT,anchor=E,padx=10,pady=5)
       
   410         labelWinWidthTitle.pack(side=RIGHT,anchor=E,pady=5)
       
   411         #paragraphFormatWidth
       
   412         labelParaWidthTitle.pack(side=LEFT,anchor=W,padx=5,pady=5)
       
   413         entryParaWidth.pack(side=RIGHT,anchor=E,padx=10,pady=5)
       
   414         #frameEncoding
       
   415         labelEncodingTitle.pack(side=LEFT,anchor=W,padx=5,pady=5)
       
   416         radioEncNone.pack(side=RIGHT,anchor=E,pady=5)
       
   417         radioEncUTF8.pack(side=RIGHT,anchor=E,pady=5)
       
   418         radioEncLocale.pack(side=RIGHT,anchor=E,pady=5)
       
   419         #frameHelp
       
   420         frameHelpListButtons.pack(side=RIGHT,padx=5,pady=5,fill=Y)
       
   421         frameHelpList.pack(side=TOP,padx=5,pady=5,expand=TRUE,fill=BOTH)
       
   422         scrollHelpList.pack(side=RIGHT,anchor=W,fill=Y)
       
   423         self.listHelp.pack(side=LEFT,anchor=E,expand=TRUE,fill=BOTH)
       
   424         self.buttonHelpListEdit.pack(side=TOP,anchor=W,pady=5)
       
   425         self.buttonHelpListAdd.pack(side=TOP,anchor=W)
       
   426         self.buttonHelpListRemove.pack(side=TOP,anchor=W,pady=5)
       
   427         return frame
       
   428 
       
   429     def AttachVarCallbacks(self):
       
   430         self.fontSize.trace_variable('w',self.VarChanged_fontSize)
       
   431         self.fontName.trace_variable('w',self.VarChanged_fontName)
       
   432         self.fontBold.trace_variable('w',self.VarChanged_fontBold)
       
   433         self.spaceNum.trace_variable('w',self.VarChanged_spaceNum)
       
   434         self.colour.trace_variable('w',self.VarChanged_colour)
       
   435         self.builtinTheme.trace_variable('w',self.VarChanged_builtinTheme)
       
   436         self.customTheme.trace_variable('w',self.VarChanged_customTheme)
       
   437         self.themeIsBuiltin.trace_variable('w',self.VarChanged_themeIsBuiltin)
       
   438         self.highlightTarget.trace_variable('w',self.VarChanged_highlightTarget)
       
   439         self.keyBinding.trace_variable('w',self.VarChanged_keyBinding)
       
   440         self.builtinKeys.trace_variable('w',self.VarChanged_builtinKeys)
       
   441         self.customKeys.trace_variable('w',self.VarChanged_customKeys)
       
   442         self.keysAreBuiltin.trace_variable('w',self.VarChanged_keysAreBuiltin)
       
   443         self.winWidth.trace_variable('w',self.VarChanged_winWidth)
       
   444         self.winHeight.trace_variable('w',self.VarChanged_winHeight)
       
   445         self.paraWidth.trace_variable('w',self.VarChanged_paraWidth)
       
   446         self.startupEdit.trace_variable('w',self.VarChanged_startupEdit)
       
   447         self.autoSave.trace_variable('w',self.VarChanged_autoSave)
       
   448         self.encoding.trace_variable('w',self.VarChanged_encoding)
       
   449 
       
   450     def VarChanged_fontSize(self,*params):
       
   451         value=self.fontSize.get()
       
   452         self.AddChangedItem('main','EditorWindow','font-size',value)
       
   453 
       
   454     def VarChanged_fontName(self,*params):
       
   455         value=self.fontName.get()
       
   456         self.AddChangedItem('main','EditorWindow','font',value)
       
   457 
       
   458     def VarChanged_fontBold(self,*params):
       
   459         value=self.fontBold.get()
       
   460         self.AddChangedItem('main','EditorWindow','font-bold',value)
       
   461 
       
   462     def VarChanged_spaceNum(self,*params):
       
   463         value=self.spaceNum.get()
       
   464         self.AddChangedItem('main','Indent','num-spaces',value)
       
   465 
       
   466     def VarChanged_colour(self,*params):
       
   467         self.OnNewColourSet()
       
   468 
       
   469     def VarChanged_builtinTheme(self,*params):
       
   470         value=self.builtinTheme.get()
       
   471         self.AddChangedItem('main','Theme','name',value)
       
   472         self.PaintThemeSample()
       
   473 
       
   474     def VarChanged_customTheme(self,*params):
       
   475         value=self.customTheme.get()
       
   476         if value != '- no custom themes -':
       
   477             self.AddChangedItem('main','Theme','name',value)
       
   478             self.PaintThemeSample()
       
   479 
       
   480     def VarChanged_themeIsBuiltin(self,*params):
       
   481         value=self.themeIsBuiltin.get()
       
   482         self.AddChangedItem('main','Theme','default',value)
       
   483         if value:
       
   484             self.VarChanged_builtinTheme()
       
   485         else:
       
   486             self.VarChanged_customTheme()
       
   487 
       
   488     def VarChanged_highlightTarget(self,*params):
       
   489         self.SetHighlightTarget()
       
   490 
       
   491     def VarChanged_keyBinding(self,*params):
       
   492         value=self.keyBinding.get()
       
   493         keySet=self.customKeys.get()
       
   494         event=self.listBindings.get(ANCHOR).split()[0]
       
   495         if idleConf.IsCoreBinding(event):
       
   496             #this is a core keybinding
       
   497             self.AddChangedItem('keys',keySet,event,value)
       
   498         else: #this is an extension key binding
       
   499             extName=idleConf.GetExtnNameForEvent(event)
       
   500             extKeybindSection=extName+'_cfgBindings'
       
   501             self.AddChangedItem('extensions',extKeybindSection,event,value)
       
   502 
       
   503     def VarChanged_builtinKeys(self,*params):
       
   504         value=self.builtinKeys.get()
       
   505         self.AddChangedItem('main','Keys','name',value)
       
   506         self.LoadKeysList(value)
       
   507 
       
   508     def VarChanged_customKeys(self,*params):
       
   509         value=self.customKeys.get()
       
   510         if value != '- no custom keys -':
       
   511             self.AddChangedItem('main','Keys','name',value)
       
   512             self.LoadKeysList(value)
       
   513 
       
   514     def VarChanged_keysAreBuiltin(self,*params):
       
   515         value=self.keysAreBuiltin.get()
       
   516         self.AddChangedItem('main','Keys','default',value)
       
   517         if value:
       
   518             self.VarChanged_builtinKeys()
       
   519         else:
       
   520             self.VarChanged_customKeys()
       
   521 
       
   522     def VarChanged_winWidth(self,*params):
       
   523         value=self.winWidth.get()
       
   524         self.AddChangedItem('main','EditorWindow','width',value)
       
   525 
       
   526     def VarChanged_winHeight(self,*params):
       
   527         value=self.winHeight.get()
       
   528         self.AddChangedItem('main','EditorWindow','height',value)
       
   529 
       
   530     def VarChanged_paraWidth(self,*params):
       
   531         value=self.paraWidth.get()
       
   532         self.AddChangedItem('main','FormatParagraph','paragraph',value)
       
   533 
       
   534     def VarChanged_startupEdit(self,*params):
       
   535         value=self.startupEdit.get()
       
   536         self.AddChangedItem('main','General','editor-on-startup',value)
       
   537 
       
   538     def VarChanged_autoSave(self,*params):
       
   539         value=self.autoSave.get()
       
   540         self.AddChangedItem('main','General','autosave',value)
       
   541 
       
   542     def VarChanged_encoding(self,*params):
       
   543         value=self.encoding.get()
       
   544         self.AddChangedItem('main','EditorWindow','encoding',value)
       
   545 
       
   546     def ResetChangedItems(self):
       
   547         #When any config item is changed in this dialog, an entry
       
   548         #should be made in the relevant section (config type) of this
       
   549         #dictionary. The key should be the config file section name and the
       
   550         #value a dictionary, whose key:value pairs are item=value pairs for
       
   551         #that config file section.
       
   552         self.changedItems={'main':{},'highlight':{},'keys':{},'extensions':{}}
       
   553 
       
   554     def AddChangedItem(self,type,section,item,value):
       
   555         value=str(value) #make sure we use a string
       
   556         if not self.changedItems[type].has_key(section):
       
   557             self.changedItems[type][section]={}
       
   558         self.changedItems[type][section][item]=value
       
   559 
       
   560     def GetDefaultItems(self):
       
   561         dItems={'main':{},'highlight':{},'keys':{},'extensions':{}}
       
   562         for configType in dItems.keys():
       
   563             sections=idleConf.GetSectionList('default',configType)
       
   564             for section in sections:
       
   565                 dItems[configType][section]={}
       
   566                 options=idleConf.defaultCfg[configType].GetOptionList(section)
       
   567                 for option in options:
       
   568                     dItems[configType][section][option]=(
       
   569                             idleConf.defaultCfg[configType].Get(section,option))
       
   570         return dItems
       
   571 
       
   572     def SetThemeType(self):
       
   573         if self.themeIsBuiltin.get():
       
   574             self.optMenuThemeBuiltin.config(state=NORMAL)
       
   575             self.optMenuThemeCustom.config(state=DISABLED)
       
   576             self.buttonDeleteCustomTheme.config(state=DISABLED)
       
   577         else:
       
   578             self.optMenuThemeBuiltin.config(state=DISABLED)
       
   579             self.radioThemeCustom.config(state=NORMAL)
       
   580             self.optMenuThemeCustom.config(state=NORMAL)
       
   581             self.buttonDeleteCustomTheme.config(state=NORMAL)
       
   582 
       
   583     def SetKeysType(self):
       
   584         if self.keysAreBuiltin.get():
       
   585             self.optMenuKeysBuiltin.config(state=NORMAL)
       
   586             self.optMenuKeysCustom.config(state=DISABLED)
       
   587             self.buttonDeleteCustomKeys.config(state=DISABLED)
       
   588         else:
       
   589             self.optMenuKeysBuiltin.config(state=DISABLED)
       
   590             self.radioKeysCustom.config(state=NORMAL)
       
   591             self.optMenuKeysCustom.config(state=NORMAL)
       
   592             self.buttonDeleteCustomKeys.config(state=NORMAL)
       
   593 
       
   594     def GetNewKeys(self):
       
   595         listIndex=self.listBindings.index(ANCHOR)
       
   596         binding=self.listBindings.get(listIndex)
       
   597         bindName=binding.split()[0] #first part, up to first space
       
   598         if self.keysAreBuiltin.get():
       
   599             currentKeySetName=self.builtinKeys.get()
       
   600         else:
       
   601             currentKeySetName=self.customKeys.get()
       
   602         currentBindings=idleConf.GetCurrentKeySet()
       
   603         if currentKeySetName in self.changedItems['keys'].keys(): #unsaved changes
       
   604             keySetChanges=self.changedItems['keys'][currentKeySetName]
       
   605             for event in keySetChanges.keys():
       
   606                 currentBindings[event]=keySetChanges[event].split()
       
   607         currentKeySequences=currentBindings.values()
       
   608         newKeys=GetKeysDialog(self,'Get New Keys',bindName,
       
   609                 currentKeySequences).result
       
   610         if newKeys: #new keys were specified
       
   611             if self.keysAreBuiltin.get(): #current key set is a built-in
       
   612                 message=('Your changes will be saved as a new Custom Key Set. '+
       
   613                         'Enter a name for your new Custom Key Set below.')
       
   614                 newKeySet=self.GetNewKeysName(message)
       
   615                 if not newKeySet: #user cancelled custom key set creation
       
   616                     self.listBindings.select_set(listIndex)
       
   617                     self.listBindings.select_anchor(listIndex)
       
   618                     return
       
   619                 else: #create new custom key set based on previously active key set
       
   620                     self.CreateNewKeySet(newKeySet)
       
   621             self.listBindings.delete(listIndex)
       
   622             self.listBindings.insert(listIndex,bindName+' - '+newKeys)
       
   623             self.listBindings.select_set(listIndex)
       
   624             self.listBindings.select_anchor(listIndex)
       
   625             self.keyBinding.set(newKeys)
       
   626         else:
       
   627             self.listBindings.select_set(listIndex)
       
   628             self.listBindings.select_anchor(listIndex)
       
   629 
       
   630     def GetNewKeysName(self,message):
       
   631         usedNames=(idleConf.GetSectionList('user','keys')+
       
   632                 idleConf.GetSectionList('default','keys'))
       
   633         newKeySet=GetCfgSectionNameDialog(self,'New Custom Key Set',
       
   634                 message,usedNames).result
       
   635         return newKeySet
       
   636 
       
   637     def SaveAsNewKeySet(self):
       
   638         newKeysName=self.GetNewKeysName('New Key Set Name:')
       
   639         if newKeysName:
       
   640             self.CreateNewKeySet(newKeysName)
       
   641 
       
   642     def KeyBindingSelected(self,event):
       
   643         self.buttonNewKeys.config(state=NORMAL)
       
   644 
       
   645     def CreateNewKeySet(self,newKeySetName):
       
   646         #creates new custom key set based on the previously active key set,
       
   647         #and makes the new key set active
       
   648         if self.keysAreBuiltin.get():
       
   649             prevKeySetName=self.builtinKeys.get()
       
   650         else:
       
   651             prevKeySetName=self.customKeys.get()
       
   652         prevKeys=idleConf.GetCoreKeys(prevKeySetName)
       
   653         newKeys={}
       
   654         for event in prevKeys.keys(): #add key set to changed items
       
   655             eventName=event[2:-2] #trim off the angle brackets
       
   656             binding=string.join(prevKeys[event])
       
   657             newKeys[eventName]=binding
       
   658         #handle any unsaved changes to prev key set
       
   659         if prevKeySetName in self.changedItems['keys'].keys():
       
   660             keySetChanges=self.changedItems['keys'][prevKeySetName]
       
   661             for event in keySetChanges.keys():
       
   662                 newKeys[event]=keySetChanges[event]
       
   663         #save the new theme
       
   664         self.SaveNewKeySet(newKeySetName,newKeys)
       
   665         #change gui over to the new key set
       
   666         customKeyList=idleConf.GetSectionList('user','keys')
       
   667         customKeyList.sort()
       
   668         self.optMenuKeysCustom.SetMenu(customKeyList,newKeySetName)
       
   669         self.keysAreBuiltin.set(0)
       
   670         self.SetKeysType()
       
   671 
       
   672     def LoadKeysList(self,keySetName):
       
   673         reselect=0
       
   674         newKeySet=0
       
   675         if self.listBindings.curselection():
       
   676             reselect=1
       
   677             listIndex=self.listBindings.index(ANCHOR)
       
   678         keySet=idleConf.GetKeySet(keySetName)
       
   679         bindNames=keySet.keys()
       
   680         bindNames.sort()
       
   681         self.listBindings.delete(0,END)
       
   682         for bindName in bindNames:
       
   683             key=string.join(keySet[bindName]) #make key(s) into a string
       
   684             bindName=bindName[2:-2] #trim off the angle brackets
       
   685             if keySetName in self.changedItems['keys'].keys():
       
   686                 #handle any unsaved changes to this key set
       
   687                 if bindName in self.changedItems['keys'][keySetName].keys():
       
   688                     key=self.changedItems['keys'][keySetName][bindName]
       
   689             self.listBindings.insert(END, bindName+' - '+key)
       
   690         if reselect:
       
   691             self.listBindings.see(listIndex)
       
   692             self.listBindings.select_set(listIndex)
       
   693             self.listBindings.select_anchor(listIndex)
       
   694 
       
   695     def DeleteCustomKeys(self):
       
   696         keySetName=self.customKeys.get()
       
   697         if not tkMessageBox.askyesno('Delete Key Set','Are you sure you wish '+
       
   698                                      'to delete the key set %r ?' % (keySetName),
       
   699                                      parent=self):
       
   700             return
       
   701         #remove key set from config
       
   702         idleConf.userCfg['keys'].remove_section(keySetName)
       
   703         if self.changedItems['keys'].has_key(keySetName):
       
   704             del(self.changedItems['keys'][keySetName])
       
   705         #write changes
       
   706         idleConf.userCfg['keys'].Save()
       
   707         #reload user key set list
       
   708         itemList=idleConf.GetSectionList('user','keys')
       
   709         itemList.sort()
       
   710         if not itemList:
       
   711             self.radioKeysCustom.config(state=DISABLED)
       
   712             self.optMenuKeysCustom.SetMenu(itemList,'- no custom keys -')
       
   713         else:
       
   714             self.optMenuKeysCustom.SetMenu(itemList,itemList[0])
       
   715         #revert to default key set
       
   716         self.keysAreBuiltin.set(idleConf.defaultCfg['main'].Get('Keys','default'))
       
   717         self.builtinKeys.set(idleConf.defaultCfg['main'].Get('Keys','name'))
       
   718         #user can't back out of these changes, they must be applied now
       
   719         self.Apply()
       
   720         self.SetKeysType()
       
   721 
       
   722     def DeleteCustomTheme(self):
       
   723         themeName=self.customTheme.get()
       
   724         if not tkMessageBox.askyesno('Delete Theme','Are you sure you wish '+
       
   725                                      'to delete the theme %r ?' % (themeName,),
       
   726                                      parent=self):
       
   727             return
       
   728         #remove theme from config
       
   729         idleConf.userCfg['highlight'].remove_section(themeName)
       
   730         if self.changedItems['highlight'].has_key(themeName):
       
   731             del(self.changedItems['highlight'][themeName])
       
   732         #write changes
       
   733         idleConf.userCfg['highlight'].Save()
       
   734         #reload user theme list
       
   735         itemList=idleConf.GetSectionList('user','highlight')
       
   736         itemList.sort()
       
   737         if not itemList:
       
   738             self.radioThemeCustom.config(state=DISABLED)
       
   739             self.optMenuThemeCustom.SetMenu(itemList,'- no custom themes -')
       
   740         else:
       
   741             self.optMenuThemeCustom.SetMenu(itemList,itemList[0])
       
   742         #revert to default theme
       
   743         self.themeIsBuiltin.set(idleConf.defaultCfg['main'].Get('Theme','default'))
       
   744         self.builtinTheme.set(idleConf.defaultCfg['main'].Get('Theme','name'))
       
   745         #user can't back out of these changes, they must be applied now
       
   746         self.Apply()
       
   747         self.SetThemeType()
       
   748 
       
   749     def GetColour(self):
       
   750         target=self.highlightTarget.get()
       
   751         prevColour=self.frameColourSet.cget('bg')
       
   752         rgbTuplet, colourString = tkColorChooser.askcolor(parent=self,
       
   753             title='Pick new colour for : '+target,initialcolor=prevColour)
       
   754         if colourString and (colourString!=prevColour):
       
   755             #user didn't cancel, and they chose a new colour
       
   756             if self.themeIsBuiltin.get(): #current theme is a built-in
       
   757                 message=('Your changes will be saved as a new Custom Theme. '+
       
   758                         'Enter a name for your new Custom Theme below.')
       
   759                 newTheme=self.GetNewThemeName(message)
       
   760                 if not newTheme: #user cancelled custom theme creation
       
   761                     return
       
   762                 else: #create new custom theme based on previously active theme
       
   763                     self.CreateNewTheme(newTheme)
       
   764                     self.colour.set(colourString)
       
   765             else: #current theme is user defined
       
   766                 self.colour.set(colourString)
       
   767 
       
   768     def OnNewColourSet(self):
       
   769         newColour=self.colour.get()
       
   770         self.frameColourSet.config(bg=newColour)#set sample
       
   771         if self.fgHilite.get(): plane='foreground'
       
   772         else: plane='background'
       
   773         sampleElement=self.themeElements[self.highlightTarget.get()][0]
       
   774         self.textHighlightSample.tag_config(sampleElement, **{plane:newColour})
       
   775         theme=self.customTheme.get()
       
   776         themeElement=sampleElement+'-'+plane
       
   777         self.AddChangedItem('highlight',theme,themeElement,newColour)
       
   778 
       
   779     def GetNewThemeName(self,message):
       
   780         usedNames=(idleConf.GetSectionList('user','highlight')+
       
   781                 idleConf.GetSectionList('default','highlight'))
       
   782         newTheme=GetCfgSectionNameDialog(self,'New Custom Theme',
       
   783                 message,usedNames).result
       
   784         return newTheme
       
   785 
       
   786     def SaveAsNewTheme(self):
       
   787         newThemeName=self.GetNewThemeName('New Theme Name:')
       
   788         if newThemeName:
       
   789             self.CreateNewTheme(newThemeName)
       
   790 
       
   791     def CreateNewTheme(self,newThemeName):
       
   792         #creates new custom theme based on the previously active theme,
       
   793         #and makes the new theme active
       
   794         if self.themeIsBuiltin.get():
       
   795             themeType='default'
       
   796             themeName=self.builtinTheme.get()
       
   797         else:
       
   798             themeType='user'
       
   799             themeName=self.customTheme.get()
       
   800         newTheme=idleConf.GetThemeDict(themeType,themeName)
       
   801         #apply any of the old theme's unsaved changes to the new theme
       
   802         if themeName in self.changedItems['highlight'].keys():
       
   803             themeChanges=self.changedItems['highlight'][themeName]
       
   804             for element in themeChanges.keys():
       
   805                 newTheme[element]=themeChanges[element]
       
   806         #save the new theme
       
   807         self.SaveNewTheme(newThemeName,newTheme)
       
   808         #change gui over to the new theme
       
   809         customThemeList=idleConf.GetSectionList('user','highlight')
       
   810         customThemeList.sort()
       
   811         self.optMenuThemeCustom.SetMenu(customThemeList,newThemeName)
       
   812         self.themeIsBuiltin.set(0)
       
   813         self.SetThemeType()
       
   814 
       
   815     def OnListFontButtonRelease(self,event):
       
   816         font = self.listFontName.get(ANCHOR)
       
   817         self.fontName.set(font.lower())
       
   818         self.SetFontSample()
       
   819 
       
   820     def SetFontSample(self,event=None):
       
   821         fontName=self.fontName.get()
       
   822         if self.fontBold.get():
       
   823             fontWeight=tkFont.BOLD
       
   824         else:
       
   825             fontWeight=tkFont.NORMAL
       
   826         self.editFont.config(size=self.fontSize.get(),
       
   827                 weight=fontWeight,family=fontName)
       
   828 
       
   829     def SetHighlightTarget(self):
       
   830         if self.highlightTarget.get()=='Cursor': #bg not possible
       
   831             self.radioFg.config(state=DISABLED)
       
   832             self.radioBg.config(state=DISABLED)
       
   833             self.fgHilite.set(1)
       
   834         else: #both fg and bg can be set
       
   835             self.radioFg.config(state=NORMAL)
       
   836             self.radioBg.config(state=NORMAL)
       
   837             self.fgHilite.set(1)
       
   838         self.SetColourSample()
       
   839 
       
   840     def SetColourSampleBinding(self,*args):
       
   841         self.SetColourSample()
       
   842 
       
   843     def SetColourSample(self):
       
   844         #set the colour smaple area
       
   845         tag=self.themeElements[self.highlightTarget.get()][0]
       
   846         if self.fgHilite.get(): plane='foreground'
       
   847         else: plane='background'
       
   848         colour=self.textHighlightSample.tag_cget(tag,plane)
       
   849         self.frameColourSet.config(bg=colour)
       
   850 
       
   851     def PaintThemeSample(self):
       
   852         if self.themeIsBuiltin.get(): #a default theme
       
   853             theme=self.builtinTheme.get()
       
   854         else: #a user theme
       
   855             theme=self.customTheme.get()
       
   856         for elementTitle in self.themeElements.keys():
       
   857             element=self.themeElements[elementTitle][0]
       
   858             colours=idleConf.GetHighlight(theme,element)
       
   859             if element=='cursor': #cursor sample needs special painting
       
   860                 colours['background']=idleConf.GetHighlight(theme,
       
   861                         'normal', fgBg='bg')
       
   862             #handle any unsaved changes to this theme
       
   863             if theme in self.changedItems['highlight'].keys():
       
   864                 themeDict=self.changedItems['highlight'][theme]
       
   865                 if themeDict.has_key(element+'-foreground'):
       
   866                     colours['foreground']=themeDict[element+'-foreground']
       
   867                 if themeDict.has_key(element+'-background'):
       
   868                     colours['background']=themeDict[element+'-background']
       
   869             self.textHighlightSample.tag_config(element, **colours)
       
   870         self.SetColourSample()
       
   871 
       
   872     def HelpSourceSelected(self,event):
       
   873         self.SetHelpListButtonStates()
       
   874 
       
   875     def SetHelpListButtonStates(self):
       
   876         if self.listHelp.size()<1: #no entries in list
       
   877             self.buttonHelpListEdit.config(state=DISABLED)
       
   878             self.buttonHelpListRemove.config(state=DISABLED)
       
   879         else: #there are some entries
       
   880             if self.listHelp.curselection(): #there currently is a selection
       
   881                 self.buttonHelpListEdit.config(state=NORMAL)
       
   882                 self.buttonHelpListRemove.config(state=NORMAL)
       
   883             else:  #there currently is not a selection
       
   884                 self.buttonHelpListEdit.config(state=DISABLED)
       
   885                 self.buttonHelpListRemove.config(state=DISABLED)
       
   886 
       
   887     def HelpListItemAdd(self):
       
   888         helpSource=GetHelpSourceDialog(self,'New Help Source').result
       
   889         if helpSource:
       
   890             self.userHelpList.append( (helpSource[0],helpSource[1]) )
       
   891             self.listHelp.insert(END,helpSource[0])
       
   892             self.UpdateUserHelpChangedItems()
       
   893         self.SetHelpListButtonStates()
       
   894 
       
   895     def HelpListItemEdit(self):
       
   896         itemIndex=self.listHelp.index(ANCHOR)
       
   897         helpSource=self.userHelpList[itemIndex]
       
   898         newHelpSource=GetHelpSourceDialog(self,'Edit Help Source',
       
   899                 menuItem=helpSource[0],filePath=helpSource[1]).result
       
   900         if (not newHelpSource) or (newHelpSource==helpSource):
       
   901             return #no changes
       
   902         self.userHelpList[itemIndex]=newHelpSource
       
   903         self.listHelp.delete(itemIndex)
       
   904         self.listHelp.insert(itemIndex,newHelpSource[0])
       
   905         self.UpdateUserHelpChangedItems()
       
   906         self.SetHelpListButtonStates()
       
   907 
       
   908     def HelpListItemRemove(self):
       
   909         itemIndex=self.listHelp.index(ANCHOR)
       
   910         del(self.userHelpList[itemIndex])
       
   911         self.listHelp.delete(itemIndex)
       
   912         self.UpdateUserHelpChangedItems()
       
   913         self.SetHelpListButtonStates()
       
   914 
       
   915     def UpdateUserHelpChangedItems(self):
       
   916         "Clear and rebuild the HelpFiles section in self.changedItems"
       
   917         self.changedItems['main']['HelpFiles'] = {}
       
   918         for num in range(1,len(self.userHelpList)+1):
       
   919             self.AddChangedItem('main','HelpFiles',str(num),
       
   920                     string.join(self.userHelpList[num-1][:2],';'))
       
   921 
       
   922     def LoadFontCfg(self):
       
   923         ##base editor font selection list
       
   924         fonts=list(tkFont.families(self))
       
   925         fonts.sort()
       
   926         for font in fonts:
       
   927             self.listFontName.insert(END,font)
       
   928         configuredFont=idleConf.GetOption('main','EditorWindow','font',
       
   929                 default='courier')
       
   930         lc_configuredFont = configuredFont.lower()
       
   931         self.fontName.set(lc_configuredFont)
       
   932         lc_fonts = [s.lower() for s in fonts]
       
   933         if lc_configuredFont in lc_fonts:
       
   934             currentFontIndex = lc_fonts.index(lc_configuredFont)
       
   935             self.listFontName.see(currentFontIndex)
       
   936             self.listFontName.select_set(currentFontIndex)
       
   937             self.listFontName.select_anchor(currentFontIndex)
       
   938         ##font size dropdown
       
   939         fontSize=idleConf.GetOption('main','EditorWindow','font-size',
       
   940                 default='10')
       
   941         self.optMenuFontSize.SetMenu(('7','8','9','10','11','12','13','14',
       
   942                 '16','18','20','22'),fontSize )
       
   943         ##fontWeight
       
   944         self.fontBold.set(idleConf.GetOption('main','EditorWindow',
       
   945                 'font-bold',default=0,type='bool'))
       
   946         ##font sample
       
   947         self.SetFontSample()
       
   948 
       
   949     def LoadTabCfg(self):
       
   950         ##indent sizes
       
   951         spaceNum=idleConf.GetOption('main','Indent','num-spaces',
       
   952                 default=4,type='int')
       
   953         self.spaceNum.set(spaceNum)
       
   954 
       
   955     def LoadThemeCfg(self):
       
   956         ##current theme type radiobutton
       
   957         self.themeIsBuiltin.set(idleConf.GetOption('main','Theme','default',
       
   958             type='bool',default=1))
       
   959         ##currently set theme
       
   960         currentOption=idleConf.CurrentTheme()
       
   961         ##load available theme option menus
       
   962         if self.themeIsBuiltin.get(): #default theme selected
       
   963             itemList=idleConf.GetSectionList('default','highlight')
       
   964             itemList.sort()
       
   965             self.optMenuThemeBuiltin.SetMenu(itemList,currentOption)
       
   966             itemList=idleConf.GetSectionList('user','highlight')
       
   967             itemList.sort()
       
   968             if not itemList:
       
   969                 self.radioThemeCustom.config(state=DISABLED)
       
   970                 self.customTheme.set('- no custom themes -')
       
   971             else:
       
   972                 self.optMenuThemeCustom.SetMenu(itemList,itemList[0])
       
   973         else: #user theme selected
       
   974             itemList=idleConf.GetSectionList('user','highlight')
       
   975             itemList.sort()
       
   976             self.optMenuThemeCustom.SetMenu(itemList,currentOption)
       
   977             itemList=idleConf.GetSectionList('default','highlight')
       
   978             itemList.sort()
       
   979             self.optMenuThemeBuiltin.SetMenu(itemList,itemList[0])
       
   980         self.SetThemeType()
       
   981         ##load theme element option menu
       
   982         themeNames=self.themeElements.keys()
       
   983         themeNames.sort(self.__ThemeNameIndexCompare)
       
   984         self.optMenuHighlightTarget.SetMenu(themeNames,themeNames[0])
       
   985         self.PaintThemeSample()
       
   986         self.SetHighlightTarget()
       
   987 
       
   988     def __ThemeNameIndexCompare(self,a,b):
       
   989         if self.themeElements[a][1]<self.themeElements[b][1]: return -1
       
   990         elif self.themeElements[a][1]==self.themeElements[b][1]: return 0
       
   991         else: return 1
       
   992 
       
   993     def LoadKeyCfg(self):
       
   994         ##current keys type radiobutton
       
   995         self.keysAreBuiltin.set(idleConf.GetOption('main','Keys','default',
       
   996             type='bool',default=1))
       
   997         ##currently set keys
       
   998         currentOption=idleConf.CurrentKeys()
       
   999         ##load available keyset option menus
       
  1000         if self.keysAreBuiltin.get(): #default theme selected
       
  1001             itemList=idleConf.GetSectionList('default','keys')
       
  1002             itemList.sort()
       
  1003             self.optMenuKeysBuiltin.SetMenu(itemList,currentOption)
       
  1004             itemList=idleConf.GetSectionList('user','keys')
       
  1005             itemList.sort()
       
  1006             if not itemList:
       
  1007                 self.radioKeysCustom.config(state=DISABLED)
       
  1008                 self.customKeys.set('- no custom keys -')
       
  1009             else:
       
  1010                 self.optMenuKeysCustom.SetMenu(itemList,itemList[0])
       
  1011         else: #user key set selected
       
  1012             itemList=idleConf.GetSectionList('user','keys')
       
  1013             itemList.sort()
       
  1014             self.optMenuKeysCustom.SetMenu(itemList,currentOption)
       
  1015             itemList=idleConf.GetSectionList('default','keys')
       
  1016             itemList.sort()
       
  1017             self.optMenuKeysBuiltin.SetMenu(itemList,itemList[0])
       
  1018         self.SetKeysType()
       
  1019         ##load keyset element list
       
  1020         keySetName=idleConf.CurrentKeys()
       
  1021         self.LoadKeysList(keySetName)
       
  1022 
       
  1023     def LoadGeneralCfg(self):
       
  1024         #startup state
       
  1025         self.startupEdit.set(idleConf.GetOption('main','General',
       
  1026                 'editor-on-startup',default=1,type='bool'))
       
  1027         #autosave state
       
  1028         self.autoSave.set(idleConf.GetOption('main', 'General', 'autosave',
       
  1029                                              default=0, type='bool'))
       
  1030         #initial window size
       
  1031         self.winWidth.set(idleConf.GetOption('main','EditorWindow','width'))
       
  1032         self.winHeight.set(idleConf.GetOption('main','EditorWindow','height'))
       
  1033         #initial paragraph reformat size
       
  1034         self.paraWidth.set(idleConf.GetOption('main','FormatParagraph','paragraph'))
       
  1035         # default source encoding
       
  1036         self.encoding.set(idleConf.GetOption('main', 'EditorWindow',
       
  1037                                              'encoding', default='none'))
       
  1038         # additional help sources
       
  1039         self.userHelpList = idleConf.GetAllExtraHelpSourcesList()
       
  1040         for helpItem in self.userHelpList:
       
  1041             self.listHelp.insert(END,helpItem[0])
       
  1042         self.SetHelpListButtonStates()
       
  1043 
       
  1044     def LoadConfigs(self):
       
  1045         """
       
  1046         load configuration from default and user config files and populate
       
  1047         the widgets on the config dialog pages.
       
  1048         """
       
  1049         ### fonts / tabs page
       
  1050         self.LoadFontCfg()
       
  1051         self.LoadTabCfg()
       
  1052         ### highlighting page
       
  1053         self.LoadThemeCfg()
       
  1054         ### keys page
       
  1055         self.LoadKeyCfg()
       
  1056         ### general page
       
  1057         self.LoadGeneralCfg()
       
  1058 
       
  1059     def SaveNewKeySet(self,keySetName,keySet):
       
  1060         """
       
  1061         save a newly created core key set.
       
  1062         keySetName - string, the name of the new key set
       
  1063         keySet - dictionary containing the new key set
       
  1064         """
       
  1065         if not idleConf.userCfg['keys'].has_section(keySetName):
       
  1066             idleConf.userCfg['keys'].add_section(keySetName)
       
  1067         for event in keySet.keys():
       
  1068             value=keySet[event]
       
  1069             idleConf.userCfg['keys'].SetOption(keySetName,event,value)
       
  1070 
       
  1071     def SaveNewTheme(self,themeName,theme):
       
  1072         """
       
  1073         save a newly created theme.
       
  1074         themeName - string, the name of the new theme
       
  1075         theme - dictionary containing the new theme
       
  1076         """
       
  1077         if not idleConf.userCfg['highlight'].has_section(themeName):
       
  1078             idleConf.userCfg['highlight'].add_section(themeName)
       
  1079         for element in theme.keys():
       
  1080             value=theme[element]
       
  1081             idleConf.userCfg['highlight'].SetOption(themeName,element,value)
       
  1082 
       
  1083     def SetUserValue(self,configType,section,item,value):
       
  1084         if idleConf.defaultCfg[configType].has_option(section,item):
       
  1085             if idleConf.defaultCfg[configType].Get(section,item)==value:
       
  1086                 #the setting equals a default setting, remove it from user cfg
       
  1087                 return idleConf.userCfg[configType].RemoveOption(section,item)
       
  1088         #if we got here set the option
       
  1089         return idleConf.userCfg[configType].SetOption(section,item,value)
       
  1090 
       
  1091     def SaveAllChangedConfigs(self):
       
  1092         "Save configuration changes to the user config file."
       
  1093         idleConf.userCfg['main'].Save()
       
  1094         for configType in self.changedItems.keys():
       
  1095             cfgTypeHasChanges = False
       
  1096             for section in self.changedItems[configType].keys():
       
  1097                 if section == 'HelpFiles':
       
  1098                     #this section gets completely replaced
       
  1099                     idleConf.userCfg['main'].remove_section('HelpFiles')
       
  1100                     cfgTypeHasChanges = True
       
  1101                 for item in self.changedItems[configType][section].keys():
       
  1102                     value = self.changedItems[configType][section][item]
       
  1103                     if self.SetUserValue(configType,section,item,value):
       
  1104                         cfgTypeHasChanges = True
       
  1105             if cfgTypeHasChanges:
       
  1106                 idleConf.userCfg[configType].Save()
       
  1107         for configType in ['keys', 'highlight']:
       
  1108             # save these even if unchanged!
       
  1109             idleConf.userCfg[configType].Save()
       
  1110         self.ResetChangedItems() #clear the changed items dict
       
  1111 
       
  1112     def DeactivateCurrentConfig(self):
       
  1113         #Before a config is saved, some cleanup of current
       
  1114         #config must be done - remove the previous keybindings
       
  1115         winInstances=self.parent.instance_dict.keys()
       
  1116         for instance in winInstances:
       
  1117             instance.RemoveKeybindings()
       
  1118 
       
  1119     def ActivateConfigChanges(self):
       
  1120         "Dynamically apply configuration changes"
       
  1121         winInstances=self.parent.instance_dict.keys()
       
  1122         for instance in winInstances:
       
  1123             instance.ResetColorizer()
       
  1124             instance.ResetFont()
       
  1125             instance.set_notabs_indentwidth()
       
  1126             instance.ApplyKeybindings()
       
  1127             instance.reset_help_menu_entries()
       
  1128 
       
  1129     def Cancel(self):
       
  1130         self.destroy()
       
  1131 
       
  1132     def Ok(self):
       
  1133         self.Apply()
       
  1134         self.destroy()
       
  1135 
       
  1136     def Apply(self):
       
  1137         self.DeactivateCurrentConfig()
       
  1138         self.SaveAllChangedConfigs()
       
  1139         self.ActivateConfigChanges()
       
  1140 
       
  1141     def Help(self):
       
  1142         pass
       
  1143 
       
  1144 if __name__ == '__main__':
       
  1145     #test the dialog
       
  1146     root=Tk()
       
  1147     Button(root,text='Dialog',
       
  1148             command=lambda:ConfigDialog(root,'Settings')).pack()
       
  1149     root.instance_dict={}
       
  1150     root.mainloop()