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

Python code coverage for Lib/idlelib/keybindingDialog.py

#countcontent
1n/a"""
2n/aDialog for building Tkinter accelerator key bindings
3n/a"""
4n/afrom tkinter import *
5n/aimport tkinter.messagebox as tkMessageBox
6n/aimport string
7n/afrom idlelib import macosxSupport
8n/a
9n/aclass GetKeysDialog(Toplevel):
10n/a def __init__(self,parent,title,action,currentKeySequences):
11n/a """
12n/a action - string, the name of the virtual event these keys will be
13n/a mapped to
14n/a currentKeys - list, a list of all key sequence lists currently mapped
15n/a to virtual events, for overlap checking
16n/a """
17n/a Toplevel.__init__(self, parent)
18n/a self.configure(borderwidth=5)
19n/a self.resizable(height=FALSE,width=FALSE)
20n/a self.title(title)
21n/a self.transient(parent)
22n/a self.grab_set()
23n/a self.protocol("WM_DELETE_WINDOW", self.Cancel)
24n/a self.parent = parent
25n/a self.action=action
26n/a self.currentKeySequences=currentKeySequences
27n/a self.result=''
28n/a self.keyString=StringVar(self)
29n/a self.keyString.set('')
30n/a self.SetModifiersForPlatform() # set self.modifiers, self.modifier_label
31n/a self.modifier_vars = []
32n/a for modifier in self.modifiers:
33n/a variable = StringVar(self)
34n/a variable.set('')
35n/a self.modifier_vars.append(variable)
36n/a self.advanced = False
37n/a self.CreateWidgets()
38n/a self.LoadFinalKeyList()
39n/a self.withdraw() #hide while setting geometry
40n/a self.update_idletasks()
41n/a self.geometry("+%d+%d" %
42n/a ((parent.winfo_rootx()+((parent.winfo_width()/2)
43n/a -(self.winfo_reqwidth()/2)),
44n/a parent.winfo_rooty()+((parent.winfo_height()/2)
45n/a -(self.winfo_reqheight()/2)) )) ) #centre dialog over parent
46n/a self.deiconify() #geometry set, unhide
47n/a self.wait_window()
48n/a
49n/a def CreateWidgets(self):
50n/a frameMain = Frame(self,borderwidth=2,relief=SUNKEN)
51n/a frameMain.pack(side=TOP,expand=TRUE,fill=BOTH)
52n/a frameButtons=Frame(self)
53n/a frameButtons.pack(side=BOTTOM,fill=X)
54n/a self.buttonOK = Button(frameButtons,text='OK',
55n/a width=8,command=self.OK)
56n/a self.buttonOK.grid(row=0,column=0,padx=5,pady=5)
57n/a self.buttonCancel = Button(frameButtons,text='Cancel',
58n/a width=8,command=self.Cancel)
59n/a self.buttonCancel.grid(row=0,column=1,padx=5,pady=5)
60n/a self.frameKeySeqBasic = Frame(frameMain)
61n/a self.frameKeySeqAdvanced = Frame(frameMain)
62n/a self.frameControlsBasic = Frame(frameMain)
63n/a self.frameHelpAdvanced = Frame(frameMain)
64n/a self.frameKeySeqAdvanced.grid(row=0,column=0,sticky=NSEW,padx=5,pady=5)
65n/a self.frameKeySeqBasic.grid(row=0,column=0,sticky=NSEW,padx=5,pady=5)
66n/a self.frameKeySeqBasic.lift()
67n/a self.frameHelpAdvanced.grid(row=1,column=0,sticky=NSEW,padx=5)
68n/a self.frameControlsBasic.grid(row=1,column=0,sticky=NSEW,padx=5)
69n/a self.frameControlsBasic.lift()
70n/a self.buttonLevel = Button(frameMain,command=self.ToggleLevel,
71n/a text='Advanced Key Binding Entry >>')
72n/a self.buttonLevel.grid(row=2,column=0,stick=EW,padx=5,pady=5)
73n/a labelTitleBasic = Label(self.frameKeySeqBasic,
74n/a text="New keys for '"+self.action+"' :")
75n/a labelTitleBasic.pack(anchor=W)
76n/a labelKeysBasic = Label(self.frameKeySeqBasic,justify=LEFT,
77n/a textvariable=self.keyString,relief=GROOVE,borderwidth=2)
78n/a labelKeysBasic.pack(ipadx=5,ipady=5,fill=X)
79n/a self.modifier_checkbuttons = {}
80n/a column = 0
81n/a for modifier, variable in zip(self.modifiers, self.modifier_vars):
82n/a label = self.modifier_label.get(modifier, modifier)
83n/a check=Checkbutton(self.frameControlsBasic,
84n/a command=self.BuildKeyString,
85n/a text=label,variable=variable,onvalue=modifier,offvalue='')
86n/a check.grid(row=0,column=column,padx=2,sticky=W)
87n/a self.modifier_checkbuttons[modifier] = check
88n/a column += 1
89n/a labelFnAdvice=Label(self.frameControlsBasic,justify=LEFT,
90n/a text=\
91n/a "Select the desired modifier keys\n"+
92n/a "above, and the final key from the\n"+
93n/a "list on the right.\n\n" +
94n/a "Use upper case Symbols when using\n" +
95n/a "the Shift modifier. (Letters will be\n" +
96n/a "converted automatically.)")
97n/a labelFnAdvice.grid(row=1,column=0,columnspan=4,padx=2,sticky=W)
98n/a self.listKeysFinal=Listbox(self.frameControlsBasic,width=15,height=10,
99n/a selectmode=SINGLE)
100n/a self.listKeysFinal.bind('<ButtonRelease-1>',self.FinalKeySelected)
101n/a self.listKeysFinal.grid(row=0,column=4,rowspan=4,sticky=NS)
102n/a scrollKeysFinal=Scrollbar(self.frameControlsBasic,orient=VERTICAL,
103n/a command=self.listKeysFinal.yview)
104n/a self.listKeysFinal.config(yscrollcommand=scrollKeysFinal.set)
105n/a scrollKeysFinal.grid(row=0,column=5,rowspan=4,sticky=NS)
106n/a self.buttonClear=Button(self.frameControlsBasic,
107n/a text='Clear Keys',command=self.ClearKeySeq)
108n/a self.buttonClear.grid(row=2,column=0,columnspan=4)
109n/a labelTitleAdvanced = Label(self.frameKeySeqAdvanced,justify=LEFT,
110n/a text="Enter new binding(s) for '"+self.action+"' :\n"+
111n/a "(These bindings will not be checked for validity!)")
112n/a labelTitleAdvanced.pack(anchor=W)
113n/a self.entryKeysAdvanced=Entry(self.frameKeySeqAdvanced,
114n/a textvariable=self.keyString)
115n/a self.entryKeysAdvanced.pack(fill=X)
116n/a labelHelpAdvanced=Label(self.frameHelpAdvanced,justify=LEFT,
117n/a text="Key bindings are specified using Tkinter keysyms as\n"+
118n/a "in these samples: <Control-f>, <Shift-F2>, <F12>,\n"
119n/a "<Control-space>, <Meta-less>, <Control-Alt-Shift-X>.\n"
120n/a "Upper case is used when the Shift modifier is present!\n\n" +
121n/a "'Emacs style' multi-keystroke bindings are specified as\n" +
122n/a "follows: <Control-x><Control-y>, where the first key\n" +
123n/a "is the 'do-nothing' keybinding.\n\n" +
124n/a "Multiple separate bindings for one action should be\n"+
125n/a "separated by a space, eg., <Alt-v> <Meta-v>." )
126n/a labelHelpAdvanced.grid(row=0,column=0,sticky=NSEW)
127n/a
128n/a def SetModifiersForPlatform(self):
129n/a """Determine list of names of key modifiers for this platform.
130n/a
131n/a The names are used to build Tk bindings -- it doesn't matter if the
132n/a keyboard has these keys, it matters if Tk understands them. The
133n/a order is also important: key binding equality depends on it, so
134n/a config-keys.def must use the same ordering.
135n/a """
136n/a import sys
137n/a if macosxSupport.runningAsOSXApp():
138n/a self.modifiers = ['Shift', 'Control', 'Option', 'Command']
139n/a else:
140n/a self.modifiers = ['Control', 'Alt', 'Shift']
141n/a self.modifier_label = {'Control': 'Ctrl'} # short name
142n/a
143n/a def ToggleLevel(self):
144n/a if self.buttonLevel.cget('text')[:8]=='Advanced':
145n/a self.ClearKeySeq()
146n/a self.buttonLevel.config(text='<< Basic Key Binding Entry')
147n/a self.frameKeySeqAdvanced.lift()
148n/a self.frameHelpAdvanced.lift()
149n/a self.entryKeysAdvanced.focus_set()
150n/a self.advanced = True
151n/a else:
152n/a self.ClearKeySeq()
153n/a self.buttonLevel.config(text='Advanced Key Binding Entry >>')
154n/a self.frameKeySeqBasic.lift()
155n/a self.frameControlsBasic.lift()
156n/a self.advanced = False
157n/a
158n/a def FinalKeySelected(self,event):
159n/a self.BuildKeyString()
160n/a
161n/a def BuildKeyString(self):
162n/a keyList = modifiers = self.GetModifiers()
163n/a finalKey = self.listKeysFinal.get(ANCHOR)
164n/a if finalKey:
165n/a finalKey = self.TranslateKey(finalKey, modifiers)
166n/a keyList.append(finalKey)
167n/a self.keyString.set('<' + '-'.join(keyList) + '>')
168n/a
169n/a def GetModifiers(self):
170n/a modList = [variable.get() for variable in self.modifier_vars]
171n/a return [mod for mod in modList if mod]
172n/a
173n/a def ClearKeySeq(self):
174n/a self.listKeysFinal.select_clear(0,END)
175n/a self.listKeysFinal.yview(MOVETO, '0.0')
176n/a for variable in self.modifier_vars:
177n/a variable.set('')
178n/a self.keyString.set('')
179n/a
180n/a def LoadFinalKeyList(self):
181n/a #these tuples are also available for use in validity checks
182n/a self.functionKeys=('F1','F2','F2','F4','F5','F6','F7','F8','F9',
183n/a 'F10','F11','F12')
184n/a self.alphanumKeys=tuple(string.ascii_lowercase+string.digits)
185n/a self.punctuationKeys=tuple('~!@#%^&*()_-+={}[]|;:,.<>/?')
186n/a self.whitespaceKeys=('Tab','Space','Return')
187n/a self.editKeys=('BackSpace','Delete','Insert')
188n/a self.moveKeys=('Home','End','Page Up','Page Down','Left Arrow',
189n/a 'Right Arrow','Up Arrow','Down Arrow')
190n/a #make a tuple of most of the useful common 'final' keys
191n/a keys=(self.alphanumKeys+self.punctuationKeys+self.functionKeys+
192n/a self.whitespaceKeys+self.editKeys+self.moveKeys)
193n/a self.listKeysFinal.insert(END, *keys)
194n/a
195n/a def TranslateKey(self, key, modifiers):
196n/a "Translate from keycap symbol to the Tkinter keysym"
197n/a translateDict = {'Space':'space',
198n/a '~':'asciitilde','!':'exclam','@':'at','#':'numbersign',
199n/a '%':'percent','^':'asciicircum','&':'ampersand','*':'asterisk',
200n/a '(':'parenleft',')':'parenright','_':'underscore','-':'minus',
201n/a '+':'plus','=':'equal','{':'braceleft','}':'braceright',
202n/a '[':'bracketleft',']':'bracketright','|':'bar',';':'semicolon',
203n/a ':':'colon',',':'comma','.':'period','<':'less','>':'greater',
204n/a '/':'slash','?':'question','Page Up':'Prior','Page Down':'Next',
205n/a 'Left Arrow':'Left','Right Arrow':'Right','Up Arrow':'Up',
206n/a 'Down Arrow': 'Down', 'Tab':'Tab'}
207n/a if key in translateDict:
208n/a key = translateDict[key]
209n/a if 'Shift' in modifiers and key in string.ascii_lowercase:
210n/a key = key.upper()
211n/a key = 'Key-' + key
212n/a return key
213n/a
214n/a def OK(self, event=None):
215n/a if self.advanced or self.KeysOK(): # doesn't check advanced string yet
216n/a self.result=self.keyString.get()
217n/a self.destroy()
218n/a
219n/a def Cancel(self, event=None):
220n/a self.result=''
221n/a self.destroy()
222n/a
223n/a def KeysOK(self):
224n/a '''Validity check on user's 'basic' keybinding selection.
225n/a
226n/a Doesn't check the string produced by the advanced dialog because
227n/a 'modifiers' isn't set.
228n/a
229n/a '''
230n/a keys = self.keyString.get()
231n/a keys.strip()
232n/a finalKey = self.listKeysFinal.get(ANCHOR)
233n/a modifiers = self.GetModifiers()
234n/a # create a key sequence list for overlap check:
235n/a keySequence = keys.split()
236n/a keysOK = False
237n/a title = 'Key Sequence Error'
238n/a if not keys:
239n/a tkMessageBox.showerror(title=title, parent=self,
240n/a message='No keys specified.')
241n/a elif not keys.endswith('>'):
242n/a tkMessageBox.showerror(title=title, parent=self,
243n/a message='Missing the final Key')
244n/a elif (not modifiers
245n/a and finalKey not in self.functionKeys + self.moveKeys):
246n/a tkMessageBox.showerror(title=title, parent=self,
247n/a message='No modifier key(s) specified.')
248n/a elif (modifiers == ['Shift']) \
249n/a and (finalKey not in
250n/a self.functionKeys + self.moveKeys + ('Tab', 'Space')):
251n/a msg = 'The shift modifier by itself may not be used with'\
252n/a ' this key symbol.'
253n/a tkMessageBox.showerror(title=title, parent=self, message=msg)
254n/a elif keySequence in self.currentKeySequences:
255n/a msg = 'This key combination is already in use.'
256n/a tkMessageBox.showerror(title=title, parent=self, message=msg)
257n/a else:
258n/a keysOK = True
259n/a return keysOK
260n/a
261n/aif __name__ == '__main__':
262n/a #test the dialog
263n/a root=Tk()
264n/a def run():
265n/a keySeq=''
266n/a dlg=GetKeysDialog(root,'Get Keys','find-again',[])
267n/a print(dlg.result)
268n/a Button(root,text='Dialog',command=run).pack()
269n/a root.mainloop()