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