Credit Nir Aides for r77288
[python.git] / Lib / idlelib / configDialog.py
blob80c54b6534caee39268fc7ff5b6089fec51bba71
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 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 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(self.__ThemeNameIndexCompare)
993 self.optMenuHighlightTarget.SetMenu(themeNames,themeNames[0])
994 self.PaintThemeSample()
995 self.SetHighlightTarget()
997 def __ThemeNameIndexCompare(self,a,b):
998 if self.themeElements[a][1]<self.themeElements[b][1]: return -1
999 elif self.themeElements[a][1]==self.themeElements[b][1]: return 0
1000 else: return 1
1002 def LoadKeyCfg(self):
1003 ##current keys type radiobutton
1004 self.keysAreBuiltin.set(idleConf.GetOption('main','Keys','default',
1005 type='bool',default=1))
1006 ##currently set keys
1007 currentOption=idleConf.CurrentKeys()
1008 ##load available keyset option menus
1009 if self.keysAreBuiltin.get(): #default theme selected
1010 itemList=idleConf.GetSectionList('default','keys')
1011 itemList.sort()
1012 self.optMenuKeysBuiltin.SetMenu(itemList,currentOption)
1013 itemList=idleConf.GetSectionList('user','keys')
1014 itemList.sort()
1015 if not itemList:
1016 self.radioKeysCustom.config(state=DISABLED)
1017 self.customKeys.set('- no custom keys -')
1018 else:
1019 self.optMenuKeysCustom.SetMenu(itemList,itemList[0])
1020 else: #user key set selected
1021 itemList=idleConf.GetSectionList('user','keys')
1022 itemList.sort()
1023 self.optMenuKeysCustom.SetMenu(itemList,currentOption)
1024 itemList=idleConf.GetSectionList('default','keys')
1025 itemList.sort()
1026 self.optMenuKeysBuiltin.SetMenu(itemList,itemList[0])
1027 self.SetKeysType()
1028 ##load keyset element list
1029 keySetName=idleConf.CurrentKeys()
1030 self.LoadKeysList(keySetName)
1032 def LoadGeneralCfg(self):
1033 #startup state
1034 self.startupEdit.set(idleConf.GetOption('main','General',
1035 'editor-on-startup',default=1,type='bool'))
1036 #autosave state
1037 self.autoSave.set(idleConf.GetOption('main', 'General', 'autosave',
1038 default=0, type='bool'))
1039 #initial window size
1040 self.winWidth.set(idleConf.GetOption('main','EditorWindow','width'))
1041 self.winHeight.set(idleConf.GetOption('main','EditorWindow','height'))
1042 #initial paragraph reformat size
1043 self.paraWidth.set(idleConf.GetOption('main','FormatParagraph','paragraph'))
1044 # default source encoding
1045 self.encoding.set(idleConf.GetOption('main', 'EditorWindow',
1046 'encoding', default='none'))
1047 # additional help sources
1048 self.userHelpList = idleConf.GetAllExtraHelpSourcesList()
1049 for helpItem in self.userHelpList:
1050 self.listHelp.insert(END,helpItem[0])
1051 self.SetHelpListButtonStates()
1053 def LoadConfigs(self):
1055 load configuration from default and user config files and populate
1056 the widgets on the config dialog pages.
1058 ### fonts / tabs page
1059 self.LoadFontCfg()
1060 self.LoadTabCfg()
1061 ### highlighting page
1062 self.LoadThemeCfg()
1063 ### keys page
1064 self.LoadKeyCfg()
1065 ### general page
1066 self.LoadGeneralCfg()
1068 def SaveNewKeySet(self,keySetName,keySet):
1070 save a newly created core key set.
1071 keySetName - string, the name of the new key set
1072 keySet - dictionary containing the new key set
1074 if not idleConf.userCfg['keys'].has_section(keySetName):
1075 idleConf.userCfg['keys'].add_section(keySetName)
1076 for event in keySet.keys():
1077 value=keySet[event]
1078 idleConf.userCfg['keys'].SetOption(keySetName,event,value)
1080 def SaveNewTheme(self,themeName,theme):
1082 save a newly created theme.
1083 themeName - string, the name of the new theme
1084 theme - dictionary containing the new theme
1086 if not idleConf.userCfg['highlight'].has_section(themeName):
1087 idleConf.userCfg['highlight'].add_section(themeName)
1088 for element in theme.keys():
1089 value=theme[element]
1090 idleConf.userCfg['highlight'].SetOption(themeName,element,value)
1092 def SetUserValue(self,configType,section,item,value):
1093 if idleConf.defaultCfg[configType].has_option(section,item):
1094 if idleConf.defaultCfg[configType].Get(section,item)==value:
1095 #the setting equals a default setting, remove it from user cfg
1096 return idleConf.userCfg[configType].RemoveOption(section,item)
1097 #if we got here set the option
1098 return idleConf.userCfg[configType].SetOption(section,item,value)
1100 def SaveAllChangedConfigs(self):
1101 "Save configuration changes to the user config file."
1102 idleConf.userCfg['main'].Save()
1103 for configType in self.changedItems.keys():
1104 cfgTypeHasChanges = False
1105 for section in self.changedItems[configType].keys():
1106 if section == 'HelpFiles':
1107 #this section gets completely replaced
1108 idleConf.userCfg['main'].remove_section('HelpFiles')
1109 cfgTypeHasChanges = True
1110 for item in self.changedItems[configType][section].keys():
1111 value = self.changedItems[configType][section][item]
1112 if self.SetUserValue(configType,section,item,value):
1113 cfgTypeHasChanges = True
1114 if cfgTypeHasChanges:
1115 idleConf.userCfg[configType].Save()
1116 for configType in ['keys', 'highlight']:
1117 # save these even if unchanged!
1118 idleConf.userCfg[configType].Save()
1119 self.ResetChangedItems() #clear the changed items dict
1121 def DeactivateCurrentConfig(self):
1122 #Before a config is saved, some cleanup of current
1123 #config must be done - remove the previous keybindings
1124 winInstances=self.parent.instance_dict.keys()
1125 for instance in winInstances:
1126 instance.RemoveKeybindings()
1128 def ActivateConfigChanges(self):
1129 "Dynamically apply configuration changes"
1130 winInstances=self.parent.instance_dict.keys()
1131 for instance in winInstances:
1132 instance.ResetColorizer()
1133 instance.ResetFont()
1134 instance.set_notabs_indentwidth()
1135 instance.ApplyKeybindings()
1136 instance.reset_help_menu_entries()
1138 def Cancel(self):
1139 self.destroy()
1141 def Ok(self):
1142 self.Apply()
1143 self.destroy()
1145 def Apply(self):
1146 self.DeactivateCurrentConfig()
1147 self.SaveAllChangedConfigs()
1148 self.ActivateConfigChanges()
1150 def Help(self):
1151 pass
1153 if __name__ == '__main__':
1154 #test the dialog
1155 root=Tk()
1156 Button(root,text='Dialog',
1157 command=lambda:ConfigDialog(root,'Settings')).pack()
1158 root.instance_dict={}
1159 root.mainloop()