mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	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
					
				
					 3 changed files with 470 additions and 457 deletions
				
			
		|  | @ -92,9 +92,9 @@ def create_widgets(self): | |||
|             note: Notebook | ||||
|             highpage: self.create_page_highlight | ||||
|             fontpage: FontPage | ||||
|             keyspage: self.create_page_keys | ||||
|             keyspage: KeysPage | ||||
|             genpage: GenPage | ||||
|             extpageL self.create_page_extensions | ||||
|             extpage: self.create_page_extensions | ||||
| 
 | ||||
|         Methods: | ||||
|             create_action_buttons | ||||
|  | @ -104,7 +104,7 @@ def create_widgets(self): | |||
|         self.note = note = Notebook(self, width=450, height=450) | ||||
|         self.highpage = self.create_page_highlight() | ||||
|         self.fontpage = FontPage(note, self.highpage) | ||||
|         self.keyspage = self.create_page_keys() | ||||
|         self.keyspage = KeysPage(note) | ||||
|         self.genpage = GenPage(note) | ||||
|         self.extpage = self.create_page_extensions() | ||||
|         note.add(self.fontpage, text='Fonts/Tabs') | ||||
|  | @ -132,7 +132,7 @@ def load_configs(self): | |||
|         #self.load_font_cfg() | ||||
|         #self.load_tab_cfg() | ||||
|         self.load_theme_cfg() | ||||
|         self.load_key_cfg() | ||||
|         # self.load_key_cfg() | ||||
|         # self.load_general_cfg() | ||||
|         # note: extension page handled separately | ||||
| 
 | ||||
