|
3 | 3 | """
|
4 | 4 | from tkinter import *
|
5 | 5 | from tkinter.ttk import Scrollbar
|
6 |
| -import tkinter.messagebox as tkMessageBox |
| 6 | +from tkinter import messagebox |
7 | 7 | import string
|
8 | 8 | import sys
|
9 | 9 |
|
| 10 | + |
10 | 11 | class GetKeysDialog(Toplevel):
|
| 12 | + |
| 13 | + # Dialog title for invalid key sequence |
| 14 | + keyerror_title = 'Key Sequence Error' |
| 15 | + |
11 | 16 | def __init__(self, parent, title, action, currentKeySequences,
|
12 | 17 | _htest=False, _utest=False):
|
13 | 18 | """
|
@@ -54,6 +59,10 @@ def __init__(self, parent, title, action, currentKeySequences,
|
54 | 59 | self.deiconify() #geometry set, unhide
|
55 | 60 | self.wait_window()
|
56 | 61 |
|
| 62 | + def showerror(self, *args, **kwargs): |
| 63 | + # Make testing easier. Replace in #30751. |
| 64 | + messagebox.showerror(*args, **kwargs) |
| 65 | + |
57 | 66 | def CreateWidgets(self):
|
58 | 67 | frameMain = Frame(self,borderwidth=2,relief=SUNKEN)
|
59 | 68 | frameMain.pack(side=TOP,expand=TRUE,fill=BOTH)
|
@@ -219,53 +228,70 @@ def TranslateKey(self, key, modifiers):
|
219 | 228 | return key
|
220 | 229 |
|
221 | 230 | def OK(self, event=None):
|
222 |
| - if self.advanced or self.KeysOK(): # doesn't check advanced string yet |
223 |
| - self.result=self.keyString.get() |
224 |
| - self.destroy() |
| 231 | + keys = self.keyString.get().strip() |
| 232 | + if not keys: |
| 233 | + self.showerror(title=self.keyerror_title, parent=self, |
| 234 | + message="No key specified.") |
| 235 | + return |
| 236 | + if (self.advanced or self.KeysOK(keys)) and self.bind_ok(keys): |
| 237 | + self.result = keys |
| 238 | + self.destroy() |
225 | 239 |
|
226 | 240 | def Cancel(self, event=None):
|
227 | 241 | self.result=''
|
228 | 242 | self.destroy()
|
229 | 243 |
|
230 |
| - def KeysOK(self): |
| 244 | + def KeysOK(self, keys): |
231 | 245 | '''Validity check on user's 'basic' keybinding selection.
|
232 | 246 |
|
233 | 247 | Doesn't check the string produced by the advanced dialog because
|
234 | 248 | 'modifiers' isn't set.
|
235 | 249 |
|
236 | 250 | '''
|
237 |
| - keys = self.keyString.get() |
238 |
| - keys.strip() |
239 | 251 | finalKey = self.listKeysFinal.get(ANCHOR)
|
240 | 252 | modifiers = self.GetModifiers()
|
241 | 253 | # create a key sequence list for overlap check:
|
242 | 254 | keySequence = keys.split()
|
243 | 255 | keysOK = False
|
244 |
| - title = 'Key Sequence Error' |
245 |
| - if not keys: |
246 |
| - tkMessageBox.showerror(title=title, parent=self, |
247 |
| - message='No keys specified.') |
248 |
| - elif not keys.endswith('>'): |
249 |
| - tkMessageBox.showerror(title=title, parent=self, |
250 |
| - message='Missing the final Key') |
| 256 | + title = self.keyerror_title |
| 257 | + if not keys.endswith('>'): |
| 258 | + self.showerror(title, parent=self, |
| 259 | + message='Missing the final Key') |
251 | 260 | elif (not modifiers
|
252 | 261 | and finalKey not in self.functionKeys + self.moveKeys):
|
253 |
| - tkMessageBox.showerror(title=title, parent=self, |
254 |
| - message='No modifier key(s) specified.') |
| 262 | + self.showerror(title=title, parent=self, |
| 263 | + message='No modifier key(s) specified.') |
255 | 264 | elif (modifiers == ['Shift']) \
|
256 | 265 | and (finalKey not in
|
257 | 266 | self.functionKeys + self.moveKeys + ('Tab', 'Space')):
|
258 | 267 | msg = 'The shift modifier by itself may not be used with'\
|
259 | 268 | ' this key symbol.'
|
260 |
| - tkMessageBox.showerror(title=title, parent=self, message=msg) |
| 269 | + self.showerror(title=title, parent=self, message=msg) |
261 | 270 | elif keySequence in self.currentKeySequences:
|
262 | 271 | msg = 'This key combination is already in use.'
|
263 |
| - tkMessageBox.showerror(title=title, parent=self, message=msg) |
| 272 | + self.showerror(title=title, parent=self, message=msg) |
264 | 273 | else:
|
265 | 274 | keysOK = True
|
266 | 275 | return keysOK
|
267 | 276 |
|
| 277 | + def bind_ok(self, keys): |
| 278 | + "Return True if Tcl accepts the new keys else show message." |
| 279 | + |
| 280 | + try: |
| 281 | + binding = self.bind(keys, lambda: None) |
| 282 | + except TclError as err: |
| 283 | + self.showerror( |
| 284 | + title=self.keyerror_title, parent=self, |
| 285 | + message=(f'The entered key sequence is not accepted.\n\n' |
| 286 | + f'Error: {err}')) |
| 287 | + return False |
| 288 | + else: |
| 289 | + self.unbind(keys, binding) |
| 290 | + return True |
| 291 | + |
268 | 292 |
|
269 | 293 | if __name__ == '__main__':
|
| 294 | + import unittest |
| 295 | + unittest.main('idlelib.idle_test.test_config_key', verbosity=2, exit=False) |
270 | 296 | from idlelib.idle_test.htest import run
|
271 | 297 | run(GetKeysDialog)
|
0 commit comments