diff -r b076b62731b7 Lib/idlelib/Debugger.py --- a/Lib/idlelib/Debugger.py Mon Sep 07 19:59:38 2015 +0300 +++ b/Lib/idlelib/Debugger.py Tue Sep 08 08:34:53 2015 -0700 @@ -310,13 +310,7 @@ def load_breakpoints(self): "Load PyShellEditorWindow breakpoints into subprocess debugger" - for editwin in self.pyshell.flist.inversedict: - filename = editwin.io.filename - try: - for lineno in editwin.breakpoints: - self.set_breakpoint_here(filename, lineno) - except AttributeError: - continue + self.flist.apply_breakpoints(self.set_breakpoint_here) class StackViewer(ScrolledList): diff -r b076b62731b7 Lib/idlelib/EditorWindow.py --- a/Lib/idlelib/EditorWindow.py Mon Sep 07 19:59:38 2015 +0300 +++ b/Lib/idlelib/EditorWindow.py Tue Sep 08 08:34:53 2015 -0700 @@ -135,13 +135,9 @@ self.top = top = WindowList.ListedToplevel(root, menu=self.menubar) if flist: self.tkinter_vars = flist.vars - #self.top.instance_dict makes flist.inversedict available to - #configDialog.py so it can access all EditorWindow instances - self.top.instance_dict = flist.inversedict else: self.tkinter_vars = {} # keys: Tkinter event names # values: Tkinter variable instances - self.top.instance_dict = {} self.recent_files_path = os.path.join(idleConf.GetUserCfgDir(), 'recent-files.lst') self.text_frame = text_frame = Frame(top) @@ -217,9 +213,7 @@ text.bind("<>", self.home_callback) if flist: - flist.inversedict[self] = key - if key: - flist.dict[key] = self + flist.register_editor_window(self, key) text.bind("<>", self.new_callback) text.bind("<>", self.flist.close_all_callback) text.bind("<>", self.open_class_browser) @@ -740,6 +734,18 @@ self.top.update_windowlist_registry(self) self.ResetColorizer() + def configuration_will_change(self): + "Callback from configuration dialog before settings are applied." + self.RemoveKeybindings() + + def configuration_changed(self): + "Callback from configuration dialog after settings are applied." + self.ResetColorizer() + self.ResetFont() + self.set_notabs_indentwidth() + self.ApplyKeybindings() + self.reset_help_menu_entries() + def _addcolorizer(self): if self.color: return @@ -913,17 +919,20 @@ % str(err), parent=self.text) # for each edit window instance, construct the recent files menu - for instance in self.top.instance_dict: - menu = instance.recent_files_menu - menu.delete(0, END) # clear, and rebuild: - for i, file_name in enumerate(rf_list): - file_name = file_name.rstrip() # zap \n - # make unicode string to display non-ASCII chars correctly - ufile_name = self._filename_to_unicode(file_name) - callback = instance.__recent_file_callback(file_name) - menu.add_command(label=ulchars[i] + " " + ufile_name, - command=callback, - underline=0) + if self.flist: + self.flist.rebuild_recent_files_menu(rf_list) + + def rebuild_recent_files_menu(self, rf_list): + ulchars = "1234567890ABCDEFGHIJK" # note: duplicated from above + menu = self.recent_files_menu + menu.delete(0, END) # clear, and rebuild: + for i, file_name in enumerate(rf_list): + file_name = file_name.rstrip() # zap \n + # make unicode string to display non-ASCII chars correctly + ufile_name = self._filename_to_unicode(file_name) + callback = self.__recent_file_callback(file_name) + menu.add_command(label=ulchars[i] + " " + ufile_name, + command=callback, underline=0) def __recent_file_callback(self, file_name): def open_recent_file(fn_closure=file_name): diff -r b076b62731b7 Lib/idlelib/FileList.py --- a/Lib/idlelib/FileList.py Mon Sep 07 19:59:38 2015 +0300 +++ b/Lib/idlelib/FileList.py Tue Sep 08 08:34:53 2015 -0700 @@ -40,6 +40,11 @@ edit._close() return None + def register_editor_window(self, win, key=None): + self.inversedict[win] = key + if key: + self.dict[key] = win + def gotofileline(self, filename, lineno=None): edit = self.open(filename) if edit is not None and lineno is not None: @@ -55,6 +60,10 @@ break return "break" + def keep_running(self): + "Application should stay running while any editors are open" + return len(self.inversedict) > 0 + def unregister_maybe_terminate(self, edit): try: key = self.inversedict[edit] @@ -99,6 +108,29 @@ except KeyError: pass + def configuration_will_change(self): + "Callback from configuration dialog before settings are applied." + for w in self.inversedict.keys(): + w.configuration_will_change() + + def configuration_changed(self): + "Callback from configuration dialog after settings are applied." + for w in self.inversedict.keys(): + w.configuration_changed() + + def apply_breakpoints(self, applycmd): + "Callback from debugger asking each editor to apply it's breakpoints" + for w in self.inversedict.keys(): + try: # only PyShellEditorWindow will support this callback + w.apply_breakpoints(applycmd) + except Exception: + pass + + def rebuild_recent_files_menu(self, rf_list): + "Called when all editors need to rebuild their recent files menus" + for w in self.inversedict.keys(): + w.rebuild_recent_files_menu(rf_list) + def canonize(self, filename): if not os.path.isabs(filename): try: diff -r b076b62731b7 Lib/idlelib/PyShell.py --- a/Lib/idlelib/PyShell.py Mon Sep 07 19:59:38 2015 +0300 +++ b/Lib/idlelib/PyShell.py Tue Sep 08 08:34:53 2015 -0700 @@ -281,6 +281,15 @@ linenumber_list = self.ranges_to_linenumbers(ranges) self.breakpoints = linenumber_list + def apply_breakpoints(self, applycmd): + "Callback from debugger asking each editor to apply it's breakpoints" + filename = self.io.filename + try: + for lineno in self.breakpoints: + applycmd(filename, lineno) + except AttributeError: + pass + def ranges_to_linenumbers(self, ranges): lines = [] for index in range(0, len(ranges), 2): @@ -1599,7 +1608,7 @@ if tkversionwarning: shell.interp.runcommand("print('%s')" % tkversionwarning) - while flist.inversedict: # keep IDLE running while files are open. + while flist.keep_running(): # keep IDLE running while files are open. root.mainloop() root.destroy() capture_warnings(False) diff -r b076b62731b7 Lib/idlelib/configDialog.py --- a/Lib/idlelib/configDialog.py Mon Sep 07 19:59:38 2015 +0300 +++ b/Lib/idlelib/configDialog.py Tue Sep 08 08:34:53 2015 -0700 @@ -30,8 +30,15 @@ """ Toplevel.__init__(self, parent) self.parent = parent - if _htest: - parent.instance_dict = {} + # Hold onto the list of files the parent belongs to, as the parent + # may go away if we're not modal. The file list may not be present + # e.g. if testing where we won't be passed an editor window; to + # prevent an API change we'll try to extract it here, rather than + # asking it to be passed to us. + try: + self.flist = parent.flist + except AttributeError: + self.flist = None self.wm_withdraw() self.configure(borderwidth=5) @@ -1140,19 +1147,13 @@ def DeactivateCurrentConfig(self): #Before a config is saved, some cleanup of current #config must be done - remove the previous keybindings - winInstances = self.parent.instance_dict.keys() - for instance in winInstances: - instance.RemoveKeybindings() + if self.flist: + self.flist.configuration_will_change() def ActivateConfigChanges(self): "Dynamically apply configuration changes" - winInstances = self.parent.instance_dict.keys() - for instance in winInstances: - instance.ResetColorizer() - instance.ResetFont() - instance.set_notabs_indentwidth() - instance.ApplyKeybindings() - instance.reset_help_menu_entries() + if self.flist: + self.flist.configuration_changed() def Cancel(self): self.destroy() diff -r b076b62731b7 Lib/idlelib/macosxSupport.py --- a/Lib/idlelib/macosxSupport.py Mon Sep 07 19:59:38 2015 +0300 +++ b/Lib/idlelib/macosxSupport.py Tue Sep 08 08:34:53 2015 -0700 @@ -164,13 +164,9 @@ def config_dialog(event=None): from idlelib import configDialog - - # Ensure that the root object has an instance_dict attribute, - # mirrors code in EditorWindow (although that sets the attribute - # on an EditorWindow instance that is then passed as the first - # argument to ConfigDialog) - root.instance_dict = flist.inversedict - root.instance_dict = flist.inversedict + # Ensure that the root object has an flist so config can communicate + # with all the editor windows to inform them of changes + root.flist = flist configDialog.ConfigDialog(root, 'Settings') def help_dialog(event=None):