|  | @ -791,431 +791,6 @@ def delete_custom_theme(self): | |||
|         self.activate_config_changes() | ||||
|         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): | ||||
|         """Remove current key bindings. | ||||
| 
 | ||||
|  | @ -1650,6 +1225,437 @@ def var_changed_space_num(self, *params): | |||
|         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): | ||||
| 
 | ||||
|     def __init__(self, master): | ||||
|  |  | |||
|  | @ -232,22 +232,27 @@ def setUp(self): | |||
|         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 | ||||
|     def setUpClass(cls): | ||||
|         d = dialog | ||||
|         dialog.note.select(d.keyspage) | ||||
|         d.set_keys_type = Func() | ||||
|         d.load_keys_list = Func() | ||||
|         page = cls.page = dialog.keyspage | ||||
|         dialog.note.select(page) | ||||
|         page.set_keys_type = Func() | ||||
|         page.load_keys_list = Func() | ||||
| 
 | ||||
|     @classmethod | ||||
|     def tearDownClass(cls): | ||||
|         d = dialog | ||||
|         del d.set_keys_type, d.load_keys_list | ||||
|         page = cls.page | ||||
|         del page.set_keys_type, page.load_keys_list | ||||
| 
 | ||||
|     def setUp(self): | ||||
|         d = dialog | ||||
|         d = self.page | ||||
|         # The following is needed for test_load_key_cfg, _delete_custom_keys. | ||||
|         # This may indicate a defect in some test or function. | ||||
|         for section in idleConf.GetSectionList('user', 'keys'): | ||||
|  | @ -258,7 +263,7 @@ def setUp(self): | |||
| 
 | ||||
|     def test_load_key_cfg(self): | ||||
|         tracers.detach() | ||||
|         d = dialog | ||||
|         d = self.page | ||||
|         eq = self.assertEqual | ||||
| 
 | ||||
|         # Use builtin keyset with no user keysets created. | ||||
|  | @ -300,7 +305,7 @@ def test_load_key_cfg(self): | |||
| 
 | ||||
|     def test_keyset_source(self): | ||||
|         eq = self.assertEqual | ||||
|         d = dialog | ||||
|         d = self.page | ||||
|         # Test these separately. | ||||
|         d.var_changed_builtin_name = Func() | ||||
|         d.var_changed_custom_name = Func() | ||||
|  | @ -321,7 +326,7 @@ def test_keyset_source(self): | |||
| 
 | ||||
|     def test_builtin_name(self): | ||||
|         eq = self.assertEqual | ||||
|         d = dialog | ||||
|         d = self.page | ||||
|         idleConf.userCfg['main'].remove_section('Keys') | ||||
|         item_list = ['IDLE Classic Windows', 'IDLE Classic OSX', | ||||
|                      'IDLE Modern UNIX'] | ||||
|  | @ -352,7 +357,7 @@ def test_builtin_name(self): | |||
|         eq(d.load_keys_list.args, ('IDLE Classic OSX', )) | ||||
| 
 | ||||
|     def test_custom_name(self): | ||||
|         d = dialog | ||||
|         d = self.page | ||||
| 
 | ||||
|         # If no selections, doesn't get added. | ||||
|         d.customlist.SetMenu([], '- no custom keys -') | ||||
|  | @ -366,7 +371,7 @@ def test_custom_name(self): | |||
|         self.assertEqual(d.load_keys_list.called, 1) | ||||
| 
 | ||||
|     def test_keybinding(self): | ||||
|         d = dialog | ||||
|         d = self.page | ||||
|         d.custom_name.set('my custom keys') | ||||
|         d.bindingslist.delete(0, 'end') | ||||
|         d.bindingslist.insert(0, 'copy') | ||||
|  | @ -386,7 +391,7 @@ def test_keybinding(self): | |||
| 
 | ||||
|     def test_set_keys_type(self): | ||||
|         eq = self.assertEqual | ||||
|         d = dialog | ||||
|         d = self.page | ||||
|         del d.set_keys_type | ||||
| 
 | ||||
|         # Builtin keyset selected. | ||||
|  | @ -407,7 +412,7 @@ def test_set_keys_type(self): | |||
| 
 | ||||
|     def test_get_new_keys(self): | ||||
|         eq = self.assertEqual | ||||
|         d = dialog | ||||
|         d = self.page | ||||
|         orig_getkeysdialog = configdialog.GetKeysDialog | ||||
|         gkd = configdialog.GetKeysDialog = Func(return_self=True) | ||||
|         gnkn = d.get_new_keys_name = Func() | ||||
|  | @ -456,7 +461,7 @@ def test_get_new_keys(self): | |||
|     def test_get_new_keys_name(self): | ||||
|         orig_sectionname = configdialog.SectionName | ||||
|         sn = configdialog.SectionName = Func(return_self=True) | ||||
|         d = dialog | ||||
|         d = self.page | ||||
| 
 | ||||
|         sn.result = '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 | ||||
| 
 | ||||
|     def test_save_as_new_key_set(self): | ||||
|         d = dialog | ||||
|         d = self.page | ||||
|         gnkn = d.get_new_keys_name = Func() | ||||
|         d.keyset_source.set(True) | ||||
| 
 | ||||
|  | @ -482,7 +487,7 @@ def test_save_as_new_key_set(self): | |||
|         del d.get_new_keys_name | ||||
| 
 | ||||
|     def test_on_bindingslist_select(self): | ||||
|         d = dialog | ||||
|         d = self.page | ||||
|         b = d.bindingslist | ||||
|         b.delete(0, 'end') | ||||
|         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): | ||||
|         eq = self.assertEqual | ||||
|         d = dialog | ||||
|         d = self.page | ||||
| 
 | ||||
|         # Use default as previously active keyset. | ||||
|         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): | ||||
|         eq = self.assertEqual | ||||
|         d = dialog | ||||
|         d = self.page | ||||
|         gks = idleConf.GetKeySet = Func() | ||||
|         del d.load_keys_list | ||||
|         b = d.bindingslist | ||||
|  | @ -578,11 +583,11 @@ def test_load_keys_list(self): | |||
| 
 | ||||
|     def test_delete_custom_keys(self): | ||||
|         eq = self.assertEqual | ||||
|         d = dialog | ||||
|         d = self.page | ||||
|         d.button_delete_custom_keys['state'] = NORMAL | ||||
|         yesno = configdialog.tkMessageBox.askyesno = Func() | ||||
|         d.deactivate_current_config = Func() | ||||
|         d.activate_config_changes = Func() | ||||
|         dialog.deactivate_current_config = Func() | ||||
|         dialog.activate_config_changes = Func() | ||||
| 
 | ||||
|         keyset_name = 'spam key set' | ||||
|         idleConf.userCfg['keys'].SetOption(keyset_name, 'name', 'value') | ||||
|  | @ -598,8 +603,8 @@ def test_delete_custom_keys(self): | |||
|         eq(yesno.called, 1) | ||||
|         eq(keyspage[keyset_name], {'option': 'True'}) | ||||
|         eq(idleConf.GetSectionList('user', 'keys'), ['spam key set']) | ||||
|         eq(d.deactivate_current_config.called, 0) | ||||
|         eq(d.activate_config_changes.called, 0) | ||||
|         eq(dialog.deactivate_current_config.called, 0) | ||||
|         eq(dialog.activate_config_changes.called, 0) | ||||
|         eq(d.set_keys_type.called, 0) | ||||
| 
 | ||||
|         # Confirm deletion. | ||||
|  | @ -610,11 +615,11 @@ def test_delete_custom_keys(self): | |||
|         eq(idleConf.GetSectionList('user', 'keys'), []) | ||||
|         eq(d.custom_keyset_on['state'], DISABLED) | ||||
|         eq(d.custom_name.get(), '- no custom keys -') | ||||
|         eq(d.deactivate_current_config.called, 1) | ||||
|         eq(d.activate_config_changes.called, 1) | ||||
|         eq(dialog.deactivate_current_config.called, 1) | ||||
|         eq(dialog.activate_config_changes.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 | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,2 @@ | |||
| IDLE: Factor KeysPage(Frame) class from ConfigDialog.  The slightly | ||||
| modified tests continue to pass.  Patch by Cheryl Sabella. | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Cheryl Sabella
						Cheryl Sabella