mirror of https://github.com/python/cpython.git
bpo-31205: IDLE: Factor KeysPage class from ConfigDialog (#3096)
The slightly modified tests continue to pass. Patch by Cheryl Sabella.
This commit is contained in:
parent
1f512b9a34
commit
e36d9f5568
|
@ -92,9 +92,9 @@ def create_widgets(self):
|
||||||
note: Notebook
|
note: Notebook
|
||||||
highpage: self.create_page_highlight
|
highpage: self.create_page_highlight
|
||||||
fontpage: FontPage
|
fontpage: FontPage
|
||||||
keyspage: self.create_page_keys
|
keyspage: KeysPage
|
||||||
genpage: GenPage
|
genpage: GenPage
|
||||||
extpageL self.create_page_extensions
|
extpage: self.create_page_extensions
|
||||||
|
|
||||||
Methods:
|
Methods:
|
||||||
create_action_buttons
|
create_action_buttons
|
||||||
|
@ -104,7 +104,7 @@ def create_widgets(self):
|
||||||
self.note = note = Notebook(self, width=450, height=450)
|
self.note = note = Notebook(self, width=450, height=450)
|
||||||
self.highpage = self.create_page_highlight()
|
self.highpage = self.create_page_highlight()
|
||||||
self.fontpage = FontPage(note, self.highpage)
|
self.fontpage = FontPage(note, self.highpage)
|
||||||
self.keyspage = self.create_page_keys()
|
self.keyspage = KeysPage(note)
|
||||||
self.genpage = GenPage(note)
|
self.genpage = GenPage(note)
|
||||||
self.extpage = self.create_page_extensions()
|
self.extpage = self.create_page_extensions()
|
||||||
note.add(self.fontpage, text='Fonts/Tabs')
|
note.add(self.fontpage, text='Fonts/Tabs')
|
||||||
|
@ -132,7 +132,7 @@ def load_configs(self):
|
||||||
#self.load_font_cfg()
|
#self.load_font_cfg()
|
||||||
#self.load_tab_cfg()
|
#self.load_tab_cfg()
|
||||||
self.load_theme_cfg()
|
self.load_theme_cfg()
|
||||||
self.load_key_cfg()
|
# self.load_key_cfg()
|
||||||
# self.load_general_cfg()
|
# self.load_general_cfg()
|
||||||
# note: extension page handled separately
|
# note: extension page handled separately
|
||||||
|
|
||||||
|
@ -791,431 +791,6 @@ def delete_custom_theme(self):
|
||||||
self.activate_config_changes()
|
self.activate_config_changes()
|
||||||
self.set_theme_type()
|
self.set_theme_type()
|
||||||
|
|
||||||
|
|
||||||
def create_page_keys(self):
|
|
||||||
"""Return frame of widgets for Keys tab.
|
|
||||||
|
|
||||||
Enable users to provisionally change both individual and sets of
|
|
||||||
keybindings (shortcut keys). Except for features implemented as
|
|
||||||
extensions, keybindings are stored in complete sets called
|
|
||||||
keysets. Built-in keysets in idlelib/config-keys.def are fixed
|
|
||||||
as far as the dialog is concerned. Any keyset can be used as the
|
|
||||||
base for a new custom keyset, stored in .idlerc/config-keys.cfg.
|
|
||||||
|
|
||||||
Function load_key_cfg() initializes tk variables and keyset
|
|
||||||
lists and calls load_keys_list for the current keyset.
|
|
||||||
Radiobuttons builtin_keyset_on and custom_keyset_on toggle var
|
|
||||||
keyset_source, which controls if the current set of keybindings
|
|
||||||
are from a builtin or custom keyset. DynOptionMenus builtinlist
|
|
||||||
and customlist contain lists of the builtin and custom keysets,
|
|
||||||
respectively, and the current item from each list is stored in
|
|
||||||
vars builtin_name and custom_name.
|
|
||||||
|
|
||||||
Button delete_custom_keys invokes delete_custom_keys() to delete
|
|
||||||
a custom keyset from idleConf.userCfg['keys'] and changes. Button
|
|
||||||
save_custom_keys invokes save_as_new_key_set() which calls
|
|
||||||
get_new_keys_name() and create_new_key_set() to save a custom keyset
|
|
||||||
and its keybindings to idleConf.userCfg['keys'].
|
|
||||||
|
|
||||||
Listbox bindingslist contains all of the keybindings for the
|
|
||||||
selected keyset. The keybindings are loaded in load_keys_list()
|
|
||||||
and are pairs of (event, [keys]) where keys can be a list
|
|
||||||
of one or more key combinations to bind to the same event.
|
|
||||||
Mouse button 1 click invokes on_bindingslist_select(), which
|
|
||||||
allows button_new_keys to be clicked.
|
|
||||||
|
|
||||||
So, an item is selected in listbindings, which activates
|
|
||||||
button_new_keys, and clicking button_new_keys calls function
|
|
||||||
get_new_keys(). Function get_new_keys() gets the key mappings from the
|
|
||||||
current keyset for the binding event item that was selected. The
|
|
||||||
function then displays another dialog, GetKeysDialog, with the
|
|
||||||
selected binding event and current keys and always new key sequences
|
|
||||||
to be entered for that binding event. If the keys aren't
|
|
||||||
changed, nothing happens. If the keys are changed and the keyset
|
|
||||||
is a builtin, function get_new_keys_name() will be called
|
|
||||||
for input of a custom keyset name. If no name is given, then the
|
|
||||||
change to the keybinding will abort and no updates will be made. If
|
|
||||||
a custom name is entered in the prompt or if the current keyset was
|
|
||||||
already custom (and thus didn't require a prompt), then
|
|
||||||
idleConf.userCfg['keys'] is updated in function create_new_key_set()
|
|
||||||
with the change to the event binding. The item listing in bindingslist
|
|
||||||
is updated with the new keys. Var keybinding is also set which invokes
|
|
||||||
the callback function, var_changed_keybinding, to add the change to
|
|
||||||
the 'keys' or 'extensions' changes tracker based on the binding type.
|
|
||||||
|
|
||||||
Tk Variables:
|
|
||||||
keybinding: Action/key bindings.
|
|
||||||
|
|
||||||
Methods:
|
|
||||||
load_keys_list: Reload active set.
|
|
||||||
create_new_key_set: Combine active keyset and changes.
|
|
||||||
set_keys_type: Command for keyset_source.
|
|
||||||
save_new_key_set: Save to idleConf.userCfg['keys'] (is function).
|
|
||||||
deactivate_current_config: Remove keys bindings in editors.
|
|
||||||
|
|
||||||
Widgets for keys page frame: (*) widgets bound to self
|
|
||||||
frame_key_sets: LabelFrame
|
|
||||||
frames[0]: Frame
|
|
||||||
(*)builtin_keyset_on: Radiobutton - var keyset_source
|
|
||||||
(*)custom_keyset_on: Radiobutton - var keyset_source
|
|
||||||
(*)builtinlist: DynOptionMenu - var builtin_name,
|
|
||||||
func keybinding_selected
|
|
||||||
(*)customlist: DynOptionMenu - var custom_name,
|
|
||||||
func keybinding_selected
|
|
||||||
(*)keys_message: Label
|
|
||||||
frames[1]: Frame
|
|
||||||
(*)button_delete_custom_keys: Button - delete_custom_keys
|
|
||||||
(*)button_save_custom_keys: Button - save_as_new_key_set
|
|
||||||
frame_custom: LabelFrame
|
|
||||||
frame_target: Frame
|
|
||||||
target_title: Label
|
|
||||||
scroll_target_y: Scrollbar
|
|
||||||
scroll_target_x: Scrollbar
|
|
||||||
(*)bindingslist: ListBox - on_bindingslist_select
|
|
||||||
(*)button_new_keys: Button - get_new_keys & ..._name
|
|
||||||
"""
|
|
||||||
parent = self.parent
|
|
||||||
self.builtin_name = tracers.add(
|
|
||||||
StringVar(parent), self.var_changed_builtin_name)
|
|
||||||
self.custom_name = tracers.add(
|
|
||||||
StringVar(parent), self.var_changed_custom_name)
|
|
||||||
self.keyset_source = tracers.add(
|
|
||||||
BooleanVar(parent), self.var_changed_keyset_source)
|
|
||||||
self.keybinding = tracers.add(
|
|
||||||
StringVar(parent), self.var_changed_keybinding)
|
|
||||||
|
|
||||||
# Widget creation:
|
|
||||||
# body and section frames.
|
|
||||||
frame = Frame(self.note)
|
|
||||||
frame_custom = LabelFrame(
|
|
||||||
frame, borderwidth=2, relief=GROOVE,
|
|
||||||
text=' Custom Key Bindings ')
|
|
||||||
frame_key_sets = LabelFrame(
|
|
||||||
frame, borderwidth=2, relief=GROOVE, text=' Key Set ')
|
|
||||||
#frame_custom
|
|
||||||
frame_target = Frame(frame_custom)
|
|
||||||
target_title = Label(frame_target, text='Action - Key(s)')
|
|
||||||
scroll_target_y = Scrollbar(frame_target)
|
|
||||||
scroll_target_x = Scrollbar(frame_target, orient=HORIZONTAL)
|
|
||||||
self.bindingslist = Listbox(
|
|
||||||
frame_target, takefocus=FALSE, exportselection=FALSE)
|
|
||||||
self.bindingslist.bind('<ButtonRelease-1>',
|
|
||||||
self.on_bindingslist_select)
|
|
||||||
scroll_target_y['command'] = self.bindingslist.yview
|
|
||||||
scroll_target_x['command'] = self.bindingslist.xview
|
|
||||||
self.bindingslist['yscrollcommand'] = scroll_target_y.set
|
|
||||||
self.bindingslist['xscrollcommand'] = scroll_target_x.set
|
|
||||||
self.button_new_keys = Button(
|
|
||||||
frame_custom, text='Get New Keys for Selection',
|
|
||||||
command=self.get_new_keys, state=DISABLED)
|
|
||||||
#frame_key_sets
|
|
||||||
frames = [Frame(frame_key_sets, padx=2, pady=2, borderwidth=0)
|
|
||||||
for i in range(2)]
|
|
||||||
self.builtin_keyset_on = Radiobutton(
|
|
||||||
frames[0], variable=self.keyset_source, value=1,
|
|
||||||
command=self.set_keys_type, text='Use a Built-in Key Set')
|
|
||||||
self.custom_keyset_on = Radiobutton(
|
|
||||||
frames[0], variable=self.keyset_source, value=0,
|
|
||||||
command=self.set_keys_type, text='Use a Custom Key Set')
|
|
||||||
self.builtinlist = DynOptionMenu(
|
|
||||||
frames[0], self.builtin_name, None, command=None)
|
|
||||||
self.customlist = DynOptionMenu(
|
|
||||||
frames[0], self.custom_name, None, command=None)
|
|
||||||
self.button_delete_custom_keys = Button(
|
|
||||||
frames[1], text='Delete Custom Key Set',
|
|
||||||
command=self.delete_custom_keys)
|
|
||||||
self.button_save_custom_keys = Button(
|
|
||||||
frames[1], text='Save as New Custom Key Set',
|
|
||||||
command=self.save_as_new_key_set)
|
|
||||||
self.keys_message = Label(frames[0], bd=2)
|
|
||||||
|
|
||||||
##widget packing
|
|
||||||
#body
|
|
||||||
frame_custom.pack(side=BOTTOM, padx=5, pady=5, expand=TRUE, fill=BOTH)
|
|
||||||
frame_key_sets.pack(side=BOTTOM, padx=5, pady=5, fill=BOTH)
|
|
||||||
#frame_custom
|
|
||||||
self.button_new_keys.pack(side=BOTTOM, fill=X, padx=5, pady=5)
|
|
||||||
frame_target.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
|
|
||||||
#frame target
|
|
||||||
frame_target.columnconfigure(0, weight=1)
|
|
||||||
frame_target.rowconfigure(1, weight=1)
|
|
||||||
target_title.grid(row=0, column=0, columnspan=2, sticky=W)
|
|
||||||
self.bindingslist.grid(row=1, column=0, sticky=NSEW)
|
|
||||||
scroll_target_y.grid(row=1, column=1, sticky=NS)
|
|
||||||
scroll_target_x.grid(row=2, column=0, sticky=EW)
|
|
||||||
#frame_key_sets
|
|
||||||
self.builtin_keyset_on.grid(row=0, column=0, sticky=W+NS)
|
|
||||||
self.custom_keyset_on.grid(row=1, column=0, sticky=W+NS)
|
|
||||||
self.builtinlist.grid(row=0, column=1, sticky=NSEW)
|
|
||||||
self.customlist.grid(row=1, column=1, sticky=NSEW)
|
|
||||||
self.keys_message.grid(row=0, column=2, sticky=NSEW, padx=5, pady=5)
|
|
||||||
self.button_delete_custom_keys.pack(side=LEFT, fill=X, expand=True, padx=2)
|
|
||||||
self.button_save_custom_keys.pack(side=LEFT, fill=X, expand=True, padx=2)
|
|
||||||
frames[0].pack(side=TOP, fill=BOTH, expand=True)
|
|
||||||
frames[1].pack(side=TOP, fill=X, expand=True, pady=2)
|
|
||||||
return frame
|
|
||||||
|
|
||||||
def load_key_cfg(self):
|
|
||||||
"Load current configuration settings for the keybinding options."
|
|
||||||
# Set current keys type radiobutton.
|
|
||||||
self.keyset_source.set(idleConf.GetOption(
|
|
||||||
'main', 'Keys', 'default', type='bool', default=1))
|
|
||||||
# Set current keys.
|
|
||||||
current_option = idleConf.CurrentKeys()
|
|
||||||
# Load available keyset option menus.
|
|
||||||
if self.keyset_source.get(): # Default theme selected.
|
|
||||||
item_list = idleConf.GetSectionList('default', 'keys')
|
|
||||||
item_list.sort()
|
|
||||||
self.builtinlist.SetMenu(item_list, current_option)
|
|
||||||
item_list = idleConf.GetSectionList('user', 'keys')
|
|
||||||
item_list.sort()
|
|
||||||
if not item_list:
|
|
||||||
self.custom_keyset_on['state'] = DISABLED
|
|
||||||
self.custom_name.set('- no custom keys -')
|
|
||||||
else:
|
|
||||||
self.customlist.SetMenu(item_list, item_list[0])
|
|
||||||
else: # User key set selected.
|
|
||||||
item_list = idleConf.GetSectionList('user', 'keys')
|
|
||||||
item_list.sort()
|
|
||||||
self.customlist.SetMenu(item_list, current_option)
|
|
||||||
item_list = idleConf.GetSectionList('default', 'keys')
|
|
||||||
item_list.sort()
|
|
||||||
self.builtinlist.SetMenu(item_list, idleConf.default_keys())
|
|
||||||
self.set_keys_type()
|
|
||||||
# Load keyset element list.
|
|
||||||
keyset_name = idleConf.CurrentKeys()
|
|
||||||
self.load_keys_list(keyset_name)
|
|
||||||
|
|
||||||
def var_changed_builtin_name(self, *params):
|
|
||||||
"Process selection of builtin key set."
|
|
||||||
old_keys = (
|
|
||||||
'IDLE Classic Windows',
|
|
||||||
'IDLE Classic Unix',
|
|
||||||
'IDLE Classic Mac',
|
|
||||||
'IDLE Classic OSX',
|
|
||||||
)
|
|
||||||
value = self.builtin_name.get()
|
|
||||||
if value not in old_keys:
|
|
||||||
if idleConf.GetOption('main', 'Keys', 'name') not in old_keys:
|
|
||||||
changes.add_option('main', 'Keys', 'name', old_keys[0])
|
|
||||||
changes.add_option('main', 'Keys', 'name2', value)
|
|
||||||
self.keys_message['text'] = 'New key set, see Help'
|
|
||||||
self.keys_message['fg'] = '#500000'
|
|
||||||
else:
|
|
||||||
changes.add_option('main', 'Keys', 'name', value)
|
|
||||||
changes.add_option('main', 'Keys', 'name2', '')
|
|
||||||
self.keys_message['text'] = ''
|
|
||||||
self.keys_message['fg'] = 'black'
|
|
||||||
self.load_keys_list(value)
|
|
||||||
|
|
||||||
def var_changed_custom_name(self, *params):
|
|
||||||
"Process selection of custom key set."
|
|
||||||
value = self.custom_name.get()
|
|
||||||
if value != '- no custom keys -':
|
|
||||||
changes.add_option('main', 'Keys', 'name', value)
|
|
||||||
self.load_keys_list(value)
|
|
||||||
|
|
||||||
def var_changed_keyset_source(self, *params):
|
|
||||||
"Process toggle between builtin key set and custom key set."
|
|
||||||
value = self.keyset_source.get()
|
|
||||||
changes.add_option('main', 'Keys', 'default', value)
|
|
||||||
if value:
|
|
||||||
self.var_changed_builtin_name()
|
|
||||||
else:
|
|
||||||
self.var_changed_custom_name()
|
|
||||||
|
|
||||||
def var_changed_keybinding(self, *params):
|
|
||||||
"Store change to a keybinding."
|
|
||||||
value = self.keybinding.get()
|
|
||||||
key_set = self.custom_name.get()
|
|
||||||
event = self.bindingslist.get(ANCHOR).split()[0]
|
|
||||||
if idleConf.IsCoreBinding(event):
|
|
||||||
changes.add_option('keys', key_set, event, value)
|
|
||||||
else: # Event is an extension binding.
|
|
||||||
ext_name = idleConf.GetExtnNameForEvent(event)
|
|
||||||
ext_keybind_section = ext_name + '_cfgBindings'
|
|
||||||
changes.add_option('extensions', ext_keybind_section, event, value)
|
|
||||||
|
|
||||||
def set_keys_type(self):
|
|
||||||
"Set available screen options based on builtin or custom key set."
|
|
||||||
if self.keyset_source.get():
|
|
||||||
self.builtinlist['state'] = NORMAL
|
|
||||||
self.customlist['state'] = DISABLED
|
|
||||||
self.button_delete_custom_keys['state'] = DISABLED
|
|
||||||
else:
|
|
||||||
self.builtinlist['state'] = DISABLED
|
|
||||||
self.custom_keyset_on['state'] = NORMAL
|
|
||||||
self.customlist['state'] = NORMAL
|
|
||||||
self.button_delete_custom_keys['state'] = NORMAL
|
|
||||||
|
|
||||||
def get_new_keys(self):
|
|
||||||
"""Handle event to change key binding for selected line.
|
|
||||||
|
|
||||||
A selection of a key/binding in the list of current
|
|
||||||
bindings pops up a dialog to enter a new binding. If
|
|
||||||
the current key set is builtin and a binding has
|
|
||||||
changed, then a name for a custom key set needs to be
|
|
||||||
entered for the change to be applied.
|
|
||||||
"""
|
|
||||||
list_index = self.bindingslist.index(ANCHOR)
|
|
||||||
binding = self.bindingslist.get(list_index)
|
|
||||||
bind_name = binding.split()[0]
|
|
||||||
if self.keyset_source.get():
|
|
||||||
current_key_set_name = self.builtin_name.get()
|
|
||||||
else:
|
|
||||||
current_key_set_name = self.custom_name.get()
|
|
||||||
current_bindings = idleConf.GetCurrentKeySet()
|
|
||||||
if current_key_set_name in changes['keys']: # unsaved changes
|
|
||||||
key_set_changes = changes['keys'][current_key_set_name]
|
|
||||||
for event in key_set_changes:
|
|
||||||
current_bindings[event] = key_set_changes[event].split()
|
|
||||||
current_key_sequences = list(current_bindings.values())
|
|
||||||
new_keys = GetKeysDialog(self, 'Get New Keys', bind_name,
|
|
||||||
current_key_sequences).result
|
|
||||||
if new_keys:
|
|
||||||
if self.keyset_source.get(): # Current key set is a built-in.
|
|
||||||
message = ('Your changes will be saved as a new Custom Key Set.'
|
|
||||||
' Enter a name for your new Custom Key Set below.')
|
|
||||||
new_keyset = self.get_new_keys_name(message)
|
|
||||||
if not new_keyset: # User cancelled custom key set creation.
|
|
||||||
self.bindingslist.select_set(list_index)
|
|
||||||
self.bindingslist.select_anchor(list_index)
|
|
||||||
return
|
|
||||||
else: # Create new custom key set based on previously active key set.
|
|
||||||
self.create_new_key_set(new_keyset)
|
|
||||||
self.bindingslist.delete(list_index)
|
|
||||||
self.bindingslist.insert(list_index, bind_name+' - '+new_keys)
|
|
||||||
self.bindingslist.select_set(list_index)
|
|
||||||
self.bindingslist.select_anchor(list_index)
|
|
||||||
self.keybinding.set(new_keys)
|
|
||||||
else:
|
|
||||||
self.bindingslist.select_set(list_index)
|
|
||||||
self.bindingslist.select_anchor(list_index)
|
|
||||||
|
|
||||||
def get_new_keys_name(self, message):
|
|
||||||
"Return new key set name from query popup."
|
|
||||||
used_names = (idleConf.GetSectionList('user', 'keys') +
|
|
||||||
idleConf.GetSectionList('default', 'keys'))
|
|
||||||
new_keyset = SectionName(
|
|
||||||
self, 'New Custom Key Set', message, used_names).result
|
|
||||||
return new_keyset
|
|
||||||
|
|
||||||
def save_as_new_key_set(self):
|
|
||||||
"Prompt for name of new key set and save changes using that name."
|
|
||||||
new_keys_name = self.get_new_keys_name('New Key Set Name:')
|
|
||||||
if new_keys_name:
|
|
||||||
self.create_new_key_set(new_keys_name)
|
|
||||||
|
|
||||||
def on_bindingslist_select(self, event):
|
|
||||||
"Activate button to assign new keys to selected action."
|
|
||||||
self.button_new_keys['state'] = NORMAL
|
|
||||||
|
|
||||||
def create_new_key_set(self, new_key_set_name):
|
|
||||||
"""Create a new custom key set with the given name.
|
|
||||||
|
|
||||||
Copy the bindings/keys from the previously active keyset
|
|
||||||
to the new keyset and activate the new custom keyset.
|
|
||||||
"""
|
|
||||||
if self.keyset_source.get():
|
|
||||||
prev_key_set_name = self.builtin_name.get()
|
|
||||||
else:
|
|
||||||
prev_key_set_name = self.custom_name.get()
|
|
||||||
prev_keys = idleConf.GetCoreKeys(prev_key_set_name)
|
|
||||||
new_keys = {}
|
|
||||||
for event in prev_keys: # Add key set to changed items.
|
|
||||||
event_name = event[2:-2] # Trim off the angle brackets.
|
|
||||||
binding = ' '.join(prev_keys[event])
|
|
||||||
new_keys[event_name] = binding
|
|
||||||
# Handle any unsaved changes to prev key set.
|
|
||||||
if prev_key_set_name in changes['keys']:
|
|
||||||
key_set_changes = changes['keys'][prev_key_set_name]
|
|
||||||
for event in key_set_changes:
|
|
||||||
new_keys[event] = key_set_changes[event]
|
|
||||||
# Save the new key set.
|
|
||||||
self.save_new_key_set(new_key_set_name, new_keys)
|
|
||||||
# Change GUI over to the new key set.
|
|
||||||
custom_key_list = idleConf.GetSectionList('user', 'keys')
|
|
||||||
custom_key_list.sort()
|
|
||||||
self.customlist.SetMenu(custom_key_list, new_key_set_name)
|
|
||||||
self.keyset_source.set(0)
|
|
||||||
self.set_keys_type()
|
|
||||||
|
|
||||||
def load_keys_list(self, keyset_name):
|
|
||||||
"""Reload the list of action/key binding pairs for the active key set.
|
|
||||||
|
|
||||||
An action/key binding can be selected to change the key binding.
|
|
||||||
"""
|
|
||||||
reselect = False
|
|
||||||
if self.bindingslist.curselection():
|
|
||||||
reselect = True
|
|
||||||
list_index = self.bindingslist.index(ANCHOR)
|
|
||||||
keyset = idleConf.GetKeySet(keyset_name)
|
|
||||||
bind_names = list(keyset.keys())
|
|
||||||
bind_names.sort()
|
|
||||||
self.bindingslist.delete(0, END)
|
|
||||||
for bind_name in bind_names:
|
|
||||||
key = ' '.join(keyset[bind_name])
|
|
||||||
bind_name = bind_name[2:-2] # Trim off the angle brackets.
|
|
||||||
if keyset_name in changes['keys']:
|
|
||||||
# Handle any unsaved changes to this key set.
|
|
||||||
if bind_name in changes['keys'][keyset_name]:
|
|
||||||
key = changes['keys'][keyset_name][bind_name]
|
|
||||||
self.bindingslist.insert(END, bind_name+' - '+key)
|
|
||||||
if reselect:
|
|
||||||
self.bindingslist.see(list_index)
|
|
||||||
self.bindingslist.select_set(list_index)
|
|
||||||
self.bindingslist.select_anchor(list_index)
|
|
||||||
|
|
||||||
def save_new_key_set(self, keyset_name, keyset):
|
|
||||||
"""Save a newly created core key set.
|
|
||||||
|
|
||||||
Add keyset to idleConf.userCfg['keys'], not to disk.
|
|
||||||
If the keyset doesn't exist, it is created. The
|
|
||||||
binding/keys are taken from the keyset argument.
|
|
||||||
|
|
||||||
keyset_name - string, the name of the new key set
|
|
||||||
keyset - dictionary containing the new keybindings
|
|
||||||
"""
|
|
||||||
if not idleConf.userCfg['keys'].has_section(keyset_name):
|
|
||||||
idleConf.userCfg['keys'].add_section(keyset_name)
|
|
||||||
for event in keyset:
|
|
||||||
value = keyset[event]
|
|
||||||
idleConf.userCfg['keys'].SetOption(keyset_name, event, value)
|
|
||||||
|
|
||||||
def delete_custom_keys(self):
|
|
||||||
"""Handle event to delete a custom key set.
|
|
||||||
|
|
||||||
Applying the delete deactivates the current configuration and
|
|
||||||
reverts to the default. The custom key set is permanently
|
|
||||||
deleted from the config file.
|
|
||||||
"""
|
|
||||||
keyset_name=self.custom_name.get()
|
|
||||||
delmsg = 'Are you sure you wish to delete the key set %r ?'
|
|
||||||
if not tkMessageBox.askyesno(
|
|
||||||
'Delete Key Set', delmsg % keyset_name, parent=self):
|
|
||||||
return
|
|
||||||
self.deactivate_current_config()
|
|
||||||
# Remove key set from changes, config, and file.
|
|
||||||
changes.delete_section('keys', keyset_name)
|
|
||||||
# Reload user key set list.
|
|
||||||
item_list = idleConf.GetSectionList('user', 'keys')
|
|
||||||
item_list.sort()
|
|
||||||
if not item_list:
|
|
||||||
self.custom_keyset_on['state'] = DISABLED
|
|
||||||
self.customlist.SetMenu(item_list, '- no custom keys -')
|
|
||||||
else:
|
|
||||||
self.customlist.SetMenu(item_list, item_list[0])
|
|
||||||
# Revert to default key set.
|
|
||||||
self.keyset_source.set(idleConf.defaultCfg['main']
|
|
||||||
.Get('Keys', 'default'))
|
|
||||||
self.builtin_name.set(idleConf.defaultCfg['main'].Get('Keys', 'name')
|
|
||||||
or idleConf.default_keys())
|
|
||||||
# User can't back out of these changes, they must be applied now.
|
|
||||||
changes.save_all()
|
|
||||||
self.save_all_changed_extensions()
|
|
||||||
self.activate_config_changes()
|
|
||||||
self.set_keys_type()
|
|
||||||
|
|
||||||
def deactivate_current_config(self):
|
def deactivate_current_config(self):
|
||||||
"""Remove current key bindings.
|
"""Remove current key bindings.
|
||||||
|
|
||||||
|
@ -1650,6 +1225,437 @@ def var_changed_space_num(self, *params):
|
||||||
changes.add_option('main', 'Indent', 'num-spaces', value)
|
changes.add_option('main', 'Indent', 'num-spaces', value)
|
||||||
|
|
||||||
|
|
||||||
|
class KeysPage(Frame):
|
||||||
|
|
||||||
|
def __init__(self, master):
|
||||||
|
super().__init__(master)
|
||||||
|
self.cd = master.master
|
||||||
|
self.create_page_keys()
|
||||||
|
self.load_key_cfg()
|
||||||
|
|
||||||
|
def create_page_keys(self):
|
||||||
|
"""Return frame of widgets for Keys tab.
|
||||||
|
|
||||||
|
Enable users to provisionally change both individual and sets of
|
||||||
|
keybindings (shortcut keys). Except for features implemented as
|
||||||
|
extensions, keybindings are stored in complete sets called
|
||||||
|
keysets. Built-in keysets in idlelib/config-keys.def are fixed
|
||||||
|
as far as the dialog is concerned. Any keyset can be used as the
|
||||||
|
base for a new custom keyset, stored in .idlerc/config-keys.cfg.
|
||||||
|
|
||||||
|
Function load_key_cfg() initializes tk variables and keyset
|
||||||
|
lists and calls load_keys_list for the current keyset.
|
||||||
|
Radiobuttons builtin_keyset_on and custom_keyset_on toggle var
|
||||||
|
keyset_source, which controls if the current set of keybindings
|
||||||
|
are from a builtin or custom keyset. DynOptionMenus builtinlist
|
||||||
|
and customlist contain lists of the builtin and custom keysets,
|
||||||
|
respectively, and the current item from each list is stored in
|
||||||
|
vars builtin_name and custom_name.
|
||||||
|
|
||||||
|
Button delete_custom_keys invokes delete_custom_keys() to delete
|
||||||
|
a custom keyset from idleConf.userCfg['keys'] and changes. Button
|
||||||
|
save_custom_keys invokes save_as_new_key_set() which calls
|
||||||
|
get_new_keys_name() and create_new_key_set() to save a custom keyset
|
||||||
|
and its keybindings to idleConf.userCfg['keys'].
|
||||||
|
|
||||||
|
Listbox bindingslist contains all of the keybindings for the
|
||||||
|
selected keyset. The keybindings are loaded in load_keys_list()
|
||||||
|
and are pairs of (event, [keys]) where keys can be a list
|
||||||
|
of one or more key combinations to bind to the same event.
|
||||||
|
Mouse button 1 click invokes on_bindingslist_select(), which
|
||||||
|
allows button_new_keys to be clicked.
|
||||||
|
|
||||||
|
So, an item is selected in listbindings, which activates
|
||||||
|
button_new_keys, and clicking button_new_keys calls function
|
||||||
|
get_new_keys(). Function get_new_keys() gets the key mappings from the
|
||||||
|
current keyset for the binding event item that was selected. The
|
||||||
|
function then displays another dialog, GetKeysDialog, with the
|
||||||
|
selected binding event and current keys and always new key sequences
|
||||||
|
to be entered for that binding event. If the keys aren't
|
||||||
|
changed, nothing happens. If the keys are changed and the keyset
|
||||||
|
is a builtin, function get_new_keys_name() will be called
|
||||||
|
for input of a custom keyset name. If no name is given, then the
|
||||||
|
change to the keybinding will abort and no updates will be made. If
|
||||||
|
a custom name is entered in the prompt or if the current keyset was
|
||||||
|
already custom (and thus didn't require a prompt), then
|
||||||
|
idleConf.userCfg['keys'] is updated in function create_new_key_set()
|
||||||
|
with the change to the event binding. The item listing in bindingslist
|
||||||
|
is updated with the new keys. Var keybinding is also set which invokes
|
||||||
|
the callback function, var_changed_keybinding, to add the change to
|
||||||
|
the 'keys' or 'extensions' changes tracker based on the binding type.
|
||||||
|
|
||||||
|
Tk Variables:
|
||||||
|
keybinding: Action/key bindings.
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
load_keys_list: Reload active set.
|
||||||
|
create_new_key_set: Combine active keyset and changes.
|
||||||
|
set_keys_type: Command for keyset_source.
|
||||||
|
save_new_key_set: Save to idleConf.userCfg['keys'] (is function).
|
||||||
|
deactivate_current_config: Remove keys bindings in editors.
|
||||||
|
|
||||||
|
Widgets for KeysPage(frame): (*) widgets bound to self
|
||||||
|
frame_key_sets: LabelFrame
|
||||||
|
frames[0]: Frame
|
||||||
|
(*)builtin_keyset_on: Radiobutton - var keyset_source
|
||||||
|
(*)custom_keyset_on: Radiobutton - var keyset_source
|
||||||
|
(*)builtinlist: DynOptionMenu - var builtin_name,
|
||||||
|
func keybinding_selected
|
||||||
|
(*)customlist: DynOptionMenu - var custom_name,
|
||||||
|
func keybinding_selected
|
||||||
|
(*)keys_message: Label
|
||||||
|
frames[1]: Frame
|
||||||
|
(*)button_delete_custom_keys: Button - delete_custom_keys
|
||||||
|
(*)button_save_custom_keys: Button - save_as_new_key_set
|
||||||
|
frame_custom: LabelFrame
|
||||||
|
frame_target: Frame
|
||||||
|
target_title: Label
|
||||||
|
scroll_target_y: Scrollbar
|
||||||
|
scroll_target_x: Scrollbar
|
||||||
|
(*)bindingslist: ListBox - on_bindingslist_select
|
||||||
|
(*)button_new_keys: Button - get_new_keys & ..._name
|
||||||
|
"""
|
||||||
|
self.builtin_name = tracers.add(
|
||||||
|
StringVar(self), self.var_changed_builtin_name)
|
||||||
|
self.custom_name = tracers.add(
|
||||||
|
StringVar(self), self.var_changed_custom_name)
|
||||||
|
self.keyset_source = tracers.add(
|
||||||
|
BooleanVar(self), self.var_changed_keyset_source)
|
||||||
|
self.keybinding = tracers.add(
|
||||||
|
StringVar(self), self.var_changed_keybinding)
|
||||||
|
|
||||||
|
# Create widgets:
|
||||||
|
# body and section frames.
|
||||||
|
frame_custom = LabelFrame(
|
||||||
|
self, borderwidth=2, relief=GROOVE,
|
||||||
|
text=' Custom Key Bindings ')
|
||||||
|
frame_key_sets = LabelFrame(
|
||||||
|
self, borderwidth=2, relief=GROOVE, text=' Key Set ')
|
||||||
|
# frame_custom.
|
||||||
|
frame_target = Frame(frame_custom)
|
||||||
|
target_title = Label(frame_target, text='Action - Key(s)')
|
||||||
|
scroll_target_y = Scrollbar(frame_target)
|
||||||
|
scroll_target_x = Scrollbar(frame_target, orient=HORIZONTAL)
|
||||||
|
self.bindingslist = Listbox(
|
||||||
|
frame_target, takefocus=FALSE, exportselection=FALSE)
|
||||||
|
self.bindingslist.bind('<ButtonRelease-1>',
|
||||||
|
self.on_bindingslist_select)
|
||||||
|
scroll_target_y['command'] = self.bindingslist.yview
|
||||||
|
scroll_target_x['command'] = self.bindingslist.xview
|
||||||
|
self.bindingslist['yscrollcommand'] = scroll_target_y.set
|
||||||
|
self.bindingslist['xscrollcommand'] = scroll_target_x.set
|
||||||
|
self.button_new_keys = Button(
|
||||||
|
frame_custom, text='Get New Keys for Selection',
|
||||||
|
command=self.get_new_keys, state=DISABLED)
|
||||||
|
# frame_key_sets.
|
||||||
|
frames = [Frame(frame_key_sets, padx=2, pady=2, borderwidth=0)
|
||||||
|
for i in range(2)]
|
||||||
|
self.builtin_keyset_on = Radiobutton(
|
||||||
|
frames[0], variable=self.keyset_source, value=1,
|
||||||
|
command=self.set_keys_type, text='Use a Built-in Key Set')
|
||||||
|
self.custom_keyset_on = Radiobutton(
|
||||||
|
frames[0], variable=self.keyset_source, value=0,
|
||||||
|
command=self.set_keys_type, text='Use a Custom Key Set')
|
||||||
|
self.builtinlist = DynOptionMenu(
|
||||||
|
frames[0], self.builtin_name, None, command=None)
|
||||||
|
self.customlist = DynOptionMenu(
|
||||||
|
frames[0], self.custom_name, None, command=None)
|
||||||
|
self.button_delete_custom_keys = Button(
|
||||||
|
frames[1], text='Delete Custom Key Set',
|
||||||
|
command=self.delete_custom_keys)
|
||||||
|
self.button_save_custom_keys = Button(
|
||||||
|
frames[1], text='Save as New Custom Key Set',
|
||||||
|
command=self.save_as_new_key_set)
|
||||||
|
self.keys_message = Label(frames[0], bd=2)
|
||||||
|
|
||||||
|
# Pack widgets:
|
||||||
|
# body.
|
||||||
|
frame_custom.pack(side=BOTTOM, padx=5, pady=5, expand=TRUE, fill=BOTH)
|
||||||
|
frame_key_sets.pack(side=BOTTOM, padx=5, pady=5, fill=BOTH)
|
||||||
|
# frame_custom.
|
||||||
|
self.button_new_keys.pack(side=BOTTOM, fill=X, padx=5, pady=5)
|
||||||
|
frame_target.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
|
||||||
|
# frame_target.
|
||||||
|
frame_target.columnconfigure(0, weight=1)
|
||||||
|
frame_target.rowconfigure(1, weight=1)
|
||||||
|
target_title.grid(row=0, column=0, columnspan=2, sticky=W)
|
||||||
|
self.bindingslist.grid(row=1, column=0, sticky=NSEW)
|
||||||
|
scroll_target_y.grid(row=1, column=1, sticky=NS)
|
||||||
|
scroll_target_x.grid(row=2, column=0, sticky=EW)
|
||||||
|
# frame_key_sets.
|
||||||
|
self.builtin_keyset_on.grid(row=0, column=0, sticky=W+NS)
|
||||||
|
self.custom_keyset_on.grid(row=1, column=0, sticky=W+NS)
|
||||||
|
self.builtinlist.grid(row=0, column=1, sticky=NSEW)
|
||||||
|
self.customlist.grid(row=1, column=1, sticky=NSEW)
|
||||||
|
self.keys_message.grid(row=0, column=2, sticky=NSEW, padx=5, pady=5)
|
||||||
|
self.button_delete_custom_keys.pack(side=LEFT, fill=X, expand=True, padx=2)
|
||||||
|
self.button_save_custom_keys.pack(side=LEFT, fill=X, expand=True, padx=2)
|
||||||
|
frames[0].pack(side=TOP, fill=BOTH, expand=True)
|
||||||
|
frames[1].pack(side=TOP, fill=X, expand=True, pady=2)
|
||||||
|
|
||||||
|
def load_key_cfg(self):
|
||||||
|
"Load current configuration settings for the keybinding options."
|
||||||
|
# Set current keys type radiobutton.
|
||||||
|
self.keyset_source.set(idleConf.GetOption(
|
||||||
|
'main', 'Keys', 'default', type='bool', default=1))
|
||||||
|
# Set current keys.
|
||||||
|
current_option = idleConf.CurrentKeys()
|
||||||
|
# Load available keyset option menus.
|
||||||
|
if self.keyset_source.get(): # Default theme selected.
|
||||||
|
item_list = idleConf.GetSectionList('default', 'keys')
|
||||||
|
item_list.sort()
|
||||||
|
self.builtinlist.SetMenu(item_list, current_option)
|
||||||
|
item_list = idleConf.GetSectionList('user', 'keys')
|
||||||
|
item_list.sort()
|
||||||
|
if not item_list:
|
||||||
|
self.custom_keyset_on['state'] = DISABLED
|
||||||
|
self.custom_name.set('- no custom keys -')
|
||||||
|
else:
|
||||||
|
self.customlist.SetMenu(item_list, item_list[0])
|
||||||
|
else: # User key set selected.
|
||||||
|
item_list = idleConf.GetSectionList('user', 'keys')
|
||||||
|
item_list.sort()
|
||||||
|
self.customlist.SetMenu(item_list, current_option)
|
||||||
|
item_list = idleConf.GetSectionList('default', 'keys')
|
||||||
|
item_list.sort()
|
||||||
|
self.builtinlist.SetMenu(item_list, idleConf.default_keys())
|
||||||
|
self.set_keys_type()
|
||||||
|
# Load keyset element list.
|
||||||
|
keyset_name = idleConf.CurrentKeys()
|
||||||
|
self.load_keys_list(keyset_name)
|
||||||
|
|
||||||
|
def var_changed_builtin_name(self, *params):
|
||||||
|
"Process selection of builtin key set."
|
||||||
|
old_keys = (
|
||||||
|
'IDLE Classic Windows',
|
||||||
|
'IDLE Classic Unix',
|
||||||
|
'IDLE Classic Mac',
|
||||||
|
'IDLE Classic OSX',
|
||||||
|
)
|
||||||
|
value = self.builtin_name.get()
|
||||||
|
if value not in old_keys:
|
||||||
|
if idleConf.GetOption('main', 'Keys', 'name') not in old_keys:
|
||||||
|
changes.add_option('main', 'Keys', 'name', old_keys[0])
|
||||||
|
changes.add_option('main', 'Keys', 'name2', value)
|
||||||
|
self.keys_message['text'] = 'New key set, see Help'
|
||||||
|
self.keys_message['fg'] = '#500000'
|
||||||
|
else:
|
||||||
|
changes.add_option('main', 'Keys', 'name', value)
|
||||||
|
changes.add_option('main', 'Keys', 'name2', '')
|
||||||
|
self.keys_message['text'] = ''
|
||||||
|
self.keys_message['fg'] = 'black'
|
||||||
|
self.load_keys_list(value)
|
||||||
|
|
||||||
|
def var_changed_custom_name(self, *params):
|
||||||
|
"Process selection of custom key set."
|
||||||
|
value = self.custom_name.get()
|
||||||
|
if value != '- no custom keys -':
|
||||||
|
changes.add_option('main', 'Keys', 'name', value)
|
||||||
|
self.load_keys_list(value)
|
||||||
|
|
||||||
|
def var_changed_keyset_source(self, *params):
|
||||||
|
"Process toggle between builtin key set and custom key set."
|
||||||
|
value = self.keyset_source.get()
|
||||||
|
changes.add_option('main', 'Keys', 'default', value)
|
||||||
|
if value:
|
||||||
|
self.var_changed_builtin_name()
|
||||||
|
else:
|
||||||
|
self.var_changed_custom_name()
|
||||||
|
|
||||||
|
def var_changed_keybinding(self, *params):
|
||||||
|
"Store change to a keybinding."
|
||||||
|
value = self.keybinding.get()
|
||||||
|
key_set = self.custom_name.get()
|
||||||
|
event = self.bindingslist.get(ANCHOR).split()[0]
|
||||||
|
if idleConf.IsCoreBinding(event):
|
||||||
|
changes.add_option('keys', key_set, event, value)
|
||||||
|
else: # Event is an extension binding.
|
||||||
|
ext_name = idleConf.GetExtnNameForEvent(event)
|
||||||
|
ext_keybind_section = ext_name + '_cfgBindings'
|
||||||
|
changes.add_option('extensions', ext_keybind_section, event, value)
|
||||||
|
|
||||||
|
def set_keys_type(self):
|
||||||
|
"Set available screen options based on builtin or custom key set."
|
||||||
|
if self.keyset_source.get():
|
||||||
|
self.builtinlist['state'] = NORMAL
|
||||||
|
self.customlist['state'] = DISABLED
|
||||||
|
self.button_delete_custom_keys['state'] = DISABLED
|
||||||
|
else:
|
||||||
|
self.builtinlist['state'] = DISABLED
|
||||||
|
self.custom_keyset_on['state'] = NORMAL
|
||||||
|
self.customlist['state'] = NORMAL
|
||||||
|
self.button_delete_custom_keys['state'] = NORMAL
|
||||||
|
|
||||||
|
def get_new_keys(self):
|
||||||
|
"""Handle event to change key binding for selected line.
|
||||||
|
|
||||||
|
A selection of a key/binding in the list of current
|
||||||
|
bindings pops up a dialog to enter a new binding. If
|
||||||
|
the current key set is builtin and a binding has
|
||||||
|
changed, then a name for a custom key set needs to be
|
||||||
|
entered for the change to be applied.
|
||||||
|
"""
|
||||||
|
list_index = self.bindingslist.index(ANCHOR)
|
||||||
|
binding = self.bindingslist.get(list_index)
|
||||||
|
bind_name = binding.split()[0]
|
||||||
|
if self.keyset_source.get():
|
||||||
|
current_key_set_name = self.builtin_name.get()
|
||||||
|
else:
|
||||||
|
current_key_set_name = self.custom_name.get()
|
||||||
|
current_bindings = idleConf.GetCurrentKeySet()
|
||||||
|
if current_key_set_name in changes['keys']: # unsaved changes
|
||||||
|
key_set_changes = changes['keys'][current_key_set_name]
|
||||||
|
for event in key_set_changes:
|
||||||
|
current_bindings[event] = key_set_changes[event].split()
|
||||||
|
current_key_sequences = list(current_bindings.values())
|
||||||
|
new_keys = GetKeysDialog(self, 'Get New Keys', bind_name,
|
||||||
|
current_key_sequences).result
|
||||||
|
if new_keys:
|
||||||
|
if self.keyset_source.get(): # Current key set is a built-in.
|
||||||
|
message = ('Your changes will be saved as a new Custom Key Set.'
|
||||||
|
' Enter a name for your new Custom Key Set below.')
|
||||||
|
new_keyset = self.get_new_keys_name(message)
|
||||||
|
if not new_keyset: # User cancelled custom key set creation.
|
||||||
|
self.bindingslist.select_set(list_index)
|
||||||
|
self.bindingslist.select_anchor(list_index)
|
||||||
|
return
|
||||||
|
else: # Create new custom key set based on previously active key set.
|
||||||
|
self.create_new_key_set(new_keyset)
|
||||||
|
self.bindingslist.delete(list_index)
|
||||||
|
self.bindingslist.insert(list_index, bind_name+' - '+new_keys)
|
||||||
|
self.bindingslist.select_set(list_index)
|
||||||
|
self.bindingslist.select_anchor(list_index)
|
||||||
|
self.keybinding.set(new_keys)
|
||||||
|
else:
|
||||||
|
self.bindingslist.select_set(list_index)
|
||||||
|
self.bindingslist.select_anchor(list_index)
|
||||||
|
|
||||||
|
def get_new_keys_name(self, message):
|
||||||
|
"Return new key set name from query popup."
|
||||||
|
used_names = (idleConf.GetSectionList('user', 'keys') +
|
||||||
|
idleConf.GetSectionList('default', 'keys'))
|
||||||
|
new_keyset = SectionName(
|
||||||
|
self, 'New Custom Key Set', message, used_names).result
|
||||||
|
return new_keyset
|
||||||
|
|
||||||
|
def save_as_new_key_set(self):
|
||||||
|
"Prompt for name of new key set and save changes using that name."
|
||||||
|
new_keys_name = self.get_new_keys_name('New Key Set Name:')
|
||||||
|
if new_keys_name:
|
||||||
|
self.create_new_key_set(new_keys_name)
|
||||||
|
|
||||||
|
def on_bindingslist_select(self, event):
|
||||||
|
"Activate button to assign new keys to selected action."
|
||||||
|
self.button_new_keys['state'] = NORMAL
|
||||||
|
|
||||||
|
def create_new_key_set(self, new_key_set_name):
|
||||||
|
"""Create a new custom key set with the given name.
|
||||||
|
|
||||||
|
Copy the bindings/keys from the previously active keyset
|
||||||
|
to the new keyset and activate the new custom keyset.
|
||||||
|
"""
|
||||||
|
if self.keyset_source.get():
|
||||||
|
prev_key_set_name = self.builtin_name.get()
|
||||||
|
else:
|
||||||
|
prev_key_set_name = self.custom_name.get()
|
||||||
|
prev_keys = idleConf.GetCoreKeys(prev_key_set_name)
|
||||||
|
new_keys = {}
|
||||||
|
for event in prev_keys: # Add key set to changed items.
|
||||||
|
event_name = event[2:-2] # Trim off the angle brackets.
|
||||||
|
binding = ' '.join(prev_keys[event])
|
||||||
|
new_keys[event_name] = binding
|
||||||
|
# Handle any unsaved changes to prev key set.
|
||||||
|
if prev_key_set_name in changes['keys']:
|
||||||
|
key_set_changes = changes['keys'][prev_key_set_name]
|
||||||
|
for event in key_set_changes:
|
||||||
|
new_keys[event] = key_set_changes[event]
|
||||||
|
# Save the new key set.
|
||||||
|
self.save_new_key_set(new_key_set_name, new_keys)
|
||||||
|
# Change GUI over to the new key set.
|
||||||
|
custom_key_list = idleConf.GetSectionList('user', 'keys')
|
||||||
|
custom_key_list.sort()
|
||||||
|
self.customlist.SetMenu(custom_key_list, new_key_set_name)
|
||||||
|
self.keyset_source.set(0)
|
||||||
|
self.set_keys_type()
|
||||||
|
|
||||||
|
def load_keys_list(self, keyset_name):
|
||||||
|
"""Reload the list of action/key binding pairs for the active key set.
|
||||||
|
|
||||||
|
An action/key binding can be selected to change the key binding.
|
||||||
|
"""
|
||||||
|
reselect = False
|
||||||
|
if self.bindingslist.curselection():
|
||||||
|
reselect = True
|
||||||
|
list_index = self.bindingslist.index(ANCHOR)
|
||||||
|
keyset = idleConf.GetKeySet(keyset_name)
|
||||||
|
bind_names = list(keyset.keys())
|
||||||
|
bind_names.sort()
|
||||||
|
self.bindingslist.delete(0, END)
|
||||||
|
for bind_name in bind_names:
|
||||||
|
key = ' '.join(keyset[bind_name])
|
||||||
|
bind_name = bind_name[2:-2] # Trim off the angle brackets.
|
||||||
|
if keyset_name in changes['keys']:
|
||||||
|
# Handle any unsaved changes to this key set.
|
||||||
|
if bind_name in changes['keys'][keyset_name]:
|
||||||
|
key = changes['keys'][keyset_name][bind_name]
|
||||||
|
self.bindingslist.insert(END, bind_name+' - '+key)
|
||||||
|
if reselect:
|
||||||
|
self.bindingslist.see(list_index)
|
||||||
|
self.bindingslist.select_set(list_index)
|
||||||
|
self.bindingslist.select_anchor(list_index)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def save_new_key_set(keyset_name, keyset):
|
||||||
|
"""Save a newly created core key set.
|
||||||
|
|
||||||
|
Add keyset to idleConf.userCfg['keys'], not to disk.
|
||||||
|
If the keyset doesn't exist, it is created. The
|
||||||
|
binding/keys are taken from the keyset argument.
|
||||||
|
|
||||||
|
keyset_name - string, the name of the new key set
|
||||||
|
keyset - dictionary containing the new keybindings
|
||||||
|
"""
|
||||||
|
if not idleConf.userCfg['keys'].has_section(keyset_name):
|
||||||
|
idleConf.userCfg['keys'].add_section(keyset_name)
|
||||||
|
for event in keyset:
|
||||||
|
value = keyset[event]
|
||||||
|
idleConf.userCfg['keys'].SetOption(keyset_name, event, value)
|
||||||
|
|
||||||
|
def delete_custom_keys(self):
|
||||||
|
"""Handle event to delete a custom key set.
|
||||||
|
|
||||||
|
Applying the delete deactivates the current configuration and
|
||||||
|
reverts to the default. The custom key set is permanently
|
||||||
|
deleted from the config file.
|
||||||
|
"""
|
||||||
|
keyset_name = self.custom_name.get()
|
||||||
|
delmsg = 'Are you sure you wish to delete the key set %r ?'
|
||||||
|
if not tkMessageBox.askyesno(
|
||||||
|
'Delete Key Set', delmsg % keyset_name, parent=self):
|
||||||
|
return
|
||||||
|
self.cd.deactivate_current_config()
|
||||||
|
# Remove key set from changes, config, and file.
|
||||||
|
changes.delete_section('keys', keyset_name)
|
||||||
|
# Reload user key set list.
|
||||||
|
item_list = idleConf.GetSectionList('user', 'keys')
|
||||||
|
item_list.sort()
|
||||||
|
if not item_list:
|
||||||
|
self.custom_keyset_on['state'] = DISABLED
|
||||||
|
self.customlist.SetMenu(item_list, '- no custom keys -')
|
||||||
|
else:
|
||||||
|
self.customlist.SetMenu(item_list, item_list[0])
|
||||||
|
# Revert to default key set.
|
||||||
|
self.keyset_source.set(idleConf.defaultCfg['main']
|
||||||
|
.Get('Keys', 'default'))
|
||||||
|
self.builtin_name.set(idleConf.defaultCfg['main'].Get('Keys', 'name')
|
||||||
|
or idleConf.default_keys())
|
||||||
|
# User can't back out of these changes, they must be applied now.
|
||||||
|
changes.save_all()
|
||||||
|
self.cd.save_all_changed_extensions()
|
||||||
|
self.cd.activate_config_changes()
|
||||||
|
self.set_keys_type()
|
||||||
|
|
||||||
|
|
||||||
class GenPage(Frame):
|
class GenPage(Frame):
|
||||||
|
|
||||||
def __init__(self, master):
|
def __init__(self, master):
|
||||||
|
|
|
@ -232,22 +232,27 @@ def setUp(self):
|
||||||
changes.clear()
|
changes.clear()
|
||||||
|
|
||||||
|
|
||||||
class KeyTest(unittest.TestCase):
|
class KeysPageTest(unittest.TestCase):
|
||||||
|
"""Test that keys tab widgets enable users to make changes.
|
||||||
|
|
||||||
|
Test that widget actions set vars, that var changes add
|
||||||
|
options to changes and that key sets works correctly.
|
||||||
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
d = dialog
|
page = cls.page = dialog.keyspage
|
||||||
dialog.note.select(d.keyspage)
|
dialog.note.select(page)
|
||||||
d.set_keys_type = Func()
|
page.set_keys_type = Func()
|
||||||
d.load_keys_list = Func()
|
page.load_keys_list = Func()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def tearDownClass(cls):
|
def tearDownClass(cls):
|
||||||
d = dialog
|
page = cls.page
|
||||||
del d.set_keys_type, d.load_keys_list
|
del page.set_keys_type, page.load_keys_list
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
d = dialog
|
d = self.page
|
||||||
# The following is needed for test_load_key_cfg, _delete_custom_keys.
|
# The following is needed for test_load_key_cfg, _delete_custom_keys.
|
||||||
# This may indicate a defect in some test or function.
|
# This may indicate a defect in some test or function.
|
||||||
for section in idleConf.GetSectionList('user', 'keys'):
|
for section in idleConf.GetSectionList('user', 'keys'):
|
||||||
|
@ -258,7 +263,7 @@ def setUp(self):
|
||||||
|
|
||||||
def test_load_key_cfg(self):
|
def test_load_key_cfg(self):
|
||||||
tracers.detach()
|
tracers.detach()
|
||||||
d = dialog
|
d = self.page
|
||||||
eq = self.assertEqual
|
eq = self.assertEqual
|
||||||
|
|
||||||
# Use builtin keyset with no user keysets created.
|
# Use builtin keyset with no user keysets created.
|
||||||
|
@ -300,7 +305,7 @@ def test_load_key_cfg(self):
|
||||||
|
|
||||||
def test_keyset_source(self):
|
def test_keyset_source(self):
|
||||||
eq = self.assertEqual
|
eq = self.assertEqual
|
||||||
d = dialog
|
d = self.page
|
||||||
# Test these separately.
|
# Test these separately.
|
||||||
d.var_changed_builtin_name = Func()
|
d.var_changed_builtin_name = Func()
|
||||||
d.var_changed_custom_name = Func()
|
d.var_changed_custom_name = Func()
|
||||||
|
@ -321,7 +326,7 @@ def test_keyset_source(self):
|
||||||
|
|
||||||
def test_builtin_name(self):
|
def test_builtin_name(self):
|
||||||
eq = self.assertEqual
|
eq = self.assertEqual
|
||||||
d = dialog
|
d = self.page
|
||||||
idleConf.userCfg['main'].remove_section('Keys')
|
idleConf.userCfg['main'].remove_section('Keys')
|
||||||
item_list = ['IDLE Classic Windows', 'IDLE Classic OSX',
|
item_list = ['IDLE Classic Windows', 'IDLE Classic OSX',
|
||||||
'IDLE Modern UNIX']
|
'IDLE Modern UNIX']
|
||||||
|
@ -352,7 +357,7 @@ def test_builtin_name(self):
|
||||||
eq(d.load_keys_list.args, ('IDLE Classic OSX', ))
|
eq(d.load_keys_list.args, ('IDLE Classic OSX', ))
|
||||||
|
|
||||||
def test_custom_name(self):
|
def test_custom_name(self):
|
||||||
d = dialog
|
d = self.page
|
||||||
|
|
||||||
# If no selections, doesn't get added.
|
# If no selections, doesn't get added.
|
||||||
d.customlist.SetMenu([], '- no custom keys -')
|
d.customlist.SetMenu([], '- no custom keys -')
|
||||||
|
@ -366,7 +371,7 @@ def test_custom_name(self):
|
||||||
self.assertEqual(d.load_keys_list.called, 1)
|
self.assertEqual(d.load_keys_list.called, 1)
|
||||||
|
|
||||||
def test_keybinding(self):
|
def test_keybinding(self):
|
||||||
d = dialog
|
d = self.page
|
||||||
d.custom_name.set('my custom keys')
|
d.custom_name.set('my custom keys')
|
||||||
d.bindingslist.delete(0, 'end')
|
d.bindingslist.delete(0, 'end')
|
||||||
d.bindingslist.insert(0, 'copy')
|
d.bindingslist.insert(0, 'copy')
|
||||||
|
@ -386,7 +391,7 @@ def test_keybinding(self):
|
||||||
|
|
||||||
def test_set_keys_type(self):
|
def test_set_keys_type(self):
|
||||||
eq = self.assertEqual
|
eq = self.assertEqual
|
||||||
d = dialog
|
d = self.page
|
||||||
del d.set_keys_type
|
del d.set_keys_type
|
||||||
|
|
||||||
# Builtin keyset selected.
|
# Builtin keyset selected.
|
||||||
|
@ -407,7 +412,7 @@ def test_set_keys_type(self):
|
||||||
|
|
||||||
def test_get_new_keys(self):
|
def test_get_new_keys(self):
|
||||||
eq = self.assertEqual
|
eq = self.assertEqual
|
||||||
d = dialog
|
d = self.page
|
||||||
orig_getkeysdialog = configdialog.GetKeysDialog
|
orig_getkeysdialog = configdialog.GetKeysDialog
|
||||||
gkd = configdialog.GetKeysDialog = Func(return_self=True)
|
gkd = configdialog.GetKeysDialog = Func(return_self=True)
|
||||||
gnkn = d.get_new_keys_name = Func()
|
gnkn = d.get_new_keys_name = Func()
|
||||||
|
@ -456,7 +461,7 @@ def test_get_new_keys(self):
|
||||||
def test_get_new_keys_name(self):
|
def test_get_new_keys_name(self):
|
||||||
orig_sectionname = configdialog.SectionName
|
orig_sectionname = configdialog.SectionName
|
||||||
sn = configdialog.SectionName = Func(return_self=True)
|
sn = configdialog.SectionName = Func(return_self=True)
|
||||||
d = dialog
|
d = self.page
|
||||||
|
|
||||||
sn.result = 'New Keys'
|
sn.result = 'New Keys'
|
||||||
self.assertEqual(d.get_new_keys_name(''), 'New Keys')
|
self.assertEqual(d.get_new_keys_name(''), 'New Keys')
|
||||||
|
@ -464,7 +469,7 @@ def test_get_new_keys_name(self):
|
||||||
configdialog.SectionName = orig_sectionname
|
configdialog.SectionName = orig_sectionname
|
||||||
|
|
||||||
def test_save_as_new_key_set(self):
|
def test_save_as_new_key_set(self):
|
||||||
d = dialog
|
d = self.page
|
||||||
gnkn = d.get_new_keys_name = Func()
|
gnkn = d.get_new_keys_name = Func()
|
||||||
d.keyset_source.set(True)
|
d.keyset_source.set(True)
|
||||||
|
|
||||||
|
@ -482,7 +487,7 @@ def test_save_as_new_key_set(self):
|
||||||
del d.get_new_keys_name
|
del d.get_new_keys_name
|
||||||
|
|
||||||
def test_on_bindingslist_select(self):
|
def test_on_bindingslist_select(self):
|
||||||
d = dialog
|
d = self.page
|
||||||
b = d.bindingslist
|
b = d.bindingslist
|
||||||
b.delete(0, 'end')
|
b.delete(0, 'end')
|
||||||
b.insert(0, 'copy')
|
b.insert(0, 'copy')
|
||||||
|
@ -504,7 +509,7 @@ def test_on_bindingslist_select(self):
|
||||||
|
|
||||||
def test_create_new_key_set_and_save_new_key_set(self):
|
def test_create_new_key_set_and_save_new_key_set(self):
|
||||||
eq = self.assertEqual
|
eq = self.assertEqual
|
||||||
d = dialog
|
d = self.page
|
||||||
|
|
||||||
# Use default as previously active keyset.
|
# Use default as previously active keyset.
|
||||||
d.keyset_source.set(True)
|
d.keyset_source.set(True)
|
||||||
|
@ -535,7 +540,7 @@ def test_create_new_key_set_and_save_new_key_set(self):
|
||||||
|
|
||||||
def test_load_keys_list(self):
|
def test_load_keys_list(self):
|
||||||
eq = self.assertEqual
|
eq = self.assertEqual
|
||||||
d = dialog
|
d = self.page
|
||||||
gks = idleConf.GetKeySet = Func()
|
gks = idleConf.GetKeySet = Func()
|
||||||
del d.load_keys_list
|
del d.load_keys_list
|
||||||
b = d.bindingslist
|
b = d.bindingslist
|
||||||
|
@ -578,11 +583,11 @@ def test_load_keys_list(self):
|
||||||
|
|
||||||
def test_delete_custom_keys(self):
|
def test_delete_custom_keys(self):
|
||||||
eq = self.assertEqual
|
eq = self.assertEqual
|
||||||
d = dialog
|
d = self.page
|
||||||
d.button_delete_custom_keys['state'] = NORMAL
|
d.button_delete_custom_keys['state'] = NORMAL
|
||||||
yesno = configdialog.tkMessageBox.askyesno = Func()
|
yesno = configdialog.tkMessageBox.askyesno = Func()
|
||||||
d.deactivate_current_config = Func()
|
dialog.deactivate_current_config = Func()
|
||||||
d.activate_config_changes = Func()
|
dialog.activate_config_changes = Func()
|
||||||
|
|
||||||
keyset_name = 'spam key set'
|
keyset_name = 'spam key set'
|
||||||
idleConf.userCfg['keys'].SetOption(keyset_name, 'name', 'value')
|
idleConf.userCfg['keys'].SetOption(keyset_name, 'name', 'value')
|
||||||
|
@ -598,8 +603,8 @@ def test_delete_custom_keys(self):
|
||||||
eq(yesno.called, 1)
|
eq(yesno.called, 1)
|
||||||
eq(keyspage[keyset_name], {'option': 'True'})
|
eq(keyspage[keyset_name], {'option': 'True'})
|
||||||
eq(idleConf.GetSectionList('user', 'keys'), ['spam key set'])
|
eq(idleConf.GetSectionList('user', 'keys'), ['spam key set'])
|
||||||
eq(d.deactivate_current_config.called, 0)
|
eq(dialog.deactivate_current_config.called, 0)
|
||||||
eq(d.activate_config_changes.called, 0)
|
eq(dialog.activate_config_changes.called, 0)
|
||||||
eq(d.set_keys_type.called, 0)
|
eq(d.set_keys_type.called, 0)
|
||||||
|
|
||||||
# Confirm deletion.
|
# Confirm deletion.
|
||||||
|
@ -610,11 +615,11 @@ def test_delete_custom_keys(self):
|
||||||
eq(idleConf.GetSectionList('user', 'keys'), [])
|
eq(idleConf.GetSectionList('user', 'keys'), [])
|
||||||
eq(d.custom_keyset_on['state'], DISABLED)
|
eq(d.custom_keyset_on['state'], DISABLED)
|
||||||
eq(d.custom_name.get(), '- no custom keys -')
|
eq(d.custom_name.get(), '- no custom keys -')
|
||||||
eq(d.deactivate_current_config.called, 1)
|
eq(dialog.deactivate_current_config.called, 1)
|
||||||
eq(d.activate_config_changes.called, 1)
|
eq(dialog.activate_config_changes.called, 1)
|
||||||
eq(d.set_keys_type.called, 1)
|
eq(d.set_keys_type.called, 1)
|
||||||
|
|
||||||
del d.activate_config_changes, d.deactivate_current_config
|
del dialog.activate_config_changes, dialog.deactivate_current_config
|
||||||
del configdialog.tkMessageBox.askyesno
|
del configdialog.tkMessageBox.askyesno
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
IDLE: Factor KeysPage(Frame) class from ConfigDialog. The slightly
|
||||||
|
modified tests continue to pass. Patch by Cheryl Sabella.
|
Loading…
Reference in New Issue