From b1660800f4f519dbfab9e5a4ad3eae1cfabab3ed Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Thu, 27 Jul 2017 18:28:01 -0400 Subject: [PATCH] bpo-31060: IDLE: Finish regrouping ConfigDialog methods (#2908) Finish resorting the 72 ConfigDialog methods into 7 groups that represent the dialog, action buttons, and font, highlight, keys, general, and extension pages. This will help with continuing to add tests and improve the pages. It will enable splitting ConfigDialog into 6 or 7 more comprehensible classes. --- Lib/idlelib/configdialog.py | 1566 +++++++++-------- .../2017-07-27-14-48-42.bpo-31060.GdY_VY.rst | 3 + 2 files changed, 788 insertions(+), 781 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2017-07-27-14-48-42.bpo-31060.GdY_VY.rst diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py index daaa34459e2..e359ec24cd3 100644 --- a/Lib/idlelib/configdialog.py +++ b/Lib/idlelib/configdialog.py @@ -30,7 +30,6 @@ from idlelib.textview import view_text changes = ConfigChanges() - class ConfigDialog(Toplevel): """Config dialog for IDLE. """ @@ -112,6 +111,58 @@ class ConfigDialog(Toplevel): self.create_page_extensions() self.create_action_buttons().pack(side=BOTTOM) + def load_configs(self): + """Load configuration for each page. + + Load configuration from default and user config files and populate + the widgets on the config dialog pages. + + Methods: + load_font_cfg + load_tab_cfg + load_theme_cfg + load_key_cfg + load_general_cfg + """ + self.load_font_cfg() + self.load_tab_cfg() + self.load_theme_cfg() + self.load_key_cfg() + self.load_general_cfg() + # note: extension page handled separately + + def attach_var_callbacks(self): + "Attach callbacks to variables that can be changed." + self.font_size.trace_add('write', self.var_changed_font) + self.font_name.trace_add('write', self.var_changed_font) + self.font_bold.trace_add('write', self.var_changed_font) + self.space_num.trace_add('write', self.var_changed_space_num) + self.color.trace_add('write', self.var_changed_color) + self.builtin_theme.trace_add('write', self.var_changed_builtin_theme) + self.custom_theme.trace_add('write', self.var_changed_custom_theme) + self.is_builtin_theme.trace_add('write', self.var_changed_is_builtin_theme) + self.highlight_target.trace_add('write', self.var_changed_highlight_target) + self.keybinding.trace_add('write', self.var_changed_keybinding) + self.builtin_keys.trace_add('write', self.var_changed_builtin_keys) + self.custom_keys.trace_add('write', self.var_changed_custom_keys) + self.are_keys_builtin.trace_add('write', self.var_changed_are_keys_builtin) + self.win_width.trace_add('write', self.var_changed_win_width) + self.win_height.trace_add('write', self.var_changed_win_height) + self.startup_edit.trace_add('write', self.var_changed_startup_edit) + self.autosave.trace_add('write', self.var_changed_autosave) + + def remove_var_callbacks(self): + "Remove callbacks to prevent memory leaks." + for var in ( + self.font_size, self.font_name, self.font_bold, + self.space_num, self.color, self.builtin_theme, + self.custom_theme, self.is_builtin_theme, self.highlight_target, + self.keybinding, self.builtin_keys, self.custom_keys, + self.are_keys_builtin, self.win_width, self.win_height, + self.startup_edit, self.autosave,): + var.trace_remove('write', var.trace_info()[0][1]) + + def create_action_buttons(self): """Return frame of action buttons for dialog. @@ -150,6 +201,50 @@ class ConfigDialog(Toplevel): buttons.pack(side=BOTTOM) return outer + def ok(self): + """Apply config changes, then dismiss dialog. + + Methods: + apply + destroy: inherited + """ + self.apply() + self.destroy() + + def apply(self): + """Apply config changes and leave dialog open. + + Methods: + deactivate_current_config + save_all_changed_extensions + activate_config_changes + """ + self.deactivate_current_config() + changes.save_all() + self.save_all_changed_extensions() + self.activate_config_changes() + + def cancel(self): + """Dismiss config dialog. + + Methods: + destroy: inherited + """ + self.destroy() + + def help(self): + """Create textview for config dialog help. + + Attrbutes accessed: + tab_pages + + Methods: + view_text: Method from textview module. + """ + page = self.tab_pages._current_page + view_text(self, title='Help for IDLE preferences', + text=help_common+help_pages.get(page, '')) + def create_page_font_tab(self): """Return frame of widgets for Font/Tabs tab. @@ -299,16 +394,6 @@ class ConfigDialog(Toplevel): # Set font weight. self.font_bold.set(font_bold) - def on_fontlist_select(self, event): - """Handle selecting a font from the list. - - Event can result from either mouse click or Up or Down key. - Set font_name and example displays to selection. - """ - font = self.fontlist.get( - ACTIVE if event.type.name == 'KeyRelease' else ANCHOR) - self.font_name.set(font.lower()) - def var_changed_font(self, *params): """Store changes to font attributes. @@ -324,6 +409,16 @@ class ConfigDialog(Toplevel): changes.add_option('main', 'EditorWindow', 'font-bold', value) self.set_samples() + def on_fontlist_select(self, event): + """Handle selecting a font from the list. + + Event can result from either mouse click or Up or Down key. + Set font_name and example displays to selection. + """ + font = self.fontlist.get( + ACTIVE if event.type.name == 'KeyRelease' else ANCHOR) + self.font_name.set(font.lower()) + def set_samples(self, event=None): """Update update both screen samples with the font settings. @@ -531,6 +626,399 @@ class ConfigDialog(Toplevel): self.new_custom_theme.pack(side=TOP, fill=X, pady=5) return frame + def load_theme_cfg(self): + """Load current configuration settings for the theme options. + + Based on the is_builtin_theme toggle, the theme is set as + either builtin or custom and the initial widget values + reflect the current settings from idleConf. + + Attributes updated: + is_builtin_theme: Set from idleConf. + opt_menu_theme_builtin: List of default themes from idleConf. + opt_menu_theme_custom: List of custom themes from idleConf. + radio_theme_custom: Disabled if there are no custom themes. + custom_theme: Message with additional information. + opt_menu_highlight_target: Create menu from self.theme_elements. + + Methods: + set_theme_type + paint_theme_sample + set_highlight_target + """ + # Set current theme type radiobutton. + self.is_builtin_theme.set(idleConf.GetOption( + 'main', 'Theme', 'default', type='bool', default=1)) + # Set current theme. + current_option = idleConf.CurrentTheme() + # Load available theme option menus. + if self.is_builtin_theme.get(): # Default theme selected. + item_list = idleConf.GetSectionList('default', 'highlight') + item_list.sort() + self.opt_menu_theme_builtin.SetMenu(item_list, current_option) + item_list = idleConf.GetSectionList('user', 'highlight') + item_list.sort() + if not item_list: + self.radio_theme_custom['state'] = DISABLED + self.custom_theme.set('- no custom themes -') + else: + self.opt_menu_theme_custom.SetMenu(item_list, item_list[0]) + else: # User theme selected. + item_list = idleConf.GetSectionList('user', 'highlight') + item_list.sort() + self.opt_menu_theme_custom.SetMenu(item_list, current_option) + item_list = idleConf.GetSectionList('default', 'highlight') + item_list.sort() + self.opt_menu_theme_builtin.SetMenu(item_list, item_list[0]) + self.set_theme_type() + # Load theme element option menu. + theme_names = list(self.theme_elements.keys()) + theme_names.sort(key=lambda x: self.theme_elements[x][1]) + self.opt_menu_highlight_target.SetMenu(theme_names, theme_names[0]) + self.paint_theme_sample() + self.set_highlight_target() + + def var_changed_builtin_theme(self, *params): + """Process new builtin theme selection. + + Add the changed theme's name to the changed_items and recreate + the sample with the values from the selected theme. + """ + old_themes = ('IDLE Classic', 'IDLE New') + value = self.builtin_theme.get() + if value not in old_themes: + if idleConf.GetOption('main', 'Theme', 'name') not in old_themes: + changes.add_option('main', 'Theme', 'name', old_themes[0]) + changes.add_option('main', 'Theme', 'name2', value) + self.new_custom_theme.config(text='New theme, see Help', + fg='#500000') + else: + changes.add_option('main', 'Theme', 'name', value) + changes.add_option('main', 'Theme', 'name2', '') + self.new_custom_theme.config(text='', fg='black') + self.paint_theme_sample() + + def var_changed_custom_theme(self, *params): + """Process new custom theme selection. + + If a new custom theme is selected, add the name to the + changed_items and apply the theme to the sample. + """ + value = self.custom_theme.get() + if value != '- no custom themes -': + changes.add_option('main', 'Theme', 'name', value) + self.paint_theme_sample() + + def var_changed_is_builtin_theme(self, *params): + """Process toggle between builtin and custom theme. + + Update the default toggle value and apply the newly + selected theme type. + """ + value = self.is_builtin_theme.get() + changes.add_option('main', 'Theme', 'default', value) + if value: + self.var_changed_builtin_theme() + else: + self.var_changed_custom_theme() + + def var_changed_color(self, *params): + "Process change to color choice." + self.on_new_color_set() + + def var_changed_highlight_target(self, *params): + "Process selection of new target tag for highlighting." + self.set_highlight_target() + + def set_theme_type(self): + """Set available screen options based on builtin or custom theme. + + Attributes accessed: + is_builtin_theme + + Attributes updated: + opt_menu_theme_builtin + opt_menu_theme_custom + button_delete_custom_theme + radio_theme_custom + + Called from: + handler for radio_theme_builtin and radio_theme_custom + delete_custom_theme + create_new_theme + load_theme_cfg + """ + if self.is_builtin_theme.get(): + self.opt_menu_theme_builtin['state'] = NORMAL + self.opt_menu_theme_custom['state'] = DISABLED + self.button_delete_custom_theme['state'] = DISABLED + else: + self.opt_menu_theme_builtin['state'] = DISABLED + self.radio_theme_custom['state'] = NORMAL + self.opt_menu_theme_custom['state'] = NORMAL + self.button_delete_custom_theme['state'] = NORMAL + + def get_color(self): + """Handle button to select a new color for the target tag. + + If a new color is selected while using a builtin theme, a + name must be supplied to create a custom theme. + + Attributes accessed: + highlight_target + frame_color_set + is_builtin_theme + + Attributes updated: + color + + Methods: + get_new_theme_name + create_new_theme + """ + target = self.highlight_target.get() + prev_color = self.frame_color_set.cget('bg') + rgbTuplet, color_string = tkColorChooser.askcolor( + parent=self, title='Pick new color for : '+target, + initialcolor=prev_color) + if color_string and (color_string != prev_color): + # User didn't cancel and they chose a new color. + if self.is_builtin_theme.get(): # Current theme is a built-in. + message = ('Your changes will be saved as a new Custom Theme. ' + 'Enter a name for your new Custom Theme below.') + new_theme = self.get_new_theme_name(message) + if not new_theme: # User cancelled custom theme creation. + return + else: # Create new custom theme based on previously active theme. + self.create_new_theme(new_theme) + self.color.set(color_string) + else: # Current theme is user defined. + self.color.set(color_string) + + def on_new_color_set(self): + "Display sample of new color selection on the dialog." + new_color=self.color.get() + self.frame_color_set.config(bg=new_color) # Set sample. + plane ='foreground' if self.fg_bg_toggle.get() else 'background' + sample_element = self.theme_elements[self.highlight_target.get()][0] + self.highlight_sample.tag_config(sample_element, **{plane:new_color}) + theme = self.custom_theme.get() + theme_element = sample_element + '-' + plane + changes.add_option('highlight', theme, theme_element, new_color) + + def get_new_theme_name(self, message): + "Return name of new theme from query popup." + used_names = (idleConf.GetSectionList('user', 'highlight') + + idleConf.GetSectionList('default', 'highlight')) + new_theme = SectionName( + self, 'New Custom Theme', message, used_names).result + return new_theme + + def save_as_new_theme(self): + """Prompt for new theme name and create the theme. + + Methods: + get_new_theme_name + create_new_theme + """ + new_theme_name = self.get_new_theme_name('New Theme Name:') + if new_theme_name: + self.create_new_theme(new_theme_name) + + def create_new_theme(self, new_theme_name): + """Create a new custom theme with the given name. + + Create the new theme based on the previously active theme + with the current changes applied. Once it is saved, then + activate the new theme. + + Attributes accessed: + builtin_theme + custom_theme + + Attributes updated: + opt_menu_theme_custom + is_builtin_theme + + Method: + save_new_theme + set_theme_type + """ + if self.is_builtin_theme.get(): + theme_type = 'default' + theme_name = self.builtin_theme.get() + else: + theme_type = 'user' + theme_name = self.custom_theme.get() + new_theme = idleConf.GetThemeDict(theme_type, theme_name) + # Apply any of the old theme's unsaved changes to the new theme. + if theme_name in changes['highlight']: + theme_changes = changes['highlight'][theme_name] + for element in theme_changes: + new_theme[element] = theme_changes[element] + # Save the new theme. + self.save_new_theme(new_theme_name, new_theme) + # Change GUI over to the new theme. + custom_theme_list = idleConf.GetSectionList('user', 'highlight') + custom_theme_list.sort() + self.opt_menu_theme_custom.SetMenu(custom_theme_list, new_theme_name) + self.is_builtin_theme.set(0) + self.set_theme_type() + + def set_highlight_target(self): + """Set fg/bg toggle and color based on highlight tag target. + + Instance variables accessed: + highlight_target + + Attributes updated: + radio_fg + radio_bg + fg_bg_toggle + + Methods: + set_color_sample + + Called from: + var_changed_highlight_target + load_theme_cfg + """ + if self.highlight_target.get() == 'Cursor': # bg not possible + self.radio_fg['state'] = DISABLED + self.radio_bg['state'] = DISABLED + self.fg_bg_toggle.set(1) + else: # Both fg and bg can be set. + self.radio_fg['state'] = NORMAL + self.radio_bg['state'] = NORMAL + self.fg_bg_toggle.set(1) + self.set_color_sample() + + def set_color_sample_binding(self, *args): + """Change color sample based on foreground/background toggle. + + Methods: + set_color_sample + """ + self.set_color_sample() + + def set_color_sample(self): + """Set the color of the frame background to reflect the selected target. + + Instance variables accessed: + theme_elements + highlight_target + fg_bg_toggle + highlight_sample + + Attributes updated: + frame_color_set + """ + # Set the color sample area. + tag = self.theme_elements[self.highlight_target.get()][0] + plane = 'foreground' if self.fg_bg_toggle.get() else 'background' + color = self.highlight_sample.tag_cget(tag, plane) + self.frame_color_set.config(bg=color) + + def paint_theme_sample(self): + """Apply the theme colors to each element tag in the sample text. + + Instance attributes accessed: + theme_elements + is_builtin_theme + builtin_theme + custom_theme + + Attributes updated: + highlight_sample: Set the tag elements to the theme. + + Methods: + set_color_sample + + Called from: + var_changed_builtin_theme + var_changed_custom_theme + load_theme_cfg + """ + if self.is_builtin_theme.get(): # Default theme + theme = self.builtin_theme.get() + else: # User theme + theme = self.custom_theme.get() + for element_title in self.theme_elements: + element = self.theme_elements[element_title][0] + colors = idleConf.GetHighlight(theme, element) + if element == 'cursor': # Cursor sample needs special painting. + colors['background'] = idleConf.GetHighlight( + theme, 'normal', fgBg='bg') + # Handle any unsaved changes to this theme. + if theme in changes['highlight']: + theme_dict = changes['highlight'][theme] + if element + '-foreground' in theme_dict: + colors['foreground'] = theme_dict[element + '-foreground'] + if element + '-background' in theme_dict: + colors['background'] = theme_dict[element + '-background'] + self.highlight_sample.tag_config(element, **colors) + self.set_color_sample() + + def save_new_theme(self, theme_name, theme): + """Save a newly created theme to idleConf. + + theme_name - string, the name of the new theme + theme - dictionary containing the new theme + """ + if not idleConf.userCfg['highlight'].has_section(theme_name): + idleConf.userCfg['highlight'].add_section(theme_name) + for element in theme: + value = theme[element] + idleConf.userCfg['highlight'].SetOption(theme_name, element, value) + + def delete_custom_theme(self): + """Handle event to delete custom theme. + + The current theme is deactivated and the default theme is + activated. The custom theme is permanently removed from + the config file. + + Attributes accessed: + custom_theme + + Attributes updated: + radio_theme_custom + opt_menu_theme_custom + is_builtin_theme + builtin_theme + + Methods: + deactivate_current_config + save_all_changed_extensions + activate_config_changes + set_theme_type + """ + theme_name = self.custom_theme.get() + delmsg = 'Are you sure you wish to delete the theme %r ?' + if not tkMessageBox.askyesno( + 'Delete Theme', delmsg % theme_name, parent=self): + return + self.deactivate_current_config() + # Remove theme from changes, config, and file. + changes.delete_section('highlight', theme_name) + # Reload user theme list. + item_list = idleConf.GetSectionList('user', 'highlight') + item_list.sort() + if not item_list: + self.radio_theme_custom['state'] = DISABLED + self.opt_menu_theme_custom.SetMenu(item_list, '- no custom themes -') + else: + self.opt_menu_theme_custom.SetMenu(item_list, item_list[0]) + # Revert to default theme. + self.is_builtin_theme.set(idleConf.defaultCfg['main'].Get('Theme', 'default')) + self.builtin_theme.set(idleConf.defaultCfg['main'].Get('Theme', 'name')) + # 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_theme_type() + + def create_page_keys(self): """Return frame of widgets for Keys tab. @@ -650,6 +1138,292 @@ class ConfigDialog(Toplevel): 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.are_keys_builtin.set(idleConf.GetOption( + 'main', 'Keys', 'default', type='bool', default=1)) + # Set current keys. + current_option = idleConf.CurrentKeys() + # Load available keyset option menus. + if self.are_keys_builtin.get(): # Default theme selected. + item_list = idleConf.GetSectionList('default', 'keys') + item_list.sort() + self.opt_menu_keys_builtin.SetMenu(item_list, current_option) + item_list = idleConf.GetSectionList('user', 'keys') + item_list.sort() + if not item_list: + self.radio_keys_custom['state'] = DISABLED + self.custom_keys.set('- no custom keys -') + else: + self.opt_menu_keys_custom.SetMenu(item_list, item_list[0]) + else: # User key set selected. + item_list = idleConf.GetSectionList('user', 'keys') + item_list.sort() + self.opt_menu_keys_custom.SetMenu(item_list, current_option) + item_list = idleConf.GetSectionList('default', 'keys') + item_list.sort() + self.opt_menu_keys_builtin.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_keys(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_keys.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.new_custom_keys.config(text='New key set, see Help', + fg='#500000') + else: + changes.add_option('main', 'Keys', 'name', value) + changes.add_option('main', 'Keys', 'name2', '') + self.new_custom_keys.config(text='', fg='black') + self.load_keys_list(value) + + def var_changed_custom_keys(self, *params): + "Process selection of custom key set." + value = self.custom_keys.get() + if value != '- no custom keys -': + changes.add_option('main', 'Keys', 'name', value) + self.load_keys_list(value) + + def var_changed_are_keys_builtin(self, *params): + "Process toggle between builtin key set and custom key set." + value = self.are_keys_builtin.get() + changes.add_option('main', 'Keys', 'default', value) + if value: + self.var_changed_builtin_keys() + else: + self.var_changed_custom_keys() + + def var_changed_keybinding(self, *params): + "Store change to a keybinding." + value = self.keybinding.get() + key_set = self.custom_keys.get() + event = self.list_bindings.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.are_keys_builtin.get(): + self.opt_menu_keys_builtin['state'] = NORMAL + self.opt_menu_keys_custom['state'] = DISABLED + self.button_delete_custom_keys['state'] = DISABLED + else: + self.opt_menu_keys_builtin['state'] = DISABLED + self.radio_keys_custom['state'] = NORMAL + self.opt_menu_keys_custom['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.list_bindings.index(ANCHOR) + binding = self.list_bindings.get(list_index) + bind_name = binding.split()[0] + if self.are_keys_builtin.get(): + current_key_set_name = self.builtin_keys.get() + else: + current_key_set_name = self.custom_keys.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.are_keys_builtin.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.list_bindings.select_set(list_index) + self.list_bindings.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.list_bindings.delete(list_index) + self.list_bindings.insert(list_index, bind_name+' - '+new_keys) + self.list_bindings.select_set(list_index) + self.list_bindings.select_anchor(list_index) + self.keybinding.set(new_keys) + else: + self.list_bindings.select_set(list_index) + self.list_bindings.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 keybinding_selected(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. + + Create the new key set based on the previously active set + with the current changes applied. Once it is saved, then + activate the new key set. + """ + if self.are_keys_builtin.get(): + prev_key_set_name = self.builtin_keys.get() + else: + prev_key_set_name = self.custom_keys.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.opt_menu_keys_custom.SetMenu(custom_key_list, new_key_set_name) + self.are_keys_builtin.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 = 0 + if self.list_bindings.curselection(): + reselect = 1 + list_index = self.list_bindings.index(ANCHOR) + keyset = idleConf.GetKeySet(keyset_name) + bind_names = list(keyset.keys()) + bind_names.sort() + self.list_bindings.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.list_bindings.insert(END, bind_name+' - '+key) + if reselect: + self.list_bindings.see(list_index) + self.list_bindings.select_set(list_index) + self.list_bindings.select_anchor(list_index) + + def save_new_key_set(self, keyset_name, keyset): + """Save a newly created core key set. + + keyset_name - string, the name of the new key set + keyset - dictionary containing the new key set + """ + 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_keys.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.radio_keys_custom['state'] = DISABLED + self.opt_menu_keys_custom.SetMenu(item_list, '- no custom keys -') + else: + self.opt_menu_keys_custom.SetMenu(item_list, item_list[0]) + # Revert to default key set. + self.are_keys_builtin.set(idleConf.defaultCfg['main'] + .Get('Keys', 'default')) + self.builtin_keys.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. + + Iterate over window instances defined in parent and remove + 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() + + def activate_config_changes(self): + """Apply configuration changes to current windows. + + Dynamically update the current parent window instances + with some of the configuration changes. + """ + 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_general(self): """Return frame of widgets for General tab. @@ -897,776 +1671,6 @@ class ConfigDialog(Toplevel): ';'.join(self.user_helplist[num-1][:2])) - def attach_var_callbacks(self): - "Attach callbacks to variables that can be changed." - self.font_size.trace_add('write', self.var_changed_font) - self.font_name.trace_add('write', self.var_changed_font) - self.font_bold.trace_add('write', self.var_changed_font) - self.space_num.trace_add('write', self.var_changed_space_num) - self.color.trace_add('write', self.var_changed_color) - self.builtin_theme.trace_add('write', self.var_changed_builtin_theme) - self.custom_theme.trace_add('write', self.var_changed_custom_theme) - self.is_builtin_theme.trace_add('write', self.var_changed_is_builtin_theme) - self.highlight_target.trace_add('write', self.var_changed_highlight_target) - self.keybinding.trace_add('write', self.var_changed_keybinding) - self.builtin_keys.trace_add('write', self.var_changed_builtin_keys) - self.custom_keys.trace_add('write', self.var_changed_custom_keys) - self.are_keys_builtin.trace_add('write', self.var_changed_are_keys_builtin) - self.win_width.trace_add('write', self.var_changed_win_width) - self.win_height.trace_add('write', self.var_changed_win_height) - self.startup_edit.trace_add('write', self.var_changed_startup_edit) - self.autosave.trace_add('write', self.var_changed_autosave) - - def remove_var_callbacks(self): - "Remove callbacks to prevent memory leaks." - for var in ( - self.font_size, self.font_name, self.font_bold, - self.space_num, self.color, self.builtin_theme, - self.custom_theme, self.is_builtin_theme, self.highlight_target, - self.keybinding, self.builtin_keys, self.custom_keys, - self.are_keys_builtin, self.win_width, self.win_height, - self.startup_edit, self.autosave,): - var.trace_remove('write', var.trace_info()[0][1]) - - def var_changed_color(self, *params): - "Process change to color choice." - self.on_new_color_set() - - def var_changed_builtin_theme(self, *params): - """Process new builtin theme selection. - - Add the changed theme's name to the changed_items and recreate - the sample with the values from the selected theme. - """ - old_themes = ('IDLE Classic', 'IDLE New') - value = self.builtin_theme.get() - if value not in old_themes: - if idleConf.GetOption('main', 'Theme', 'name') not in old_themes: - changes.add_option('main', 'Theme', 'name', old_themes[0]) - changes.add_option('main', 'Theme', 'name2', value) - self.new_custom_theme.config(text='New theme, see Help', - fg='#500000') - else: - changes.add_option('main', 'Theme', 'name', value) - changes.add_option('main', 'Theme', 'name2', '') - self.new_custom_theme.config(text='', fg='black') - self.paint_theme_sample() - - def var_changed_custom_theme(self, *params): - """Process new custom theme selection. - - If a new custom theme is selected, add the name to the - changed_items and apply the theme to the sample. - """ - value = self.custom_theme.get() - if value != '- no custom themes -': - changes.add_option('main', 'Theme', 'name', value) - self.paint_theme_sample() - - def var_changed_is_builtin_theme(self, *params): - """Process toggle between builtin and custom theme. - - Update the default toggle value and apply the newly - selected theme type. - """ - value = self.is_builtin_theme.get() - changes.add_option('main', 'Theme', 'default', value) - if value: - self.var_changed_builtin_theme() - else: - self.var_changed_custom_theme() - - def var_changed_highlight_target(self, *params): - "Process selection of new target tag for highlighting." - self.set_highlight_target() - - def var_changed_keybinding(self, *params): - "Store change to a keybinding." - value = self.keybinding.get() - key_set = self.custom_keys.get() - event = self.list_bindings.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 var_changed_builtin_keys(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_keys.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.new_custom_keys.config(text='New key set, see Help', - fg='#500000') - else: - changes.add_option('main', 'Keys', 'name', value) - changes.add_option('main', 'Keys', 'name2', '') - self.new_custom_keys.config(text='', fg='black') - self.load_keys_list(value) - - def var_changed_custom_keys(self, *params): - "Process selection of custom key set." - value = self.custom_keys.get() - if value != '- no custom keys -': - changes.add_option('main', 'Keys', 'name', value) - self.load_keys_list(value) - - def var_changed_are_keys_builtin(self, *params): - "Process toggle between builtin key set and custom key set." - value = self.are_keys_builtin.get() - changes.add_option('main', 'Keys', 'default', value) - if value: - self.var_changed_builtin_keys() - else: - self.var_changed_custom_keys() - - def set_theme_type(self): - """Set available screen options based on builtin or custom theme. - - Attributes accessed: - is_builtin_theme - - Attributes updated: - opt_menu_theme_builtin - opt_menu_theme_custom - button_delete_custom_theme - radio_theme_custom - - Called from: - handler for radio_theme_builtin and radio_theme_custom - delete_custom_theme - create_new_theme - load_theme_cfg - """ - if self.is_builtin_theme.get(): - self.opt_menu_theme_builtin['state'] = NORMAL - self.opt_menu_theme_custom['state'] = DISABLED - self.button_delete_custom_theme['state'] = DISABLED - else: - self.opt_menu_theme_builtin['state'] = DISABLED - self.radio_theme_custom['state'] = NORMAL - self.opt_menu_theme_custom['state'] = NORMAL - self.button_delete_custom_theme['state'] = NORMAL - - def set_keys_type(self): - "Set available screen options based on builtin or custom key set." - if self.are_keys_builtin.get(): - self.opt_menu_keys_builtin['state'] = NORMAL - self.opt_menu_keys_custom['state'] = DISABLED - self.button_delete_custom_keys['state'] = DISABLED - else: - self.opt_menu_keys_builtin['state'] = DISABLED - self.radio_keys_custom['state'] = NORMAL - self.opt_menu_keys_custom['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.list_bindings.index(ANCHOR) - binding = self.list_bindings.get(list_index) - bind_name = binding.split()[0] - if self.are_keys_builtin.get(): - current_key_set_name = self.builtin_keys.get() - else: - current_key_set_name = self.custom_keys.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.are_keys_builtin.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.list_bindings.select_set(list_index) - self.list_bindings.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.list_bindings.delete(list_index) - self.list_bindings.insert(list_index, bind_name+' - '+new_keys) - self.list_bindings.select_set(list_index) - self.list_bindings.select_anchor(list_index) - self.keybinding.set(new_keys) - else: - self.list_bindings.select_set(list_index) - self.list_bindings.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 keybinding_selected(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. - - Create the new key set based on the previously active set - with the current changes applied. Once it is saved, then - activate the new key set. - """ - if self.are_keys_builtin.get(): - prev_key_set_name = self.builtin_keys.get() - else: - prev_key_set_name = self.custom_keys.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.opt_menu_keys_custom.SetMenu(custom_key_list, new_key_set_name) - self.are_keys_builtin.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 = 0 - if self.list_bindings.curselection(): - reselect = 1 - list_index = self.list_bindings.index(ANCHOR) - keyset = idleConf.GetKeySet(keyset_name) - bind_names = list(keyset.keys()) - bind_names.sort() - self.list_bindings.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.list_bindings.insert(END, bind_name+' - '+key) - if reselect: - self.list_bindings.see(list_index) - self.list_bindings.select_set(list_index) - self.list_bindings.select_anchor(list_index) - - 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_keys.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.radio_keys_custom['state'] = DISABLED - self.opt_menu_keys_custom.SetMenu(item_list, '- no custom keys -') - else: - self.opt_menu_keys_custom.SetMenu(item_list, item_list[0]) - # Revert to default key set. - self.are_keys_builtin.set(idleConf.defaultCfg['main'] - .Get('Keys', 'default')) - self.builtin_keys.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 delete_custom_theme(self): - """Handle event to delete custom theme. - - The current theme is deactivated and the default theme is - activated. The custom theme is permanently removed from - the config file. - - Attributes accessed: - custom_theme - - Attributes updated: - radio_theme_custom - opt_menu_theme_custom - is_builtin_theme - builtin_theme - - Methods: - deactivate_current_config - save_all_changed_extensions - activate_config_changes - set_theme_type - """ - theme_name = self.custom_theme.get() - delmsg = 'Are you sure you wish to delete the theme %r ?' - if not tkMessageBox.askyesno( - 'Delete Theme', delmsg % theme_name, parent=self): - return - self.deactivate_current_config() - # Remove theme from changes, config, and file. - changes.delete_section('highlight', theme_name) - # Reload user theme list. - item_list = idleConf.GetSectionList('user', 'highlight') - item_list.sort() - if not item_list: - self.radio_theme_custom['state'] = DISABLED - self.opt_menu_theme_custom.SetMenu(item_list, '- no custom themes -') - else: - self.opt_menu_theme_custom.SetMenu(item_list, item_list[0]) - # Revert to default theme. - self.is_builtin_theme.set(idleConf.defaultCfg['main'].Get('Theme', 'default')) - self.builtin_theme.set(idleConf.defaultCfg['main'].Get('Theme', 'name')) - # 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_theme_type() - - def get_color(self): - """Handle button to select a new color for the target tag. - - If a new color is selected while using a builtin theme, a - name must be supplied to create a custom theme. - - Attributes accessed: - highlight_target - frame_color_set - is_builtin_theme - - Attributes updated: - color - - Methods: - get_new_theme_name - create_new_theme - """ - target = self.highlight_target.get() - prev_color = self.frame_color_set.cget('bg') - rgbTuplet, color_string = tkColorChooser.askcolor( - parent=self, title='Pick new color for : '+target, - initialcolor=prev_color) - if color_string and (color_string != prev_color): - # User didn't cancel and they chose a new color. - if self.is_builtin_theme.get(): # Current theme is a built-in. - message = ('Your changes will be saved as a new Custom Theme. ' - 'Enter a name for your new Custom Theme below.') - new_theme = self.get_new_theme_name(message) - if not new_theme: # User cancelled custom theme creation. - return - else: # Create new custom theme based on previously active theme. - self.create_new_theme(new_theme) - self.color.set(color_string) - else: # Current theme is user defined. - self.color.set(color_string) - - def on_new_color_set(self): - "Display sample of new color selection on the dialog." - new_color=self.color.get() - self.frame_color_set.config(bg=new_color) # Set sample. - plane ='foreground' if self.fg_bg_toggle.get() else 'background' - sample_element = self.theme_elements[self.highlight_target.get()][0] - self.highlight_sample.tag_config(sample_element, **{plane:new_color}) - theme = self.custom_theme.get() - theme_element = sample_element + '-' + plane - changes.add_option('highlight', theme, theme_element, new_color) - - def get_new_theme_name(self, message): - "Return name of new theme from query popup." - used_names = (idleConf.GetSectionList('user', 'highlight') + - idleConf.GetSectionList('default', 'highlight')) - new_theme = SectionName( - self, 'New Custom Theme', message, used_names).result - return new_theme - - def save_as_new_theme(self): - """Prompt for new theme name and create the theme. - - Methods: - get_new_theme_name - create_new_theme - """ - new_theme_name = self.get_new_theme_name('New Theme Name:') - if new_theme_name: - self.create_new_theme(new_theme_name) - - def create_new_theme(self, new_theme_name): - """Create a new custom theme with the given name. - - Create the new theme based on the previously active theme - with the current changes applied. Once it is saved, then - activate the new theme. - - Attributes accessed: - builtin_theme - custom_theme - - Attributes updated: - opt_menu_theme_custom - is_builtin_theme - - Method: - save_new_theme - set_theme_type - """ - if self.is_builtin_theme.get(): - theme_type = 'default' - theme_name = self.builtin_theme.get() - else: - theme_type = 'user' - theme_name = self.custom_theme.get() - new_theme = idleConf.GetThemeDict(theme_type, theme_name) - # Apply any of the old theme's unsaved changes to the new theme. - if theme_name in changes['highlight']: - theme_changes = changes['highlight'][theme_name] - for element in theme_changes: - new_theme[element] = theme_changes[element] - # Save the new theme. - self.save_new_theme(new_theme_name, new_theme) - # Change GUI over to the new theme. - custom_theme_list = idleConf.GetSectionList('user', 'highlight') - custom_theme_list.sort() - self.opt_menu_theme_custom.SetMenu(custom_theme_list, new_theme_name) - self.is_builtin_theme.set(0) - self.set_theme_type() - - def set_highlight_target(self): - """Set fg/bg toggle and color based on highlight tag target. - - Instance variables accessed: - highlight_target - - Attributes updated: - radio_fg - radio_bg - fg_bg_toggle - - Methods: - set_color_sample - - Called from: - var_changed_highlight_target - load_theme_cfg - """ - if self.highlight_target.get() == 'Cursor': # bg not possible - self.radio_fg['state'] = DISABLED - self.radio_bg['state'] = DISABLED - self.fg_bg_toggle.set(1) - else: # Both fg and bg can be set. - self.radio_fg['state'] = NORMAL - self.radio_bg['state'] = NORMAL - self.fg_bg_toggle.set(1) - self.set_color_sample() - - def set_color_sample_binding(self, *args): - """Change color sample based on foreground/background toggle. - - Methods: - set_color_sample - """ - self.set_color_sample() - - def set_color_sample(self): - """Set the color of the frame background to reflect the selected target. - - Instance variables accessed: - theme_elements - highlight_target - fg_bg_toggle - highlight_sample - - Attributes updated: - frame_color_set - """ - # Set the color sample area. - tag = self.theme_elements[self.highlight_target.get()][0] - plane = 'foreground' if self.fg_bg_toggle.get() else 'background' - color = self.highlight_sample.tag_cget(tag, plane) - self.frame_color_set.config(bg=color) - - def paint_theme_sample(self): - """Apply the theme colors to each element tag in the sample text. - - Instance attributes accessed: - theme_elements - is_builtin_theme - builtin_theme - custom_theme - - Attributes updated: - highlight_sample: Set the tag elements to the theme. - - Methods: - set_color_sample - - Called from: - var_changed_builtin_theme - var_changed_custom_theme - load_theme_cfg - """ - if self.is_builtin_theme.get(): # Default theme - theme = self.builtin_theme.get() - else: # User theme - theme = self.custom_theme.get() - for element_title in self.theme_elements: - element = self.theme_elements[element_title][0] - colors = idleConf.GetHighlight(theme, element) - if element == 'cursor': # Cursor sample needs special painting. - colors['background'] = idleConf.GetHighlight( - theme, 'normal', fgBg='bg') - # Handle any unsaved changes to this theme. - if theme in changes['highlight']: - theme_dict = changes['highlight'][theme] - if element + '-foreground' in theme_dict: - colors['foreground'] = theme_dict[element + '-foreground'] - if element + '-background' in theme_dict: - colors['background'] = theme_dict[element + '-background'] - self.highlight_sample.tag_config(element, **colors) - self.set_color_sample() - - def load_theme_cfg(self): - """Load current configuration settings for the theme options. - - Based on the is_builtin_theme toggle, the theme is set as - either builtin or custom and the initial widget values - reflect the current settings from idleConf. - - Attributes updated: - is_builtin_theme: Set from idleConf. - opt_menu_theme_builtin: List of default themes from idleConf. - opt_menu_theme_custom: List of custom themes from idleConf. - radio_theme_custom: Disabled if there are no custom themes. - custom_theme: Message with additional information. - opt_menu_highlight_target: Create menu from self.theme_elements. - - Methods: - set_theme_type - paint_theme_sample - set_highlight_target - """ - # Set current theme type radiobutton. - self.is_builtin_theme.set(idleConf.GetOption( - 'main', 'Theme', 'default', type='bool', default=1)) - # Set current theme. - current_option = idleConf.CurrentTheme() - # Load available theme option menus. - if self.is_builtin_theme.get(): # Default theme selected. - item_list = idleConf.GetSectionList('default', 'highlight') - item_list.sort() - self.opt_menu_theme_builtin.SetMenu(item_list, current_option) - item_list = idleConf.GetSectionList('user', 'highlight') - item_list.sort() - if not item_list: - self.radio_theme_custom['state'] = DISABLED - self.custom_theme.set('- no custom themes -') - else: - self.opt_menu_theme_custom.SetMenu(item_list, item_list[0]) - else: # User theme selected. - item_list = idleConf.GetSectionList('user', 'highlight') - item_list.sort() - self.opt_menu_theme_custom.SetMenu(item_list, current_option) - item_list = idleConf.GetSectionList('default', 'highlight') - item_list.sort() - self.opt_menu_theme_builtin.SetMenu(item_list, item_list[0]) - self.set_theme_type() - # Load theme element option menu. - theme_names = list(self.theme_elements.keys()) - theme_names.sort(key=lambda x: self.theme_elements[x][1]) - self.opt_menu_highlight_target.SetMenu(theme_names, theme_names[0]) - self.paint_theme_sample() - self.set_highlight_target() - - def load_key_cfg(self): - "Load current configuration settings for the keybinding options." - # Set current keys type radiobutton. - self.are_keys_builtin.set(idleConf.GetOption( - 'main', 'Keys', 'default', type='bool', default=1)) - # Set current keys. - current_option = idleConf.CurrentKeys() - # Load available keyset option menus. - if self.are_keys_builtin.get(): # Default theme selected. - item_list = idleConf.GetSectionList('default', 'keys') - item_list.sort() - self.opt_menu_keys_builtin.SetMenu(item_list, current_option) - item_list = idleConf.GetSectionList('user', 'keys') - item_list.sort() - if not item_list: - self.radio_keys_custom['state'] = DISABLED - self.custom_keys.set('- no custom keys -') - else: - self.opt_menu_keys_custom.SetMenu(item_list, item_list[0]) - else: # User key set selected. - item_list = idleConf.GetSectionList('user', 'keys') - item_list.sort() - self.opt_menu_keys_custom.SetMenu(item_list, current_option) - item_list = idleConf.GetSectionList('default', 'keys') - item_list.sort() - self.opt_menu_keys_builtin.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 load_configs(self): - """Load configuration for each page. - - Load configuration from default and user config files and populate - the widgets on the config dialog pages. - - Methods: - load_font_cfg - load_tab_cfg - load_theme_cfg - load_key_cfg - load_general_cfg - """ - self.load_font_cfg() - self.load_tab_cfg() - self.load_theme_cfg() - self.load_key_cfg() - self.load_general_cfg() - # note: extension page handled separately - - def save_new_key_set(self, keyset_name, keyset): - """Save a newly created core key set. - - keyset_name - string, the name of the new key set - keyset - dictionary containing the new key set - """ - 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 save_new_theme(self, theme_name, theme): - """Save a newly created theme to idleConf. - - theme_name - string, the name of the new theme - theme - dictionary containing the new theme - """ - if not idleConf.userCfg['highlight'].has_section(theme_name): - idleConf.userCfg['highlight'].add_section(theme_name) - for element in theme: - value = theme[element] - idleConf.userCfg['highlight'].SetOption(theme_name, element, value) - - def deactivate_current_config(self): - """Remove current key bindings. - - Iterate over window instances defined in parent and remove - 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() - - def activate_config_changes(self): - """Apply configuration changes to current windows. - - Dynamically update the current parent window instances - with some of the configuration changes. - """ - 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 cancel(self): - """Dismiss config dialog. - - Methods: - destroy: inherited - """ - self.destroy() - - def ok(self): - """Apply config changes, then dismiss dialog. - - Methods: - apply - destroy: inherited - """ - self.apply() - self.destroy() - - def apply(self): - """Apply config changes and leave dialog open. - - Methods: - deactivate_current_config - save_all_changed_extensions - activate_config_changes - """ - self.deactivate_current_config() - changes.save_all() - self.save_all_changed_extensions() - self.activate_config_changes() - - def help(self): - """Create textview for config dialog help. - - Attrbutes accessed: - tab_pages - - Methods: - view_text: Method from textview module. - """ - page = self.tab_pages._current_page - view_text(self, title='Help for IDLE preferences', - text=help_common+help_pages.get(page, '')) - def create_page_extensions(self): """Part of the config dialog used for configuring IDLE extensions. diff --git a/Misc/NEWS.d/next/IDLE/2017-07-27-14-48-42.bpo-31060.GdY_VY.rst b/Misc/NEWS.d/next/IDLE/2017-07-27-14-48-42.bpo-31060.GdY_VY.rst new file mode 100644 index 00000000000..1d202c7fa2c --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2017-07-27-14-48-42.bpo-31060.GdY_VY.rst @@ -0,0 +1,3 @@ +IDLE - Finish rearranging methods of ConfigDialog Grouping methods +pertaining to each tab and the buttons will aid writing tests and improving +the tabs and will enable splitting the groups into classes.