summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/idlelib/configdialog.py1540
-rw-r--r--Misc/NEWS.d/next/IDLE/2017-07-27-14-48-42.bpo-31060.GdY_VY.rst3
2 files changed, 775 insertions, 768 deletions
diff --git a/Lib/idlelib/configdialog.py b/Lib/idlelib/configdialog.py
index daaa344..e359ec2 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,406 +626,57 @@ class ConfigDialog(Toplevel):
self.new_custom_theme.pack(side=TOP, fill=X, pady=5)
return frame
- def create_page_keys(self):
- """Return frame of widgets for Keys tab.
-
- Tk Variables:
- builtin_keys: Menu variable for built-in keybindings.
- custom_keys: Menu variable for custom keybindings.
- are_keys_builtin: Selector for built-in or custom keybindings.
- keybinding: Action/key bindings.
-
- Methods:
- load_key_config: Set table.
- load_keys_list: Reload active set.
- keybinding_selected: Bound to list_bindings button release.
- get_new_keys: Command for button_new_keys.
- get_new_keys_name: Call popup.
- create_new_key_set: Combine active keyset and changes.
- set_keys_type: Command for are_keys_builtin.
- delete_custom_keys: Command for button_delete_custom_keys.
- save_as_new_key_set: Command for button_save_custom_keys.
- save_new_key_set: Save to idleConf.userCfg['keys'] (is function).
- deactivate_current_config: Remove keys bindings in editors.
-
- Widget Structure: (*) widgets bound to self
- frame
- frame_custom: LabelFrame
- frame_target: Frame
- target_title: Label
- scroll_target_y: Scrollbar
- scroll_target_x: Scrollbar
- (*)list_bindings: ListBox
- (*)button_new_keys: Button
- frame_key_sets: LabelFrame
- frames[0]: Frame
- (*)radio_keys_builtin: Radiobutton - are_keys_builtin
- (*)radio_keys_custom: Radiobutton - are_keys_builtin
- (*)opt_menu_keys_builtin: DynOptionMenu - builtin_keys
- (*)opt_menu_keys_custom: DynOptionMenu - custom_keys
- (*)new_custom_keys: Label
- frames[1]: Frame
- (*)button_delete_custom_keys: Button
- button_save_custom_keys: Button
- """
- parent = self.parent
- self.builtin_keys = StringVar(parent)
- self.custom_keys = StringVar(parent)
- self.are_keys_builtin = BooleanVar(parent)
- self.keybinding = StringVar(parent)
-
- ##widget creation
- #body frame
- frame = self.tab_pages.pages['Keys'].frame
- #body section frames
- 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.list_bindings = Listbox(
- frame_target, takefocus=FALSE, exportselection=FALSE)
- self.list_bindings.bind('<ButtonRelease-1>', self.keybinding_selected)
- scroll_target_y.config(command=self.list_bindings.yview)
- scroll_target_x.config(command=self.list_bindings.xview)
- self.list_bindings.config(yscrollcommand=scroll_target_y.set)
- self.list_bindings.config(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.radio_keys_builtin = Radiobutton(
- frames[0], variable=self.are_keys_builtin, value=1,
- command=self.set_keys_type, text='Use a Built-in Key Set')
- self.radio_keys_custom = Radiobutton(
- frames[0], variable=self.are_keys_builtin, value=0,
- command=self.set_keys_type, text='Use a Custom Key Set')
- self.opt_menu_keys_builtin = DynOptionMenu(
- frames[0], self.builtin_keys, None, command=None)
- self.opt_menu_keys_custom = DynOptionMenu(
- frames[0], self.custom_keys, None, command=None)
- self.button_delete_custom_keys = Button(
- frames[1], text='Delete Custom Key Set',
- command=self.delete_custom_keys)
- button_save_custom_keys = Button(
- frames[1], text='Save as New Custom Key Set',
- command=self.save_as_new_key_set)
- self.new_custom_keys = 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.list_bindings.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.radio_keys_builtin.grid(row=0, column=0, sticky=W+NS)
- self.radio_keys_custom.grid(row=1, column=0, sticky=W+NS)
- self.opt_menu_keys_builtin.grid(row=0, column=1, sticky=NSEW)
- self.opt_menu_keys_custom.grid(row=1, column=1, sticky=NSEW)
- self.new_custom_keys.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)
- 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 create_page_general(self):
- """Return frame of widgets for General tab.
-
- Enable users to provisionally change general options. Function
- load_general_cfg intializes tk variables and helplist using
- idleConf. Radiobuttons startup_shell_on and startup_editor_on
- set var startup_edit. Radiobuttons save_ask_on and save_auto_on
- set var autosave. Entry boxes win_width_int and win_height_int
- set var win_width and win_height. Setting var_name invokes the
- var_changed_var_name callback that adds option to changes.
-
- Helplist: load_general_cfg loads list user_helplist with
- name, position pairs and copies names to listbox helplist.
- Clicking a name invokes help_source selected. Clicking
- button_helplist_name invokes helplist_item_name, which also
- changes user_helplist. These functions all call
- set_add_delete_state. All but load call update_help_changes to
- rewrite changes['main']['HelpFiles'].
-
- Widget Structure: (*) widgets bound to self
- frame
- frame_run: LabelFrame
- startup_title: Label
- (*)startup_editor_on: Radiobutton - startup_edit
- (*)startup_shell_on: Radiobutton - startup_edit
- frame_save: LabelFrame
- run_save_title: Label
- (*)save_ask_on: Radiobutton - autosave
- (*)save_auto_on: Radiobutton - autosave
- frame_win_size: LabelFrame
- win_size_title: Label
- win_width_title: Label
- (*)win_width_int: Entry - win_width
- win_height_title: Label
- (*)win_height_int: Entry - win_height
- frame_help: LabelFrame
- frame_helplist: Frame
- frame_helplist_buttons: Frame
- (*)button_helplist_edit
- (*)button_helplist_add
- (*)button_helplist_remove
- (*)helplist: ListBox
- scroll_helplist: Scrollbar
- """
- parent = self.parent
- self.startup_edit = IntVar(parent)
- self.autosave = IntVar(parent)
- self.win_width = StringVar(parent)
- self.win_height = StringVar(parent)
-
- # Create widgets:
- # body.
- frame = self.tab_pages.pages['General'].frame
- # body section frames.
- frame_run = LabelFrame(frame, borderwidth=2, relief=GROOVE,
- text=' Startup Preferences ')
- frame_save = LabelFrame(frame, borderwidth=2, relief=GROOVE,
- text=' autosave Preferences ')
- frame_win_size = Frame(frame, borderwidth=2, relief=GROOVE)
- frame_help = LabelFrame(frame, borderwidth=2, relief=GROOVE,
- text=' Additional Help Sources ')
- # frame_run.
- startup_title = Label(frame_run, text='At Startup')
- self.startup_editor_on = Radiobutton(
- frame_run, variable=self.startup_edit, value=1,
- text="Open Edit Window")
- self.startup_shell_on = Radiobutton(
- frame_run, variable=self.startup_edit, value=0,
- text='Open Shell Window')
- # frame_save.
- run_save_title = Label(frame_save, text='At Start of Run (F5) ')
- self.save_ask_on = Radiobutton(
- frame_save, variable=self.autosave, value=0,
- text="Prompt to Save")
- self.save_auto_on = Radiobutton(
- frame_save, variable=self.autosave, value=1,
- text='No Prompt')
- # frame_win_size.
- win_size_title = Label(
- frame_win_size, text='Initial Window Size (in characters)')
- win_width_title = Label(frame_win_size, text='Width')
- self.win_width_int = Entry(
- frame_win_size, textvariable=self.win_width, width=3)
- win_height_title = Label(frame_win_size, text='Height')
- self.win_height_int = Entry(
- frame_win_size, textvariable=self.win_height, width=3)
- # frame_help.
- frame_helplist = Frame(frame_help)
- frame_helplist_buttons = Frame(frame_helplist)
- self.helplist = Listbox(
- frame_helplist, height=5, takefocus=FALSE,
- exportselection=FALSE)
- scroll_helplist = Scrollbar(frame_helplist)
- scroll_helplist['command'] = self.helplist.yview
- self.helplist['yscrollcommand'] = scroll_helplist.set
- self.helplist.bind('<ButtonRelease-1>', self.help_source_selected)
- self.button_helplist_edit = Button(
- frame_helplist_buttons, text='Edit', state=DISABLED,
- width=8, command=self.helplist_item_edit)
- self.button_helplist_add = Button(
- frame_helplist_buttons, text='Add',
- width=8, command=self.helplist_item_add)
- self.button_helplist_remove = Button(
- frame_helplist_buttons, text='Remove', state=DISABLED,
- width=8, command=self.helplist_item_remove)
-
- # Pack widgets:
- # body.
- frame_run.pack(side=TOP, padx=5, pady=5, fill=X)
- frame_save.pack(side=TOP, padx=5, pady=5, fill=X)
- frame_win_size.pack(side=TOP, padx=5, pady=5, fill=X)
- frame_help.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
- # frame_run.
- startup_title.pack(side=LEFT, anchor=W, padx=5, pady=5)
- self.startup_shell_on.pack(side=RIGHT, anchor=W, padx=5, pady=5)
- self.startup_editor_on.pack(side=RIGHT, anchor=W, padx=5, pady=5)
- # frame_save.
- run_save_title.pack(side=LEFT, anchor=W, padx=5, pady=5)
- self.save_auto_on.pack(side=RIGHT, anchor=W, padx=5, pady=5)
- self.save_ask_on.pack(side=RIGHT, anchor=W, padx=5, pady=5)
- # frame_win_size.
- win_size_title.pack(side=LEFT, anchor=W, padx=5, pady=5)
- self.win_height_int.pack(side=RIGHT, anchor=E, padx=10, pady=5)
- win_height_title.pack(side=RIGHT, anchor=E, pady=5)
- self.win_width_int.pack(side=RIGHT, anchor=E, padx=10, pady=5)
- win_width_title.pack(side=RIGHT, anchor=E, pady=5)
- # frame_help.
- frame_helplist_buttons.pack(side=RIGHT, padx=5, pady=5, fill=Y)
- frame_helplist.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
- scroll_helplist.pack(side=RIGHT, anchor=W, fill=Y)
- self.helplist.pack(side=LEFT, anchor=E, expand=TRUE, fill=BOTH)
- self.button_helplist_edit.pack(side=TOP, anchor=W, pady=5)
- self.button_helplist_add.pack(side=TOP, anchor=W)
- self.button_helplist_remove.pack(side=TOP, anchor=W, pady=5)
-
- return frame
-
- def load_general_cfg(self):
- "Load current configuration settings for the general options."
- # Set startup state.
- self.startup_edit.set(idleConf.GetOption(
- 'main', 'General', 'editor-on-startup', default=0, type='bool'))
- # Set autosave state.
- self.autosave.set(idleConf.GetOption(
- 'main', 'General', 'autosave', default=0, type='bool'))
- # Set initial window size.
- self.win_width.set(idleConf.GetOption(
- 'main', 'EditorWindow', 'width', type='int'))
- self.win_height.set(idleConf.GetOption(
- 'main', 'EditorWindow', 'height', type='int'))
- # Set additional help sources.
- self.user_helplist = idleConf.GetAllExtraHelpSourcesList()
- self.helplist.delete(0, 'end')
- for help_item in self.user_helplist:
- self.helplist.insert(END, help_item[0])
- self.set_add_delete_state()
-
- def var_changed_startup_edit(self, *params):
- "Store change to toggle for starting IDLE in the editor or shell."
- value = self.startup_edit.get()
- changes.add_option('main', 'General', 'editor-on-startup', value)
-
- def var_changed_autosave(self, *params):
- "Store change to autosave."
- value = self.autosave.get()
- changes.add_option('main', 'General', 'autosave', value)
-
- def var_changed_win_width(self, *params):
- "Store change to window width."
- value = self.win_width.get()
- changes.add_option('main', 'EditorWindow', 'width', value)
-
- def var_changed_win_height(self, *params):
- "Store change to window height."
- value = self.win_height.get()
- changes.add_option('main', 'EditorWindow', 'height', value)
-
- def help_source_selected(self, event):
- "Handle event for selecting additional help."
- self.set_add_delete_state()
-
- def set_add_delete_state(self):
- "Toggle the state for the help list buttons based on list entries."
- if self.helplist.size() < 1: # No entries in list.
- self.button_helplist_edit['state'] = DISABLED
- self.button_helplist_remove['state'] = DISABLED
- else: # Some entries.
- if self.helplist.curselection(): # There currently is a selection.
- self.button_helplist_edit['state'] = NORMAL
- self.button_helplist_remove['state'] = NORMAL
- else: # There currently is not a selection.
- self.button_helplist_edit['state'] = DISABLED
- self.button_helplist_remove['state'] = DISABLED
-
- def helplist_item_add(self):
- """Handle add button for the help list.
-
- Query for name and location of new help sources and add
- them to the list.
- """
- help_source = HelpSource(self, 'New Help Source').result
- if help_source:
- self.user_helplist.append(help_source)
- self.helplist.insert(END, help_source[0])
- self.update_help_changes()
-
- def helplist_item_edit(self):
- """Handle edit button for the help list.
+ def load_theme_cfg(self):
+ """Load current configuration settings for the theme options.
- Query with existing help source information and update
- config if the values are changed.
- """
- item_index = self.helplist.index(ANCHOR)
- help_source = self.user_helplist[item_index]
- new_help_source = HelpSource(
- self, 'Edit Help Source',
- menuitem=help_source[0],
- filepath=help_source[1],
- ).result
- if new_help_source and new_help_source != help_source:
- self.user_helplist[item_index] = new_help_source
- self.helplist.delete(item_index)
- self.helplist.insert(item_index, new_help_source[0])
- self.update_help_changes()
- self.set_add_delete_state() # Selected will be un-selected
+ 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.
- def helplist_item_remove(self):
- """Handle remove button for the help list.
+ 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.
- Delete the help list item from config.
+ Methods:
+ set_theme_type
+ paint_theme_sample
+ set_highlight_target
"""
- item_index = self.helplist.index(ANCHOR)
- del(self.user_helplist[item_index])
- self.helplist.delete(item_index)
- self.update_help_changes()
- self.set_add_delete_state()
-
- def update_help_changes(self):
- "Clear and rebuild the HelpFiles section in changes"
- changes['main']['HelpFiles'] = {}
- for num in range(1, len(self.user_helplist) + 1):
- changes.add_option(
- 'main', 'HelpFiles', str(num),
- ';'.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()
+ # 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.
@@ -976,59 +722,14 @@ class ConfigDialog(Toplevel):
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 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.
@@ -1057,218 +758,6 @@ class ConfigDialog(Toplevel):
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.
@@ -1470,57 +959,184 @@ class ConfigDialog(Toplevel):
self.highlight_sample.tag_config(element, **colors)
self.set_color_sample()
- def load_theme_cfg(self):
- """Load current configuration settings for the theme options.
+ def save_new_theme(self, theme_name, theme):
+ """Save a newly created theme to idleConf.
- 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.
+ 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:
- 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.
+ 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
- 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])
+ 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()
- # 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 create_page_keys(self):
+ """Return frame of widgets for Keys tab.
+
+ Tk Variables:
+ builtin_keys: Menu variable for built-in keybindings.
+ custom_keys: Menu variable for custom keybindings.
+ are_keys_builtin: Selector for built-in or custom keybindings.
+ keybinding: Action/key bindings.
+
+ Methods:
+ load_key_config: Set table.
+ load_keys_list: Reload active set.
+ keybinding_selected: Bound to list_bindings button release.
+ get_new_keys: Command for button_new_keys.
+ get_new_keys_name: Call popup.
+ create_new_key_set: Combine active keyset and changes.
+ set_keys_type: Command for are_keys_builtin.
+ delete_custom_keys: Command for button_delete_custom_keys.
+ save_as_new_key_set: Command for button_save_custom_keys.
+ save_new_key_set: Save to idleConf.userCfg['keys'] (is function).
+ deactivate_current_config: Remove keys bindings in editors.
+
+ Widget Structure: (*) widgets bound to self
+ frame
+ frame_custom: LabelFrame
+ frame_target: Frame
+ target_title: Label
+ scroll_target_y: Scrollbar
+ scroll_target_x: Scrollbar
+ (*)list_bindings: ListBox
+ (*)button_new_keys: Button
+ frame_key_sets: LabelFrame
+ frames[0]: Frame
+ (*)radio_keys_builtin: Radiobutton - are_keys_builtin
+ (*)radio_keys_custom: Radiobutton - are_keys_builtin
+ (*)opt_menu_keys_builtin: DynOptionMenu - builtin_keys
+ (*)opt_menu_keys_custom: DynOptionMenu - custom_keys
+ (*)new_custom_keys: Label
+ frames[1]: Frame
+ (*)button_delete_custom_keys: Button
+ button_save_custom_keys: Button
+ """
+ parent = self.parent
+ self.builtin_keys = StringVar(parent)
+ self.custom_keys = StringVar(parent)
+ self.are_keys_builtin = BooleanVar(parent)
+ self.keybinding = StringVar(parent)
+
+ ##widget creation
+ #body frame
+ frame = self.tab_pages.pages['Keys'].frame
+ #body section frames
+ 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.list_bindings = Listbox(
+ frame_target, takefocus=FALSE, exportselection=FALSE)
+ self.list_bindings.bind('<ButtonRelease-1>', self.keybinding_selected)
+ scroll_target_y.config(command=self.list_bindings.yview)
+ scroll_target_x.config(command=self.list_bindings.xview)
+ self.list_bindings.config(yscrollcommand=scroll_target_y.set)
+ self.list_bindings.config(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.radio_keys_builtin = Radiobutton(
+ frames[0], variable=self.are_keys_builtin, value=1,
+ command=self.set_keys_type, text='Use a Built-in Key Set')
+ self.radio_keys_custom = Radiobutton(
+ frames[0], variable=self.are_keys_builtin, value=0,
+ command=self.set_keys_type, text='Use a Custom Key Set')
+ self.opt_menu_keys_builtin = DynOptionMenu(
+ frames[0], self.builtin_keys, None, command=None)
+ self.opt_menu_keys_custom = DynOptionMenu(
+ frames[0], self.custom_keys, None, command=None)
+ self.button_delete_custom_keys = Button(
+ frames[1], text='Delete Custom Key Set',
+ command=self.delete_custom_keys)
+ button_save_custom_keys = Button(
+ frames[1], text='Save as New Custom Key Set',
+ command=self.save_as_new_key_set)
+ self.new_custom_keys = 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.list_bindings.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.radio_keys_builtin.grid(row=0, column=0, sticky=W+NS)
+ self.radio_keys_custom.grid(row=1, column=0, sticky=W+NS)
+ self.opt_menu_keys_builtin.grid(row=0, column=1, sticky=NSEW)
+ self.opt_menu_keys_custom.grid(row=1, column=1, sticky=NSEW)
+ self.new_custom_keys.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)
+ 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."
@@ -1553,25 +1169,188 @@ class ConfigDialog(Toplevel):
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
+
+ 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.
"""
- 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
+ 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.
@@ -1585,17 +1364,39 @@ class ConfigDialog(Toplevel):
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.
+ def delete_custom_keys(self):
+ """Handle event to delete a custom key set.
- theme_name - string, the name of the new theme
- theme - dictionary containing the new theme
+ Applying the delete deactivates the current configuration and
+ reverts to the default. The custom key set is permanently
+ deleted from the config file.
"""
- 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)
+ 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.
@@ -1623,49 +1424,252 @@ class ConfigDialog(Toplevel):
instance.ApplyKeybindings()
instance.reset_help_menu_entries()
- def cancel(self):
- """Dismiss config dialog.
- Methods:
- destroy: inherited
- """
- self.destroy()
+ def create_page_general(self):
+ """Return frame of widgets for General tab.
- def ok(self):
- """Apply config changes, then dismiss dialog.
+ Enable users to provisionally change general options. Function
+ load_general_cfg intializes tk variables and helplist using
+ idleConf. Radiobuttons startup_shell_on and startup_editor_on
+ set var startup_edit. Radiobuttons save_ask_on and save_auto_on
+ set var autosave. Entry boxes win_width_int and win_height_int
+ set var win_width and win_height. Setting var_name invokes the
+ var_changed_var_name callback that adds option to changes.
- Methods:
- apply
- destroy: inherited
+ Helplist: load_general_cfg loads list user_helplist with
+ name, position pairs and copies names to listbox helplist.
+ Clicking a name invokes help_source selected. Clicking
+ button_helplist_name invokes helplist_item_name, which also
+ changes user_helplist. These functions all call
+ set_add_delete_state. All but load call update_help_changes to
+ rewrite changes['main']['HelpFiles'].
+
+ Widget Structure: (*) widgets bound to self
+ frame
+ frame_run: LabelFrame
+ startup_title: Label
+ (*)startup_editor_on: Radiobutton - startup_edit
+ (*)startup_shell_on: Radiobutton - startup_edit
+ frame_save: LabelFrame
+ run_save_title: Label
+ (*)save_ask_on: Radiobutton - autosave
+ (*)save_auto_on: Radiobutton - autosave
+ frame_win_size: LabelFrame
+ win_size_title: Label
+ win_width_title: Label
+ (*)win_width_int: Entry - win_width
+ win_height_title: Label
+ (*)win_height_int: Entry - win_height
+ frame_help: LabelFrame
+ frame_helplist: Frame
+ frame_helplist_buttons: Frame
+ (*)button_helplist_edit
+ (*)button_helplist_add
+ (*)button_helplist_remove
+ (*)helplist: ListBox
+ scroll_helplist: Scrollbar
"""
- self.apply()
- self.destroy()
+ parent = self.parent
+ self.startup_edit = IntVar(parent)
+ self.autosave = IntVar(parent)
+ self.win_width = StringVar(parent)
+ self.win_height = StringVar(parent)
- def apply(self):
- """Apply config changes and leave dialog open.
+ # Create widgets:
+ # body.
+ frame = self.tab_pages.pages['General'].frame
+ # body section frames.
+ frame_run = LabelFrame(frame, borderwidth=2, relief=GROOVE,
+ text=' Startup Preferences ')
+ frame_save = LabelFrame(frame, borderwidth=2, relief=GROOVE,
+ text=' autosave Preferences ')
+ frame_win_size = Frame(frame, borderwidth=2, relief=GROOVE)
+ frame_help = LabelFrame(frame, borderwidth=2, relief=GROOVE,
+ text=' Additional Help Sources ')
+ # frame_run.
+ startup_title = Label(frame_run, text='At Startup')
+ self.startup_editor_on = Radiobutton(
+ frame_run, variable=self.startup_edit, value=1,
+ text="Open Edit Window")
+ self.startup_shell_on = Radiobutton(
+ frame_run, variable=self.startup_edit, value=0,
+ text='Open Shell Window')
+ # frame_save.
+ run_save_title = Label(frame_save, text='At Start of Run (F5) ')
+ self.save_ask_on = Radiobutton(
+ frame_save, variable=self.autosave, value=0,
+ text="Prompt to Save")
+ self.save_auto_on = Radiobutton(
+ frame_save, variable=self.autosave, value=1,
+ text='No Prompt')
+ # frame_win_size.
+ win_size_title = Label(
+ frame_win_size, text='Initial Window Size (in characters)')
+ win_width_title = Label(frame_win_size, text='Width')
+ self.win_width_int = Entry(
+ frame_win_size, textvariable=self.win_width, width=3)
+ win_height_title = Label(frame_win_size, text='Height')
+ self.win_height_int = Entry(
+ frame_win_size, textvariable=self.win_height, width=3)
+ # frame_help.
+ frame_helplist = Frame(frame_help)
+ frame_helplist_buttons = Frame(frame_helplist)
+ self.helplist = Listbox(
+ frame_helplist, height=5, takefocus=FALSE,
+ exportselection=FALSE)
+ scroll_helplist = Scrollbar(frame_helplist)
+ scroll_helplist['command'] = self.helplist.yview
+ self.helplist['yscrollcommand'] = scroll_helplist.set
+ self.helplist.bind('<ButtonRelease-1>', self.help_source_selected)
+ self.button_helplist_edit = Button(
+ frame_helplist_buttons, text='Edit', state=DISABLED,
+ width=8, command=self.helplist_item_edit)
+ self.button_helplist_add = Button(
+ frame_helplist_buttons, text='Add',
+ width=8, command=self.helplist_item_add)
+ self.button_helplist_remove = Button(
+ frame_helplist_buttons, text='Remove', state=DISABLED,
+ width=8, command=self.helplist_item_remove)
- Methods:
- deactivate_current_config
- save_all_changed_extensions
- activate_config_changes
+ # Pack widgets:
+ # body.
+ frame_run.pack(side=TOP, padx=5, pady=5, fill=X)
+ frame_save.pack(side=TOP, padx=5, pady=5, fill=X)
+ frame_win_size.pack(side=TOP, padx=5, pady=5, fill=X)
+ frame_help.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
+ # frame_run.
+ startup_title.pack(side=LEFT, anchor=W, padx=5, pady=5)
+ self.startup_shell_on.pack(side=RIGHT, anchor=W, padx=5, pady=5)
+ self.startup_editor_on.pack(side=RIGHT, anchor=W, padx=5, pady=5)
+ # frame_save.
+ run_save_title.pack(side=LEFT, anchor=W, padx=5, pady=5)
+ self.save_auto_on.pack(side=RIGHT, anchor=W, padx=5, pady=5)
+ self.save_ask_on.pack(side=RIGHT, anchor=W, padx=5, pady=5)
+ # frame_win_size.
+ win_size_title.pack(side=LEFT, anchor=W, padx=5, pady=5)
+ self.win_height_int.pack(side=RIGHT, anchor=E, padx=10, pady=5)
+ win_height_title.pack(side=RIGHT, anchor=E, pady=5)
+ self.win_width_int.pack(side=RIGHT, anchor=E, padx=10, pady=5)
+ win_width_title.pack(side=RIGHT, anchor=E, pady=5)
+ # frame_help.
+ frame_helplist_buttons.pack(side=RIGHT, padx=5, pady=5, fill=Y)
+ frame_helplist.pack(side=TOP, padx=5, pady=5, expand=TRUE, fill=BOTH)
+ scroll_helplist.pack(side=RIGHT, anchor=W, fill=Y)
+ self.helplist.pack(side=LEFT, anchor=E, expand=TRUE, fill=BOTH)
+ self.button_helplist_edit.pack(side=TOP, anchor=W, pady=5)
+ self.button_helplist_add.pack(side=TOP, anchor=W)
+ self.button_helplist_remove.pack(side=TOP, anchor=W, pady=5)
+
+ return frame
+
+ def load_general_cfg(self):
+ "Load current configuration settings for the general options."
+ # Set startup state.
+ self.startup_edit.set(idleConf.GetOption(
+ 'main', 'General', 'editor-on-startup', default=0, type='bool'))
+ # Set autosave state.
+ self.autosave.set(idleConf.GetOption(
+ 'main', 'General', 'autosave', default=0, type='bool'))
+ # Set initial window size.
+ self.win_width.set(idleConf.GetOption(
+ 'main', 'EditorWindow', 'width', type='int'))
+ self.win_height.set(idleConf.GetOption(
+ 'main', 'EditorWindow', 'height', type='int'))
+ # Set additional help sources.
+ self.user_helplist = idleConf.GetAllExtraHelpSourcesList()
+ self.helplist.delete(0, 'end')
+ for help_item in self.user_helplist:
+ self.helplist.insert(END, help_item[0])
+ self.set_add_delete_state()
+
+ def var_changed_startup_edit(self, *params):
+ "Store change to toggle for starting IDLE in the editor or shell."
+ value = self.startup_edit.get()
+ changes.add_option('main', 'General', 'editor-on-startup', value)
+
+ def var_changed_autosave(self, *params):
+ "Store change to autosave."
+ value = self.autosave.get()
+ changes.add_option('main', 'General', 'autosave', value)
+
+ def var_changed_win_width(self, *params):
+ "Store change to window width."
+ value = self.win_width.get()
+ changes.add_option('main', 'EditorWindow', 'width', value)
+
+ def var_changed_win_height(self, *params):
+ "Store change to window height."
+ value = self.win_height.get()
+ changes.add_option('main', 'EditorWindow', 'height', value)
+
+ def help_source_selected(self, event):
+ "Handle event for selecting additional help."
+ self.set_add_delete_state()
+
+ def set_add_delete_state(self):
+ "Toggle the state for the help list buttons based on list entries."
+ if self.helplist.size() < 1: # No entries in list.
+ self.button_helplist_edit['state'] = DISABLED
+ self.button_helplist_remove['state'] = DISABLED
+ else: # Some entries.
+ if self.helplist.curselection(): # There currently is a selection.
+ self.button_helplist_edit['state'] = NORMAL
+ self.button_helplist_remove['state'] = NORMAL
+ else: # There currently is not a selection.
+ self.button_helplist_edit['state'] = DISABLED
+ self.button_helplist_remove['state'] = DISABLED
+
+ def helplist_item_add(self):
+ """Handle add button for the help list.
+
+ Query for name and location of new help sources and add
+ them to the list.
"""
- self.deactivate_current_config()
- changes.save_all()
- self.save_all_changed_extensions()
- self.activate_config_changes()
+ help_source = HelpSource(self, 'New Help Source').result
+ if help_source:
+ self.user_helplist.append(help_source)
+ self.helplist.insert(END, help_source[0])
+ self.update_help_changes()
- def help(self):
- """Create textview for config dialog help.
+ def helplist_item_edit(self):
+ """Handle edit button for the help list.
- Attrbutes accessed:
- tab_pages
+ Query with existing help source information and update
+ config if the values are changed.
+ """
+ item_index = self.helplist.index(ANCHOR)
+ help_source = self.user_helplist[item_index]
+ new_help_source = HelpSource(
+ self, 'Edit Help Source',
+ menuitem=help_source[0],
+ filepath=help_source[1],
+ ).result
+ if new_help_source and new_help_source != help_source:
+ self.user_helplist[item_index] = new_help_source
+ self.helplist.delete(item_index)
+ self.helplist.insert(item_index, new_help_source[0])
+ self.update_help_changes()
+ self.set_add_delete_state() # Selected will be un-selected
- Methods:
- view_text: Method from textview module.
+ def helplist_item_remove(self):
+ """Handle remove button for the help list.
+
+ Delete the help list item from config.
"""
- page = self.tab_pages._current_page
- view_text(self, title='Help for IDLE preferences',
- text=help_common+help_pages.get(page, ''))
+ item_index = self.helplist.index(ANCHOR)
+ del(self.user_helplist[item_index])
+ self.helplist.delete(item_index)
+ self.update_help_changes()
+ self.set_add_delete_state()
+
+ def update_help_changes(self):
+ "Clear and rebuild the HelpFiles section in changes"
+ changes['main']['HelpFiles'] = {}
+ for num in range(1, len(self.user_helplist) + 1):
+ changes.add_option(
+ 'main', 'HelpFiles', str(num),
+ ';'.join(self.user_helplist[num-1][:2]))
+
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 0000000..1d202c7
--- /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.