Commit e36d9f55 authored by Cheryl Sabella's avatar Cheryl Sabella Committed by Terry Jan Reedy

bpo-31205: IDLE: Factor KeysPage class from ConfigDialog (#3096)

  The slightly modified tests continue to pass.  Patch by Cheryl Sabella.
parent 1f512b9a
...@@ -92,9 +92,9 @@ class ConfigDialog(Toplevel): ...@@ -92,9 +92,9 @@ class ConfigDialog(Toplevel):
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 @@ class ConfigDialog(Toplevel): ...@@ -104,7 +104,7 @@ class ConfigDialog(Toplevel):
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 @@ class ConfigDialog(Toplevel): ...@@ -132,7 +132,7 @@ class ConfigDialog(Toplevel):
#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,863 +791,869 @@ class ConfigDialog(Toplevel): ...@@ -791,863 +791,869 @@ class ConfigDialog(Toplevel):
self.activate_config_changes() self.activate_config_changes()
self.set_theme_type() self.set_theme_type()
def deactivate_current_config(self):
"""Remove current key bindings.
def create_page_keys(self): Iterate over window instances defined in parent and remove
"""Return frame of widgets for Keys tab. the keybindings.
"""
# Before a config is saved, some cleanup of current
# config must be done - remove the previous keybindings.
win_instances = self.parent.instance_dict.keys()
for instance in win_instances:
instance.RemoveKeybindings()
Enable users to provisionally change both individual and sets of def activate_config_changes(self):
keybindings (shortcut keys). Except for features implemented as """Apply configuration changes to current windows.
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 Dynamically update the current parent window instances
lists and calls load_keys_list for the current keyset. with some of the configuration changes.
Radiobuttons builtin_keyset_on and custom_keyset_on toggle var """
keyset_source, which controls if the current set of keybindings win_instances = self.parent.instance_dict.keys()
are from a builtin or custom keyset. DynOptionMenus builtinlist for instance in win_instances:
and customlist contain lists of the builtin and custom keysets, instance.ResetColorizer()
respectively, and the current item from each list is stored in instance.ResetFont()
vars builtin_name and custom_name. instance.set_notabs_indentwidth()
instance.ApplyKeybindings()
instance.reset_help_menu_entries()
Button delete_custom_keys invokes delete_custom_keys() to delete def create_page_extensions(self):
a custom keyset from idleConf.userCfg['keys'] and changes. Button """Part of the config dialog used for configuring IDLE extensions.
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 This code is generic - it works for any and all IDLE extensions.
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 IDLE extensions save their configuration options using idleConf.
button_new_keys, and clicking button_new_keys calls function This code reads the current configuration using idleConf, supplies a
get_new_keys(). Function get_new_keys() gets the key mappings from the GUI interface to change the configuration values, and saves the
current keyset for the binding event item that was selected. The changes using idleConf.
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: Not all changes take effect immediately - some may require restarting IDLE.
keybinding: Action/key bindings. This depends on each extension's implementation.
Methods: All values are treated as text, and it is up to the user to supply
load_keys_list: Reload active set. reasonable values. The only exception to this are the 'enable*' options,
create_new_key_set: Combine active keyset and changes. which are boolean, and can be toggled with a True/False button.
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 Methods:
frame_key_sets: LabelFrame load_extensions:
frames[0]: Frame extension_selected: Handle selection from list.
(*)builtin_keyset_on: Radiobutton - var keyset_source create_extension_frame: Hold widgets for one extension.
(*)custom_keyset_on: Radiobutton - var keyset_source set_extension_value: Set in userCfg['extensions'].
(*)builtinlist: DynOptionMenu - var builtin_name, save_all_changed_extensions: Call extension page Save().
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 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 = Frame(self.note)
frame_custom = LabelFrame( self.ext_defaultCfg = idleConf.defaultCfg['extensions']
frame, borderwidth=2, relief=GROOVE, self.ext_userCfg = idleConf.userCfg['extensions']
text=' Custom Key Bindings ') self.is_int = self.register(is_int)
frame_key_sets = LabelFrame( self.load_extensions()
frame, borderwidth=2, relief=GROOVE, text=' Key Set ') # Create widgets - a listbox shows all available extensions, with the
#frame_custom # controls for the extension selected in the listbox to the right.
frame_target = Frame(frame_custom) self.extension_names = StringVar(self)
target_title = Label(frame_target, text='Action - Key(s)') frame.rowconfigure(0, weight=1)
scroll_target_y = Scrollbar(frame_target) frame.columnconfigure(2, weight=1)
scroll_target_x = Scrollbar(frame_target, orient=HORIZONTAL) self.extension_list = Listbox(frame, listvariable=self.extension_names,
self.bindingslist = Listbox( selectmode='browse')
frame_target, takefocus=FALSE, exportselection=FALSE) self.extension_list.bind('<<ListboxSelect>>', self.extension_selected)
self.bindingslist.bind('<ButtonRelease-1>', scroll = Scrollbar(frame, command=self.extension_list.yview)
self.on_bindingslist_select) self.extension_list.yscrollcommand=scroll.set
scroll_target_y['command'] = self.bindingslist.yview self.details_frame = LabelFrame(frame, width=250, height=250)
scroll_target_x['command'] = self.bindingslist.xview self.extension_list.grid(column=0, row=0, sticky='nws')
self.bindingslist['yscrollcommand'] = scroll_target_y.set scroll.grid(column=1, row=0, sticky='ns')
self.bindingslist['xscrollcommand'] = scroll_target_x.set self.details_frame.grid(column=2, row=0, sticky='nsew', padx=[10, 0])
self.button_new_keys = Button( frame.configure(padx=10, pady=10)
frame_custom, text='Get New Keys for Selection', self.config_frame = {}
command=self.get_new_keys, state=DISABLED) self.current_extension = None
#frame_key_sets
frames = [Frame(frame_key_sets, padx=2, pady=2, borderwidth=0) self.outerframe = self # TEMPORARY
for i in range(2)] self.tabbed_page_set = self.extension_list # TEMPORARY
self.builtin_keyset_on = Radiobutton(
frames[0], variable=self.keyset_source, value=1, # Create the frame holding controls for each extension.
command=self.set_keys_type, text='Use a Built-in Key Set') ext_names = ''
self.custom_keyset_on = Radiobutton( for ext_name in sorted(self.extensions):
frames[0], variable=self.keyset_source, value=0, self.create_extension_frame(ext_name)
command=self.set_keys_type, text='Use a Custom Key Set') ext_names = ext_names + '{' + ext_name + '} '
self.builtinlist = DynOptionMenu( self.extension_names.set(ext_names)
frames[0], self.builtin_name, None, command=None) self.extension_list.selection_set(0)
self.customlist = DynOptionMenu( self.extension_selected(None)
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 return frame
def load_key_cfg(self): def load_extensions(self):
"Load current configuration settings for the keybinding options." "Fill self.extensions with data from the default and user configs."
# Set current keys type radiobutton. self.extensions = {}
self.keyset_source.set(idleConf.GetOption( for ext_name in idleConf.GetExtensions(active_only=False):
'main', 'Keys', 'default', type='bool', default=1)) self.extensions[ext_name] = []
# 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): for ext_name in self.extensions:
"Process selection of builtin key set." opt_list = sorted(self.ext_defaultCfg.GetOptionList(ext_name))
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): # Bring 'enable' options to the beginning of the list.
"Process selection of custom key set." enables = [opt_name for opt_name in opt_list
value = self.custom_name.get() if opt_name.startswith('enable')]
if value != '- no custom keys -': for opt_name in enables:
changes.add_option('main', 'Keys', 'name', value) opt_list.remove(opt_name)
self.load_keys_list(value) opt_list = enables + opt_list
def var_changed_keyset_source(self, *params): for opt_name in opt_list:
"Process toggle between builtin key set and custom key set." def_str = self.ext_defaultCfg.Get(
value = self.keyset_source.get() ext_name, opt_name, raw=True)
changes.add_option('main', 'Keys', 'default', value) try:
if value: def_obj = {'True':True, 'False':False}[def_str]
self.var_changed_builtin_name() opt_type = 'bool'
else: except KeyError:
self.var_changed_custom_name() try:
def_obj = int(def_str)
opt_type = 'int'
except ValueError:
def_obj = def_str
opt_type = None
try:
value = self.ext_userCfg.Get(
ext_name, opt_name, type=opt_type, raw=True,
default=def_obj)
except ValueError: # Need this until .Get fixed.
value = def_obj # Bad values overwritten by entry.
var = StringVar(self)
var.set(str(value))
def var_changed_keybinding(self, *params): self.extensions[ext_name].append({'name': opt_name,
"Store change to a keybinding." 'type': opt_type,
value = self.keybinding.get() 'default': def_str,
key_set = self.custom_name.get() 'value': value,
event = self.bindingslist.get(ANCHOR).split()[0] 'var': var,
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): def extension_selected(self, event):
"Set available screen options based on builtin or custom key set." "Handle selection of an extension from the list."
if self.keyset_source.get(): newsel = self.extension_list.curselection()
self.builtinlist['state'] = NORMAL if newsel:
self.customlist['state'] = DISABLED newsel = self.extension_list.get(newsel)
self.button_delete_custom_keys['state'] = DISABLED if newsel is None or newsel != self.current_extension:
else: if self.current_extension:
self.builtinlist['state'] = DISABLED self.details_frame.config(text='')
self.custom_keyset_on['state'] = NORMAL self.config_frame[self.current_extension].grid_forget()
self.customlist['state'] = NORMAL self.current_extension = None
self.button_delete_custom_keys['state'] = NORMAL if newsel:
self.details_frame.config(text=newsel)
self.config_frame[newsel].grid(column=0, row=0, sticky='nsew')
self.current_extension = newsel
def get_new_keys(self): def create_extension_frame(self, ext_name):
"""Handle event to change key binding for selected line. """Create a frame holding the widgets to configure one extension"""
f = VerticalScrolledFrame(self.details_frame, height=250, width=250)
self.config_frame[ext_name] = f
entry_area = f.interior
# Create an entry for each configuration option.
for row, opt in enumerate(self.extensions[ext_name]):
# Create a row with a label and entry/checkbutton.
label = Label(entry_area, text=opt['name'])
label.grid(row=row, column=0, sticky=NW)
var = opt['var']
if opt['type'] == 'bool':
Checkbutton(entry_area, textvariable=var, variable=var,
onvalue='True', offvalue='False',
indicatoron=FALSE, selectcolor='', width=8
).grid(row=row, column=1, sticky=W, padx=7)
elif opt['type'] == 'int':
Entry(entry_area, textvariable=var, validate='key',
validatecommand=(self.is_int, '%P')
).grid(row=row, column=1, sticky=NSEW, padx=7)
A selection of a key/binding in the list of current else:
bindings pops up a dialog to enter a new binding. If Entry(entry_area, textvariable=var
the current key set is builtin and a binding has ).grid(row=row, column=1, sticky=NSEW, padx=7)
changed, then a name for a custom key set needs to be return
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): def set_extension_value(self, section, opt):
"Return new key set name from query popup." """Return True if the configuration was added or changed.
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): If the value is the same as the default, then remove it
"Prompt for name of new key set and save changes using that name." from user config file.
new_keys_name = self.get_new_keys_name('New Key Set Name:') """
if new_keys_name: name = opt['name']
self.create_new_key_set(new_keys_name) default = opt['default']
value = opt['var'].get().strip() or default
opt['var'].set(value)
# if self.defaultCfg.has_section(section):
# Currently, always true; if not, indent to return.
if (value == default):
return self.ext_userCfg.RemoveOption(section, name)
# Set the option.
return self.ext_userCfg.SetOption(section, name, value)
def on_bindingslist_select(self, event): def save_all_changed_extensions(self):
"Activate button to assign new keys to selected action." """Save configuration changes to the user config file.
self.button_new_keys['state'] = NORMAL
def create_new_key_set(self, new_key_set_name): Attributes accessed:
"""Create a new custom key set with the given name. extensions
Copy the bindings/keys from the previously active keyset Methods:
to the new keyset and activate the new custom keyset. set_extension_value
""" """
if self.keyset_source.get(): has_changes = False
prev_key_set_name = self.builtin_name.get() for ext_name in self.extensions:
else: options = self.extensions[ext_name]
prev_key_set_name = self.custom_name.get() for opt in options:
prev_keys = idleConf.GetCoreKeys(prev_key_set_name) if self.set_extension_value(ext_name, opt):
new_keys = {} has_changes = True
for event in prev_keys: # Add key set to changed items. if has_changes:
event_name = event[2:-2] # Trim off the angle brackets. self.ext_userCfg.Save()
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. # class TabPage(Frame): # A template for Page classes.
""" # def __init__(self, master):
reselect = False # super().__init__(master)
if self.bindingslist.curselection(): # self.create_page_tab()
reselect = True # self.load_tab_cfg()
list_index = self.bindingslist.index(ANCHOR) # def create_page_tab(self):
keyset = idleConf.GetKeySet(keyset_name) # # Define tk vars and register var and callback with tracers.
bind_names = list(keyset.keys()) # # Create subframes and widgets.
bind_names.sort() # # Pack widgets.
self.bindingslist.delete(0, END) # def load_tab_cfg(self):
for bind_name in bind_names: # # Initialize widgets with data from idleConf.
key = ' '.join(keyset[bind_name]) # def var_changed_var_name():
bind_name = bind_name[2:-2] # Trim off the angle brackets. # # For each tk var that needs other than default callback.
if keyset_name in changes['keys']: # def other_methods():
# Handle any unsaved changes to this key set. # # Define tab-specific behavior.
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 class FontPage(Frame):
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 __init__(self, master, highpage):
"""Remove current key bindings. super().__init__(master)
self.highlight_sample = highpage.highlight_sample
self.create_page_font_tab()
self.load_font_cfg()
self.load_tab_cfg()
Iterate over window instances defined in parent and remove def create_page_font_tab(self):
the keybindings. """Return frame of widgets for Font/Tabs tab.
"""
# Before a config is saved, some cleanup of current
# config must be done - remove the previous keybindings.
win_instances = self.parent.instance_dict.keys()
for instance in win_instances:
instance.RemoveKeybindings()
def activate_config_changes(self): Fonts: Enable users to provisionally change font face, size, or
"""Apply configuration changes to current windows. boldness and to see the consequence of proposed choices. Each
action set 3 options in changes structuree and changes the
corresponding aspect of the font sample on this page and
highlight sample on highlight page.
Dynamically update the current parent window instances Function load_font_cfg initializes font vars and widgets from
with some of the configuration changes. idleConf entries and tk.
"""
win_instances = self.parent.instance_dict.keys()
for instance in win_instances:
instance.ResetColorizer()
instance.ResetFont()
instance.set_notabs_indentwidth()
instance.ApplyKeybindings()
instance.reset_help_menu_entries()
def create_page_extensions(self): Fontlist: mouse button 1 click or up or down key invoke
"""Part of the config dialog used for configuring IDLE extensions. on_fontlist_select(), which sets var font_name.
This code is generic - it works for any and all IDLE extensions. Sizelist: clicking the menubutton opens the dropdown menu. A
mouse button 1 click or return key sets var font_size.
IDLE extensions save their configuration options using idleConf. Bold_toggle: clicking the box toggles var font_bold.
This code reads the current configuration using idleConf, supplies a
GUI interface to change the configuration values, and saves the
changes using idleConf.
Not all changes take effect immediately - some may require restarting IDLE. Changing any of the font vars invokes var_changed_font, which
This depends on each extension's implementation. adds all 3 font options to changes and calls set_samples.
Set_samples applies a new font constructed from the font vars to
font_sample and to highlight_sample on the hightlight page.
All values are treated as text, and it is up to the user to supply Tabs: Enable users to change spaces entered for indent tabs.
reasonable values. The only exception to this are the 'enable*' options, Changing indent_scale value with the mouse sets Var space_num,
which are boolean, and can be toggled with a True/False button. which invokes the default callback to add an entry to
changes. Load_tab_cfg initializes space_num to default.
Methods: Widgets for FontPage(Frame): (*) widgets bound to self
load_extensions: frame_font: LabelFrame
extension_selected: Handle selection from list. frame_font_name: Frame
create_extension_frame: Hold widgets for one extension. font_name_title: Label
set_extension_value: Set in userCfg['extensions']. (*)fontlist: ListBox - font_name
save_all_changed_extensions: Call extension page Save(). scroll_font: Scrollbar
frame_font_param: Frame
font_size_title: Label
(*)sizelist: DynOptionMenu - font_size
(*)bold_toggle: Checkbutton - font_bold
frame_font_sample: Frame
(*)font_sample: Label
frame_indent: LabelFrame
indent_title: Label
(*)indent_scale: Scale - space_num
""" """
parent = self.parent self.font_name = tracers.add(StringVar(self), self.var_changed_font)
frame = Frame(self.note) self.font_size = tracers.add(StringVar(self), self.var_changed_font)
self.ext_defaultCfg = idleConf.defaultCfg['extensions'] self.font_bold = tracers.add(BooleanVar(self), self.var_changed_font)
self.ext_userCfg = idleConf.userCfg['extensions'] self.space_num = tracers.add(IntVar(self), ('main', 'Indent', 'num-spaces'))
self.is_int = self.register(is_int)
self.load_extensions()
# Create widgets - a listbox shows all available extensions, with the
# controls for the extension selected in the listbox to the right.
self.extension_names = StringVar(self)
frame.rowconfigure(0, weight=1)
frame.columnconfigure(2, weight=1)
self.extension_list = Listbox(frame, listvariable=self.extension_names,
selectmode='browse')
self.extension_list.bind('<<ListboxSelect>>', self.extension_selected)
scroll = Scrollbar(frame, command=self.extension_list.yview)
self.extension_list.yscrollcommand=scroll.set
self.details_frame = LabelFrame(frame, width=250, height=250)
self.extension_list.grid(column=0, row=0, sticky='nws')
scroll.grid(column=1, row=0, sticky='ns')
self.details_frame.grid(column=2, row=0, sticky='nsew', padx=[10, 0])
frame.configure(padx=10, pady=10)
self.config_frame = {}
self.current_extension = None
self.outerframe = self # TEMPORARY # Create widgets:
self.tabbed_page_set = self.extension_list # TEMPORARY # body and body section frames.
frame_font = LabelFrame(
self, borderwidth=2, relief=GROOVE, text=' Base Editor Font ')
frame_indent = LabelFrame(
self, borderwidth=2, relief=GROOVE, text=' Indentation Width ')
# frame_font.
frame_font_name = Frame(frame_font)
frame_font_param = Frame(frame_font)
font_name_title = Label(
frame_font_name, justify=LEFT, text='Font Face :')
self.fontlist = Listbox(frame_font_name, height=5,
takefocus=True, exportselection=FALSE)
self.fontlist.bind('<ButtonRelease-1>', self.on_fontlist_select)
self.fontlist.bind('<KeyRelease-Up>', self.on_fontlist_select)
self.fontlist.bind('<KeyRelease-Down>', self.on_fontlist_select)
scroll_font = Scrollbar(frame_font_name)
scroll_font.config(command=self.fontlist.yview)
self.fontlist.config(yscrollcommand=scroll_font.set)
font_size_title = Label(frame_font_param, text='Size :')
self.sizelist = DynOptionMenu(frame_font_param, self.font_size, None)
self.bold_toggle = Checkbutton(
frame_font_param, variable=self.font_bold,
onvalue=1, offvalue=0, text='Bold')
frame_font_sample = Frame(frame_font, relief=SOLID, borderwidth=1)
temp_font = tkFont.Font(self, ('courier', 10, 'normal'))
self.font_sample = Label(
frame_font_sample, justify=LEFT, font=temp_font,
text='AaBbCcDdEe\nFfGgHhIiJj\n1234567890\n#:+=(){}[]')
# frame_indent.
indent_title = Label(
frame_indent, justify=LEFT,
text='Python Standard: 4 Spaces!')
self.indent_scale = Scale(
frame_indent, variable=self.space_num,
orient='horizontal', tickinterval=2, from_=2, to=16)
# Create the frame holding controls for each extension. # Pack widgets:
ext_names = '' # body.
for ext_name in sorted(self.extensions): frame_font.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH)
self.create_extension_frame(ext_name) frame_indent.pack(side=LEFT, padx=5, pady=5, fill=Y)
ext_names = ext_names + '{' + ext_name + '} ' # frame_font.
self.extension_names.set(ext_names) frame_font_name.pack(side=TOP, padx=5, pady=5, fill=X)
self.extension_list.selection_set(0) frame_font_param.pack(side=TOP, padx=5, pady=5, fill=X)
self.extension_selected(None) font_name_title.pack(side=TOP, anchor=W)
self.fontlist.pack(side=LEFT, expand=TRUE, fill=X)
scroll_font.pack(side=LEFT, fill=Y)
font_size_title.pack(side=LEFT, anchor=W)
self.sizelist.pack(side=LEFT, anchor=W)
self.bold_toggle.pack(side=LEFT, anchor=W, padx=20)
frame_font_sample.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
self.font_sample.pack(expand=TRUE, fill=BOTH)
# frame_indent.
frame_indent.pack(side=TOP, fill=X)
indent_title.pack(side=TOP, anchor=W, padx=5)
self.indent_scale.pack(side=TOP, padx=5, fill=X)
return frame def load_font_cfg(self):
"""Load current configuration settings for the font options.
def load_extensions(self): Retrieve current font with idleConf.GetFont and font families
"Fill self.extensions with data from the default and user configs." from tk. Setup fontlist and set font_name. Setup sizelist,
self.extensions = {} which sets font_size. Set font_bold. Call set_samples.
for ext_name in idleConf.GetExtensions(active_only=False): """
self.extensions[ext_name] = [] configured_font = idleConf.GetFont(self, 'main', 'EditorWindow')
font_name = configured_font[0].lower()
font_size = configured_font[1]
font_bold = configured_font[2]=='bold'
for ext_name in self.extensions: # Set editor font selection list and font_name.
opt_list = sorted(self.ext_defaultCfg.GetOptionList(ext_name)) fonts = list(tkFont.families(self))
fonts.sort()
# Bring 'enable' options to the beginning of the list. for font in fonts:
enables = [opt_name for opt_name in opt_list self.fontlist.insert(END, font)
if opt_name.startswith('enable')] self.font_name.set(font_name)
for opt_name in enables: lc_fonts = [s.lower() for s in fonts]
opt_list.remove(opt_name) try:
opt_list = enables + opt_list current_font_index = lc_fonts.index(font_name)
self.fontlist.see(current_font_index)
for opt_name in opt_list: self.fontlist.select_set(current_font_index)
def_str = self.ext_defaultCfg.Get( self.fontlist.select_anchor(current_font_index)
ext_name, opt_name, raw=True) self.fontlist.activate(current_font_index)
try: except ValueError:
def_obj = {'True':True, 'False':False}[def_str] pass
opt_type = 'bool' # Set font size dropdown.
except KeyError: self.sizelist.SetMenu(('7', '8', '9', '10', '11', '12', '13', '14',
try: '16', '18', '20', '22', '25', '29', '34', '40'),
def_obj = int(def_str) font_size)
opt_type = 'int' # Set font weight.
except ValueError: self.font_bold.set(font_bold)
def_obj = def_str self.set_samples()
opt_type = None
try:
value = self.ext_userCfg.Get(
ext_name, opt_name, type=opt_type, raw=True,
default=def_obj)
except ValueError: # Need this until .Get fixed.
value = def_obj # Bad values overwritten by entry.
var = StringVar(self)
var.set(str(value))
self.extensions[ext_name].append({'name': opt_name, def var_changed_font(self, *params):
'type': opt_type, """Store changes to font attributes.
'default': def_str,
'value': value,
'var': var,
})
def extension_selected(self, event): When one font attribute changes, save them all, as they are
"Handle selection of an extension from the list." not independent from each other. In particular, when we are
newsel = self.extension_list.curselection() overriding the default font, we need to write out everything.
if newsel: """
newsel = self.extension_list.get(newsel) value = self.font_name.get()
if newsel is None or newsel != self.current_extension: changes.add_option('main', 'EditorWindow', 'font', value)
if self.current_extension: value = self.font_size.get()
self.details_frame.config(text='') changes.add_option('main', 'EditorWindow', 'font-size', value)
self.config_frame[self.current_extension].grid_forget() value = self.font_bold.get()
self.current_extension = None changes.add_option('main', 'EditorWindow', 'font-bold', value)
if newsel: self.set_samples()
self.details_frame.config(text=newsel)
self.config_frame[newsel].grid(column=0, row=0, sticky='nsew')
self.current_extension = newsel
def create_extension_frame(self, ext_name): def on_fontlist_select(self, event):
"""Create a frame holding the widgets to configure one extension""" """Handle selecting a font from the list.
f = VerticalScrolledFrame(self.details_frame, height=250, width=250)
self.config_frame[ext_name] = f
entry_area = f.interior
# Create an entry for each configuration option.
for row, opt in enumerate(self.extensions[ext_name]):
# Create a row with a label and entry/checkbutton.
label = Label(entry_area, text=opt['name'])
label.grid(row=row, column=0, sticky=NW)
var = opt['var']
if opt['type'] == 'bool':
Checkbutton(entry_area, textvariable=var, variable=var,
onvalue='True', offvalue='False',
indicatoron=FALSE, selectcolor='', width=8
).grid(row=row, column=1, sticky=W, padx=7)
elif opt['type'] == 'int':
Entry(entry_area, textvariable=var, validate='key',
validatecommand=(self.is_int, '%P')
).grid(row=row, column=1, sticky=NSEW, padx=7)
else: Event can result from either mouse click or Up or Down key.
Entry(entry_area, textvariable=var Set font_name and example displays to selection.
).grid(row=row, column=1, sticky=NSEW, padx=7) """
return font = self.fontlist.get(
ACTIVE if event.type.name == 'KeyRelease' else ANCHOR)
self.font_name.set(font.lower())
def set_extension_value(self, section, opt): def set_samples(self, event=None):
"""Return True if the configuration was added or changed. """Update update both screen samples with the font settings.
If the value is the same as the default, then remove it Called on font initialization and change events.
from user config file. Accesses font_name, font_size, and font_bold Variables.
Updates font_sample and hightlight page highlight_sample.
""" """
name = opt['name'] font_name = self.font_name.get()
default = opt['default'] font_weight = tkFont.BOLD if self.font_bold.get() else tkFont.NORMAL
value = opt['var'].get().strip() or default new_font = (font_name, self.font_size.get(), font_weight)
opt['var'].set(value) self.font_sample['font'] = new_font
# if self.defaultCfg.has_section(section): self.highlight_sample['font'] = new_font
# Currently, always true; if not, indent to return.
if (value == default):
return self.ext_userCfg.RemoveOption(section, name)
# Set the option.
return self.ext_userCfg.SetOption(section, name, value)
def save_all_changed_extensions(self):
"""Save configuration changes to the user config file.
Attributes accessed: def load_tab_cfg(self):
extensions """Load current configuration settings for the tab options.
Methods: Attributes updated:
set_extension_value space_num: Set to value from idleConf.
""" """
has_changes = False # Set indent sizes.
for ext_name in self.extensions: space_num = idleConf.GetOption(
options = self.extensions[ext_name] 'main', 'Indent', 'num-spaces', default=4, type='int')
for opt in options: self.space_num.set(space_num)
if self.set_extension_value(ext_name, opt):
has_changes = True
if has_changes:
self.ext_userCfg.Save()
# class TabPage(Frame): # A template for Page classes. def var_changed_space_num(self, *params):
# def __init__(self, master): "Store change to indentation size."
# super().__init__(master) value = self.space_num.get()
# self.create_page_tab() changes.add_option('main', 'Indent', 'num-spaces', value)
# self.load_tab_cfg()
# def create_page_tab(self):
# # Define tk vars and register var and callback with tracers.
# # Create subframes and widgets.
# # Pack widgets.
# def load_tab_cfg(self):
# # Initialize widgets with data from idleConf.
# def var_changed_var_name():
# # For each tk var that needs other than default callback.
# def other_methods():
# # Define tab-specific behavior.
class FontPage(Frame): class KeysPage(Frame):
def __init__(self, master, highpage): def __init__(self, master):
super().__init__(master) super().__init__(master)
self.highlight_sample = highpage.highlight_sample self.cd = master.master
self.create_page_font_tab() self.create_page_keys()
self.load_font_cfg() self.load_key_cfg()
self.load_tab_cfg()
def create_page_font_tab(self): def create_page_keys(self):
"""Return frame of widgets for Font/Tabs tab. """Return frame of widgets for Keys tab.
Fonts: Enable users to provisionally change font face, size, or Enable users to provisionally change both individual and sets of
boldness and to see the consequence of proposed choices. Each keybindings (shortcut keys). Except for features implemented as
action set 3 options in changes structuree and changes the extensions, keybindings are stored in complete sets called
corresponding aspect of the font sample on this page and keysets. Built-in keysets in idlelib/config-keys.def are fixed
highlight sample on highlight page. 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_font_cfg initializes font vars and widgets from Function load_key_cfg() initializes tk variables and keyset
idleConf entries and tk. 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.
Fontlist: mouse button 1 click or up or down key invoke Button delete_custom_keys invokes delete_custom_keys() to delete
on_fontlist_select(), which sets var font_name. 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'].
Sizelist: clicking the menubutton opens the dropdown menu. A Listbox bindingslist contains all of the keybindings for the
mouse button 1 click or return key sets var font_size. 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.
Bold_toggle: clicking the box toggles var font_bold. 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.
Changing any of the font vars invokes var_changed_font, which Tk Variables:
adds all 3 font options to changes and calls set_samples. keybinding: Action/key bindings.
Set_samples applies a new font constructed from the font vars to
font_sample and to highlight_sample on the hightlight page.
Tabs: Enable users to change spaces entered for indent tabs. Methods:
Changing indent_scale value with the mouse sets Var space_num, load_keys_list: Reload active set.
which invokes the default callback to add an entry to create_new_key_set: Combine active keyset and changes.
changes. Load_tab_cfg initializes space_num to default. 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 FontPage(Frame): (*) widgets bound to self Widgets for KeysPage(frame): (*) widgets bound to self
frame_font: LabelFrame frame_key_sets: LabelFrame
frame_font_name: Frame frames[0]: Frame
font_name_title: Label (*)builtin_keyset_on: Radiobutton - var keyset_source
(*)fontlist: ListBox - font_name (*)custom_keyset_on: Radiobutton - var keyset_source
scroll_font: Scrollbar (*)builtinlist: DynOptionMenu - var builtin_name,
frame_font_param: Frame func keybinding_selected
font_size_title: Label (*)customlist: DynOptionMenu - var custom_name,
(*)sizelist: DynOptionMenu - font_size func keybinding_selected
(*)bold_toggle: Checkbutton - font_bold (*)keys_message: Label
frame_font_sample: Frame frames[1]: Frame
(*)font_sample: Label (*)button_delete_custom_keys: Button - delete_custom_keys
frame_indent: LabelFrame (*)button_save_custom_keys: Button - save_as_new_key_set
indent_title: Label frame_custom: LabelFrame
(*)indent_scale: Scale - space_num 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.font_name = tracers.add(StringVar(self), self.var_changed_font) self.builtin_name = tracers.add(
self.font_size = tracers.add(StringVar(self), self.var_changed_font) StringVar(self), self.var_changed_builtin_name)
self.font_bold = tracers.add(BooleanVar(self), self.var_changed_font) self.custom_name = tracers.add(
self.space_num = tracers.add(IntVar(self), ('main', 'Indent', 'num-spaces')) 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: # Create widgets:
# body and body section frames. # body and section frames.
frame_font = LabelFrame( frame_custom = LabelFrame(
self, borderwidth=2, relief=GROOVE, text=' Base Editor Font ') self, borderwidth=2, relief=GROOVE,
frame_indent = LabelFrame( text=' Custom Key Bindings ')
self, borderwidth=2, relief=GROOVE, text=' Indentation Width ') frame_key_sets = LabelFrame(
# frame_font. self, borderwidth=2, relief=GROOVE, text=' Key Set ')
frame_font_name = Frame(frame_font) # frame_custom.
frame_font_param = Frame(frame_font) frame_target = Frame(frame_custom)
font_name_title = Label( target_title = Label(frame_target, text='Action - Key(s)')
frame_font_name, justify=LEFT, text='Font Face :') scroll_target_y = Scrollbar(frame_target)
self.fontlist = Listbox(frame_font_name, height=5, scroll_target_x = Scrollbar(frame_target, orient=HORIZONTAL)
takefocus=True, exportselection=FALSE) self.bindingslist = Listbox(
self.fontlist.bind('<ButtonRelease-1>', self.on_fontlist_select) frame_target, takefocus=FALSE, exportselection=FALSE)
self.fontlist.bind('<KeyRelease-Up>', self.on_fontlist_select) self.bindingslist.bind('<ButtonRelease-1>',
self.fontlist.bind('<KeyRelease-Down>', self.on_fontlist_select) self.on_bindingslist_select)
scroll_font = Scrollbar(frame_font_name) scroll_target_y['command'] = self.bindingslist.yview
scroll_font.config(command=self.fontlist.yview) scroll_target_x['command'] = self.bindingslist.xview
self.fontlist.config(yscrollcommand=scroll_font.set) self.bindingslist['yscrollcommand'] = scroll_target_y.set
font_size_title = Label(frame_font_param, text='Size :') self.bindingslist['xscrollcommand'] = scroll_target_x.set
self.sizelist = DynOptionMenu(frame_font_param, self.font_size, None) self.button_new_keys = Button(
self.bold_toggle = Checkbutton( frame_custom, text='Get New Keys for Selection',
frame_font_param, variable=self.font_bold, command=self.get_new_keys, state=DISABLED)
onvalue=1, offvalue=0, text='Bold') # frame_key_sets.
frame_font_sample = Frame(frame_font, relief=SOLID, borderwidth=1) frames = [Frame(frame_key_sets, padx=2, pady=2, borderwidth=0)
temp_font = tkFont.Font(self, ('courier', 10, 'normal')) for i in range(2)]
self.font_sample = Label( self.builtin_keyset_on = Radiobutton(
frame_font_sample, justify=LEFT, font=temp_font, frames[0], variable=self.keyset_source, value=1,
text='AaBbCcDdEe\nFfGgHhIiJj\n1234567890\n#:+=(){}[]') command=self.set_keys_type, text='Use a Built-in Key Set')
# frame_indent. self.custom_keyset_on = Radiobutton(
indent_title = Label( frames[0], variable=self.keyset_source, value=0,
frame_indent, justify=LEFT, command=self.set_keys_type, text='Use a Custom Key Set')
text='Python Standard: 4 Spaces!') self.builtinlist = DynOptionMenu(
self.indent_scale = Scale( frames[0], self.builtin_name, None, command=None)
frame_indent, variable=self.space_num, self.customlist = DynOptionMenu(
orient='horizontal', tickinterval=2, from_=2, to=16) 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)
# Pack widgets: def set_keys_type(self):
# body. "Set available screen options based on builtin or custom key set."
frame_font.pack(side=LEFT, padx=5, pady=5, expand=TRUE, fill=BOTH) if self.keyset_source.get():
frame_indent.pack(side=LEFT, padx=5, pady=5, fill=Y) self.builtinlist['state'] = NORMAL
# frame_font. self.customlist['state'] = DISABLED
frame_font_name.pack(side=TOP, padx=5, pady=5, fill=X) self.button_delete_custom_keys['state'] = DISABLED
frame_font_param.pack(side=TOP, padx=5, pady=5, fill=X) else:
font_name_title.pack(side=TOP, anchor=W) self.builtinlist['state'] = DISABLED
self.fontlist.pack(side=LEFT, expand=TRUE, fill=X) self.custom_keyset_on['state'] = NORMAL
scroll_font.pack(side=LEFT, fill=Y) self.customlist['state'] = NORMAL
font_size_title.pack(side=LEFT, anchor=W) self.button_delete_custom_keys['state'] = NORMAL
self.sizelist.pack(side=LEFT, anchor=W)
self.bold_toggle.pack(side=LEFT, anchor=W, padx=20)
frame_font_sample.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
self.font_sample.pack(expand=TRUE, fill=BOTH)
# frame_indent.
frame_indent.pack(side=TOP, fill=X)
indent_title.pack(side=TOP, anchor=W, padx=5)
self.indent_scale.pack(side=TOP, padx=5, fill=X)
def load_font_cfg(self): def get_new_keys(self):
"""Load current configuration settings for the font options. """Handle event to change key binding for selected line.
Retrieve current font with idleConf.GetFont and font families A selection of a key/binding in the list of current
from tk. Setup fontlist and set font_name. Setup sizelist, bindings pops up a dialog to enter a new binding. If
which sets font_size. Set font_bold. Call set_samples. 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.
""" """
configured_font = idleConf.GetFont(self, 'main', 'EditorWindow') list_index = self.bindingslist.index(ANCHOR)
font_name = configured_font[0].lower() binding = self.bindingslist.get(list_index)
font_size = configured_font[1] bind_name = binding.split()[0]
font_bold = configured_font[2]=='bold' 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)
# Set editor font selection list and font_name. def get_new_keys_name(self, message):
fonts = list(tkFont.families(self)) "Return new key set name from query popup."
fonts.sort() used_names = (idleConf.GetSectionList('user', 'keys') +
for font in fonts: idleConf.GetSectionList('default', 'keys'))
self.fontlist.insert(END, font) new_keyset = SectionName(
self.font_name.set(font_name) self, 'New Custom Key Set', message, used_names).result
lc_fonts = [s.lower() for s in fonts] return new_keyset
try:
current_font_index = lc_fonts.index(font_name)
self.fontlist.see(current_font_index)
self.fontlist.select_set(current_font_index)
self.fontlist.select_anchor(current_font_index)
self.fontlist.activate(current_font_index)
except ValueError:
pass
# Set font size dropdown.
self.sizelist.SetMenu(('7', '8', '9', '10', '11', '12', '13', '14',
'16', '18', '20', '22', '25', '29', '34', '40'),
font_size)
# Set font weight.
self.font_bold.set(font_bold)
self.set_samples()
def var_changed_font(self, *params): def save_as_new_key_set(self):
"""Store changes to font attributes. "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)
When one font attribute changes, save them all, as they are def on_bindingslist_select(self, event):
not independent from each other. In particular, when we are "Activate button to assign new keys to selected action."
overriding the default font, we need to write out everything. self.button_new_keys['state'] = NORMAL
"""
value = self.font_name.get()
changes.add_option('main', 'EditorWindow', 'font', value)
value = self.font_size.get()
changes.add_option('main', 'EditorWindow', 'font-size', value)
value = self.font_bold.get()
changes.add_option('main', 'EditorWindow', 'font-bold', value)
self.set_samples()
def on_fontlist_select(self, event): def create_new_key_set(self, new_key_set_name):
"""Handle selecting a font from the list. """Create a new custom key set with the given name.
Event can result from either mouse click or Up or Down key. Copy the bindings/keys from the previously active keyset
Set font_name and example displays to selection. to the new keyset and activate the new custom keyset.
""" """
font = self.fontlist.get( if self.keyset_source.get():
ACTIVE if event.type.name == 'KeyRelease' else ANCHOR) prev_key_set_name = self.builtin_name.get()
self.font_name.set(font.lower()) 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 set_samples(self, event=None): def load_keys_list(self, keyset_name):
"""Update update both screen samples with the font settings. """Reload the list of action/key binding pairs for the active key set.
Called on font initialization and change events. An action/key binding can be selected to change the key binding.
Accesses font_name, font_size, and font_bold Variables.
Updates font_sample and hightlight page highlight_sample.
""" """
font_name = self.font_name.get() reselect = False
font_weight = tkFont.BOLD if self.font_bold.get() else tkFont.NORMAL if self.bindingslist.curselection():
new_font = (font_name, self.font_size.get(), font_weight) reselect = True
self.font_sample['font'] = new_font list_index = self.bindingslist.index(ANCHOR)
self.highlight_sample['font'] = new_font 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 load_tab_cfg(self): @staticmethod
"""Load current configuration settings for the tab options. def save_new_key_set(keyset_name, keyset):
"""Save a newly created core key set.
Attributes updated: Add keyset to idleConf.userCfg['keys'], not to disk.
space_num: Set to value from idleConf. 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
""" """
# Set indent sizes. if not idleConf.userCfg['keys'].has_section(keyset_name):
space_num = idleConf.GetOption( idleConf.userCfg['keys'].add_section(keyset_name)
'main', 'Indent', 'num-spaces', default=4, type='int') for event in keyset:
self.space_num.set(space_num) value = keyset[event]
idleConf.userCfg['keys'].SetOption(keyset_name, event, value)
def var_changed_space_num(self, *params): def delete_custom_keys(self):
"Store change to indentation size." """Handle event to delete a custom key set.
value = self.space_num.get()
changes.add_option('main', 'Indent', 'num-spaces', value) 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):
......
...@@ -232,22 +232,27 @@ class HighlightTest(unittest.TestCase): ...@@ -232,22 +232,27 @@ class HighlightTest(unittest.TestCase):
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 @@ class KeyTest(unittest.TestCase): ...@@ -258,7 +263,7 @@ class KeyTest(unittest.TestCase):
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 @@ class KeyTest(unittest.TestCase): ...@@ -300,7 +305,7 @@ class KeyTest(unittest.TestCase):
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 @@ class KeyTest(unittest.TestCase): ...@@ -321,7 +326,7 @@ class KeyTest(unittest.TestCase):
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 @@ class KeyTest(unittest.TestCase): ...@@ -352,7 +357,7 @@ class KeyTest(unittest.TestCase):
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 @@ class KeyTest(unittest.TestCase): ...@@ -366,7 +371,7 @@ class KeyTest(unittest.TestCase):
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 @@ class KeyTest(unittest.TestCase): ...@@ -386,7 +391,7 @@ class KeyTest(unittest.TestCase):
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 @@ class KeyTest(unittest.TestCase): ...@@ -407,7 +412,7 @@ class KeyTest(unittest.TestCase):
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 @@ class KeyTest(unittest.TestCase): ...@@ -456,7 +461,7 @@ class KeyTest(unittest.TestCase):
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 @@ class KeyTest(unittest.TestCase): ...@@ -464,7 +469,7 @@ class KeyTest(unittest.TestCase):
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 @@ class KeyTest(unittest.TestCase): ...@@ -482,7 +487,7 @@ class KeyTest(unittest.TestCase):
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 @@ class KeyTest(unittest.TestCase): ...@@ -504,7 +509,7 @@ class KeyTest(unittest.TestCase):
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 @@ class KeyTest(unittest.TestCase): ...@@ -535,7 +540,7 @@ class KeyTest(unittest.TestCase):
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 @@ class KeyTest(unittest.TestCase): ...@@ -578,11 +583,11 @@ class KeyTest(unittest.TestCase):
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 @@ class KeyTest(unittest.TestCase): ...@@ -598,8 +603,8 @@ class KeyTest(unittest.TestCase):
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 @@ class KeyTest(unittest.TestCase): ...@@ -610,11 +615,11 @@ class KeyTest(unittest.TestCase):
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
......
IDLE: Factor KeysPage(Frame) class from ConfigDialog. The slightly
modified tests continue to pass. Patch by Cheryl Sabella.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment