mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
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.
This commit is contained in:
parent
af5392f5c6
commit
8c78aa70c8
3 changed files with 118 additions and 26 deletions
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue