Repository: spyder-ide/spyder

Issue:
Editor grabs focus when opening files at startup
## Description of your problem

**What steps will reproduce the problem?**
1. In spyder open a couple of files in editor
2. Close spyder and restart
3. 

**What is the expected output? What do you see instead?**
 After the main window appears, it is grabbing focus for each file that is reopened from the previous session. In addition each of these files is put to the front of the editor window. 

Reopening files in a thread is a good idea to reduce startup time. However, at the moment this is not effective, as the user will not be able to do anything (neither in spyder nor in any other application) until all files are loaded.

**Please provide any additional information below**
## Versions and main components
- Spyder Version: 4.0.0dev 858193f
- Python Version: 2.7.12
- Operating system: osx 10.10



Discussion:
... more over, the files are opend twice if a project was active (I guess first spyder opens it's list and then later the project) -> should this be put in a separate issue?

Thanks for reporting. I opened an issue about files being opened twice at startup when a project is active. We'll fix this problem in 3.0.2.

I don't know what to do about this one though. It seems a problem when you have a lot of files opened in your last session (30, 50?), but nobody has complained about it before :-)

I think even with a handful of files it's slightly annoying though it wasn't annoying enough for me to complain about.

I think the solution would be to prevent our `load` function to steal focus at startup. Let's assign one of our juniors to it :-)

OK. Maybe I am too impatient … ;-) and maybe there is something wrong with my setup.

Anyway I can see the files open one by one (about 1-2 per second). Don’t know if others observe the same. Since I am developing a plugin, restart spyder frequently, 10 seconds waiting for my 10 files to open (20 when I have a project active) is getting on my nerves…

I imagine the quick fix would be, to not put each newly opened file on the front tab (e.g. open the one that was front last time first, then add tabs in the background without setting the focus). A way to speed up things may be to skip parsing each file (at least an outline is generated for each while loading) and deferr that to the moment the user switches to the file…. what do you think?

Cheers,
C.

> On 24 Oct 2016, at 03:55, Carlos Cordoba notifications@github.com wrote:
> 
> Thanks for reporting. I opened an issue about files being opened twice at startup when a project is active. We'll fix this problem in 3.0.2.
> 
> I don't know what to do about this one though. It seems a problem when you have a lot of files opened in your last session (30, 50?), but nobody has complained about it before :-)
> 
> —
> You are receiving this because you authored the thread.
> Reply to this email directly, view it on GitHub, or mute the thread.

## 

Christoph Gohle
christoph@gohle.org


Resolving patch:
diff --git a/spyder/plugins/editor.py b/spyder/plugins/editor.py
--- a/spyder/plugins/editor.py
+++ b/spyder/plugins/editor.py
@@ -1446,11 +1446,13 @@ def get_current_filename(self):
     def is_file_opened(self, filename=None):
         return self.editorstacks[0].is_file_opened(filename)
         
-    def set_current_filename(self, filename, editorwindow=None):
-        """Set focus to *filename* if this file has been opened
-        Return the editor instance associated to *filename*"""
+    def set_current_filename(self, filename, editorwindow=None, focus=True):
+        """Set focus to *filename* if this file has been opened.
+
+        Return the editor instance associated to *filename*.
+        """
         editorstack = self.get_current_editorstack(editorwindow)
-        return editorstack.set_current_filename(filename)
+        return editorstack.set_current_filename(filename, focus)
 
     def set_path(self):
         for finfo in self.editorstacks[0].data:
@@ -1839,27 +1841,32 @@ def _convert(fname):
             goto = [goto]
         elif goto is not None and len(goto) != len(filenames):
             goto = None
-            
+
         for index, filename in enumerate(filenames):
             # -- Do not open an already opened file
-            current_editor = self.set_current_filename(filename, editorwindow)
+            if index == 0:  # this is the last file focused in previous session
+                focus = True
+            else:
+                focus = False
+            current_editor = self.set_current_filename(filename,
+                                                       editorwindow,
+                                                       focus=focus)
             if current_editor is None:
                 # -- Not a valid filename:
                 if not osp.isfile(filename):
                     continue
                 # --
                 current_es = self.get_current_editorstack(editorwindow)
-
-                # Creating the editor widget in the first editorstack (the one
-                # that can't be destroyed), then cloning this editor widget in
-                # all other editorstacks:
+                # Creating the editor widget in the first editorstack
+                # (the one that can't be destroyed), then cloning this
+                # editor widget in all other editorstacks:
                 finfo = self.editorstacks[0].load(filename, set_current=False)
                 finfo.path = self.main.get_spyder_pythonpath()
                 self._clone_file_everywhere(finfo)
-                current_editor = current_es.set_current_filename(filename)
+                current_editor = current_es.set_current_filename(filename,
+                                                                 focus=focus)
                 current_editor.set_breakpoints(load_breakpoints(filename))
                 self.register_widget_shortcuts(current_editor)
-
                 current_es.analyze_script()
                 self.__add_recent_file(filename)
             if goto is not None: # 'word' is assumed to be None as well
@@ -2602,12 +2609,15 @@ def setup_open_files(self):
         else:
             filenames = self.get_option('filenames', default=[])
         self.close_all_files()
- 
+
         if filenames and any([osp.isfile(f) for f in filenames]):
-            self.load(filenames)
+            filenames = self.reorder_filenames(filenames)
             layout = self.get_option('layout_settings', None)
+            is_vertical, cfname, clines = layout.get('splitsettings')[0]
+            self.load(filenames, goto=clines)
             if layout is not None:
-                self.editorsplitter.set_layout_settings(layout)
+                self.editorsplitter.set_layout_settings(layout,
+                                                        dont_goto=filenames[0])
             win_layout = self.get_option('windows_layout_settings', None)
             if win_layout:
                 for layout_settings in win_layout:
@@ -2617,6 +2627,33 @@ def setup_open_files(self):
             self.__load_temp_file()
         self.set_create_new_file_if_empty(True)
 
+    def reorder_filenames(self, filenames):
+        """Take the last session filenames and put the last open on first.
+
+        It takes a list of filenames and using the current filename from the 
+        layout settings, sets the one that had focused last in the position 0. 
+        It also reorders the current lines for each file (supposing that they 
+        are in the same order as the filenames) and sets them back in the 
+        layout settings.
+        """
+        layout = self.get_option('layout_settings', None)
+        splitsettings = layout.get('splitsettings')
+        index_first_file = 0
+        reordered_splitsettings = []
+        for index, (is_vertical, cfname, clines) in enumerate(splitsettings):
+            #the first element of filenames is now the one that last had focus
+            if index == 0:
+                index_first_file = filenames.index(cfname)
+                filenames.pop(index_first_file)
+                filenames.insert(0, cfname)
+            clines_0 = clines[0]
+            clines.pop(index_first_file)
+            clines.insert(0, clines_0)
+            reordered_splitsettings.append((is_vertical, cfname, clines))
+        layout['splitsettings'] = reordered_splitsettings
+        self.set_option('layout_settings', layout)
+        return filenames
+
     def save_open_files(self):
         """Save the list of open files"""
         self.set_option('filenames', self.get_open_filenames())
diff --git a/spyder/widgets/editor.py b/spyder/widgets/editor.py
--- a/spyder/widgets/editor.py
+++ b/spyder/widgets/editor.py
@@ -1122,13 +1122,15 @@ def has_filename(self, filename):
             if fixpath(filename) == fixpath(finfo.filename):
                 return index
 
-    def set_current_filename(self, filename):
-        """Set current filename and return the associated editor instance"""
+    def set_current_filename(self, filename, focus=True):
+        """Set current filename and return the associated editor instance."""
         index = self.has_filename(filename)
         if index is not None:
-            self.set_stack_index(index)
+            if focus:
+                self.set_stack_index(index)
             editor = self.data[index].editor
-            editor.setFocus()
+            if focus:
+                editor.setFocus()
             return editor
 
     def is_file_opened(self, filename=None):
@@ -2075,8 +2077,8 @@ def get_layout_settings(self):
         return dict(hexstate=qbytearray_to_str(self.saveState()),
                     sizes=self.sizes(), splitsettings=splitsettings)
 
-    def set_layout_settings(self, settings):
-        """Restore layout state"""
+    def set_layout_settings(self, settings, dont_goto=None):
+        """Restore layout state."""
         splitsettings = settings.get('splitsettings')
         if splitsettings is None:
             return
@@ -2089,12 +2091,17 @@ def set_layout_settings(self, settings):
             editorstack = splitter.widget(0)
             for index, finfo in enumerate(editorstack.data):
                 editor = finfo.editor
-                # FIXME: Temporal fix
-                try:
-                    editor.go_to_line(clines[index])
-                except IndexError:
+                # TODO: go_to_line is not working properly (the line it jumps
+                # to is not the corresponding to that file). This will be fixed
+                # in a future PR (which will fix issue #3857)
+                if dont_goto is not None:
+                    # skip go to line for first file because is already there
                     pass
-            editorstack.set_current_filename(cfname)
+                else:
+                    try:
+                        editor.go_to_line(clines[index])
+                    except IndexError:
+                        pass
         hexstate = settings.get('hexstate')
         if hexstate is not None:
             self.restoreState( QByteArray().fromHex(


Test patch: