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