summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTerry Jan Reedy <tjreedy@udel.edu>2017-07-27 22:28:01 (GMT)
committerGitHub <noreply@github.com>2017-07-27 22:28:01 (GMT)
commitb1660800f4f519dbfab9e5a4ad3eae1cfabab3ed (patch)
treee16e97401bf801c066a8b82b80f25a1413d95b57
parent12953ffe12ac781332b384c36b25d12216b1db62 (diff)
downloadcpython-b1660800f4f519dbfab9e5a4ad3eae1cfabab3ed.zip
cpython-b1660800f4f519dbfab9e5a4ad3eae1cfabab3ed.tar.gz
cpython-b1660800f4f519dbfab9e5a4ad3eae1cfabab3ed.tar.bz2
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.
-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.