diff options
author | csabella <cheryl.sabella@gmail.com> | 2017-06-26 04:55:48 (GMT) |
---|---|---|
committer | terryjreedy <tjreedy@udel.edu> | 2017-06-26 04:55:48 (GMT) |
commit | 8c78aa70c888a370af18896a72cabd00e4120f09 (patch) | |
tree | b7059a54610f623b90969315be4ac868f366243f /Lib/idlelib/config_key.py | |
parent | af5392f5c6f8014659e995840df6ee7b5017f743 (diff) | |
download | cpython-8c78aa70c888a370af18896a72cabd00e4120f09.zip cpython-8c78aa70c888a370af18896a72cabd00e4120f09.tar.gz cpython-8c78aa70c888a370af18896a72cabd00e4120f09.tar.bz2 |
bpo-6739: IDLE: Check for valid keybinding in config_keys (#2377)
Verify user-entered key sequences by trying to bind them with tk.
Add tests for all 3 validation functions.
Original patch by G Polo. Tests added by Cheryl Sabella.
Diffstat (limited to 'Lib/idlelib/config_key.py')
-rw-r--r-- | Lib/idlelib/config_key.py | 62 |
1 files changed, 44 insertions, 18 deletions
diff --git a/Lib/idlelib/config_key.py b/Lib/idlelib/config_key.py index 479d6ad..8d575ec 100644 --- a/Lib/idlelib/config_key.py +++ b/Lib/idlelib/config_key.py @@ -3,11 +3,16 @@ Dialog for building Tkinter accelerator key bindings """ from tkinter import * from tkinter.ttk import Scrollbar -import tkinter.messagebox as tkMessageBox +from tkinter import messagebox import string import sys + class GetKeysDialog(Toplevel): + + # Dialog title for invalid key sequence + keyerror_title = 'Key Sequence Error' + def __init__(self, parent, title, action, currentKeySequences, _htest=False, _utest=False): """ @@ -54,6 +59,10 @@ class GetKeysDialog(Toplevel): self.deiconify() #geometry set, unhide self.wait_window() + def showerror(self, *args, **kwargs): + # Make testing easier. Replace in #30751. + messagebox.showerror(*args, **kwargs) + def CreateWidgets(self): frameMain = Frame(self,borderwidth=2,relief=SUNKEN) frameMain.pack(side=TOP,expand=TRUE,fill=BOTH) @@ -219,53 +228,70 @@ class GetKeysDialog(Toplevel): return key def OK(self, event=None): - if self.advanced or self.KeysOK(): # doesn't check advanced string yet - self.result=self.keyString.get() - self.destroy() + keys = self.keyString.get().strip() + if not keys: + self.showerror(title=self.keyerror_title, parent=self, + message="No key specified.") + return + if (self.advanced or self.KeysOK(keys)) and self.bind_ok(keys): + self.result = keys + self.destroy() def Cancel(self, event=None): self.result='' self.destroy() - def KeysOK(self): + def KeysOK(self, keys): '''Validity check on user's 'basic' keybinding selection. Doesn't check the string produced by the advanced dialog because 'modifiers' isn't set. ''' - keys = self.keyString.get() - keys.strip() finalKey = self.listKeysFinal.get(ANCHOR) modifiers = self.GetModifiers() # create a key sequence list for overlap check: keySequence = keys.split() keysOK = False - title = 'Key Sequence Error' - if not keys: - tkMessageBox.showerror(title=title, parent=self, - message='No keys specified.') - elif not keys.endswith('>'): - tkMessageBox.showerror(title=title, parent=self, - message='Missing the final Key') + title = self.keyerror_title + if not keys.endswith('>'): + self.showerror(title, parent=self, + message='Missing the final Key') elif (not modifiers and finalKey not in self.functionKeys + self.moveKeys): - tkMessageBox.showerror(title=title, parent=self, - message='No modifier key(s) specified.') + self.showerror(title=title, parent=self, + message='No modifier key(s) specified.') elif (modifiers == ['Shift']) \ and (finalKey not in self.functionKeys + self.moveKeys + ('Tab', 'Space')): msg = 'The shift modifier by itself may not be used with'\ ' this key symbol.' - tkMessageBox.showerror(title=title, parent=self, message=msg) + self.showerror(title=title, parent=self, message=msg) elif keySequence in self.currentKeySequences: msg = 'This key combination is already in use.' - tkMessageBox.showerror(title=title, parent=self, message=msg) + self.showerror(title=title, parent=self, message=msg) else: keysOK = True return keysOK + def bind_ok(self, keys): + "Return True if Tcl accepts the new keys else show message." + + try: + binding = self.bind(keys, lambda: None) + except TclError as err: + self.showerror( + title=self.keyerror_title, parent=self, + message=(f'The entered key sequence is not accepted.\n\n' + f'Error: {err}')) + return False + else: + self.unbind(keys, binding) + return True + if __name__ == '__main__': + import unittest + unittest.main('idlelib.idle_test.test_config_key', verbosity=2, exit=False) from idlelib.idle_test.htest import run run(GetKeysDialog) |