ยปCore Development>Code coverage>Lib/idlelib/configDialog.py

Python code coverage for Lib/idlelib/configDialog.py

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