Repository: spyder-ide/spyder

Issue:
Saving a new file or renaming an existing file in master is broken
<!--- **PLEASE READ:** When submitting here, please ensure you've completed the following checklist and checked the boxes to confirm. Issue reports without it may be closed. Thanks! --->

### Issue Report Checklist

* [x] Searched the [issues page](https://github.com/spyder-ide/spyder/issues?q=is%3Aissue) for similar reports
* [x] Read the relevant sections of the [Spyder Troubleshooting Guide](https://github.com/spyder-ide/spyder/wiki/Troubleshooting-Guide-and-FAQ) and followed its advice
* [x] Reproduced the issue after updating with ``conda update spyder`` (or ``pip``, if not using Anaconda)
* [x] Could not reproduce inside ``jupyter qtconsole`` (if console-related)
* [x] Tried basic troubleshooting (if a bug/error)
    * [x] Restarted Spyder
    * [x] Reset preferences with ``spyder --reset``
    * [x] Reinstalled the latest version of [Anaconda](https://www.anaconda.com/download/)
    * [x] Tried the other applicable steps from the Troubleshooting Guide
* [x] Completed the **Problem Description**, **Steps to Reproduce** and **Version** sections below

## Problem Description

Saving a new file to disk, or renaming an existing file is not working.

### What steps reproduce the problem?

1. Create a new file
2.  Save the file

or

1. Rename an opened file with `Save As`

### What is the expected output? What do you see instead?

It should be possible to save new files and rename files.

### Paste Traceback/Error Below (if applicable)
<!--- Copy from error dialog or View > Panes > Internal Console --->

```python-traceback
  File "C:\Users\User\spyder\spyder\plugins\editor\plugin.py", line 2237, in save
    return editorstack.save(index=index, force=force)
  File "C:\Users\User\spyder\spyder\plugins\editor\widgets\editor.py", line 1716, in save
    return self.save_as(index=index)
  File "C:\Users\User\spyder\spyder\plugins\editor\widgets\editor.py", line 1865, in save_as
    new_filename=filename)
  File "C:\Users\User\spyder\spyder\plugins\editor\widgets\editor.py", line 1345, in rename_in_data
    self.outlineexplorer.file_renamed(finfo.editor, finfo.filename)
  File "C:\Users\User\spyder\spyder\plugins\outlineexplorer\widgets.py", line 610, in file_renamed
    self.treewidget.file_renamed(editor, new_filename)
  File "C:\Users\User\spyder\spyder\plugins\outlineexplorer\widgets.py", line 287, in file_renamed
    editor_id = editor.get_id()
AttributeError: 'CodeEditor' object has no attribute 'get_id'

```

## Versions
<!--- You can get this information from Help > About Spyder...
or (if Spyder won't launch) the "conda list" command
from the Anaconda Prompt/Terminal/command line. --->

* Spyder version: Spyder 4.0.0.dev0 commit https://github.com/spyder-ide/spyder/commit/c3bcb544673a3782a6f8720b9eb0f522992ea1f6
* Python version: Python 3.6.5 64bits
* Qt version: Qt 5.9.3
* PyQt version: PyQt5 5.9.2
* Operating System name/version: Windows 10

### Dependencies
<!--- Please go to the menu entry Help > Dependencies,
press the Copy to clipboard button and paste below --->

```
pyflakes >=0.6.0  :  1.6.0 (OK)
pycodestyle >=2.3 :  2.3.1 (OK)
pygments >=2.0    :  2.2.0 (OK)
sphinx >=0.6.6    :  1.7.1 (OK)
rope >=0.9.4      :  0.10.7 (OK)
jedi >=0.11.0     :  0.12.1 (OK)
nbconvert >=4.0   :  5.3.1 (OK)
pandas >=0.13.1   :  0.22.0 (OK)
numpy >=1.7       :  1.13.0 (OK)
sympy >=0.7.3     :  1.1.1 (OK)
cython >=0.21     :  0.27.3 (OK)
qtconsole >=4.2.0 :  4.4.0.dev (OK)
IPython >=4.0     :  6.2.1 (OK)
matplotlib >=2.0.0:  2.2.0 (OK)
pylint >=0.25     :  1.8.3 (OK)
```



Discussion:

Resolving patch:
diff --git a/spyder/plugins/editor/widgets/editor.py b/spyder/plugins/editor/widgets/editor.py
--- a/spyder/plugins/editor/widgets/editor.py
+++ b/spyder/plugins/editor/widgets/editor.py
@@ -1342,7 +1342,8 @@ def rename_in_data(self, original_filename, new_filename):
             # Fixes Issue 1287
             self.set_current_filename(current_fname)
         if self.outlineexplorer is not None:
-            self.outlineexplorer.file_renamed(finfo.editor, finfo.filename)
+            self.outlineexplorer.file_renamed(
+                finfo.editor.oe_proxy, finfo.filename)
         return new_index
 
     def set_stack_title(self, index, is_modified):
@@ -1425,6 +1426,13 @@ def get_current_filename(self):
         if self.data:
             return self.data[self.get_stack_index()].filename
 
+    def get_filenames(self):
+        """
+        Return a list with the names of all the files currently opened in
+        the editorstack.
+        """
+        return [finfo.filename for finfo in self.data]
+
     def has_filename(self, filename):
         """Return the self.data index position for the filename.
 


Test patch:
diff --git a/spyder/plugins/editor/widgets/tests/test_save.py b/spyder/plugins/editor/widgets/tests/test_save.py
--- a/spyder/plugins/editor/widgets/tests/test_save.py
+++ b/spyder/plugins/editor/widgets/tests/test_save.py
@@ -9,6 +9,7 @@
 """
 
 # Standard library imports
+import os.path as osp
 try:
     from unittest.mock import Mock
 except ImportError:
@@ -19,10 +20,10 @@
 
 # Local imports
 from spyder.plugins.editor.widgets import editor
+from spyder.plugins.outlineexplorer.widgets import OutlineExplorerWidget
 
 
-# Helpers
-# --------------------------------
+# ---- Helpers
 def add_files(editorstack):
     editorstack.close_action.setEnabled(False)
     editorstack.set_introspector(Mock())
@@ -38,8 +39,7 @@ def add_files(editorstack):
     editorstack.new(__file__, 'utf-8', text)
 
 
-# Qt Test Fixtures
-# --------------------------------
+# ---- Qt Test Fixtures
 @pytest.fixture
 def base_editor_bot(qtbot):
     editor_stack = editor.EditorStack(None, [])
@@ -87,8 +87,7 @@ def editor_splitter_layout_bot(editor_splitter_bot):
     return es
 
 
-# Tests
-# -------------------------------
+# ---- Tests
 @pytest.mark.show_save_dialog
 def test_save_if_changed(editor_bot, mocker):
     """Test EditorStack.save_if_changed()."""
@@ -282,6 +281,38 @@ def test_save_as(editor_bot, mocker):
     editor_stack.file_renamed_in_data = save_file_renamed_in_data
 
 
+@pytest.mark.show_save_dialog
+def test_save_as_with_outline(editor_bot, mocker, tmpdir):
+    """
+    Test EditorStack.save_as() when the outline explorer is not None.
+
+    Regression test for issue #7754.
+    """
+    editorstack, qtbot = editor_bot
+
+    # Set and assert the initial state.
+    editorstack.tabs.setCurrentIndex(1)
+    assert editorstack.get_current_filename() == 'secondtab.py'
+
+    # Add an outline explorer to the editor stack and refresh it.
+    editorstack.set_outlineexplorer(OutlineExplorerWidget())
+    qtbot.addWidget(editorstack.outlineexplorer)
+    editorstack.refresh()
+
+    # No save name.
+    mocker.patch.object(editorstack, 'select_savename', return_value=None)
+    assert editorstack.save_as() is False
+    assert editorstack.get_filenames() == ['foo.py', 'secondtab.py', __file__]
+
+    # Save secondtab.py as foo2.py in a tmpdir
+    new_filename = osp.join(tmpdir.strpath, 'foo2.py')
+    editorstack.select_savename.return_value = new_filename
+    assert not osp.exists(new_filename)
+    assert editorstack.save_as() is True
+    assert editorstack.get_filenames() == ['foo.py', new_filename, __file__]
+    assert osp.exists(new_filename)
+
+
 def test_save_copy_as(editor_bot, mocker):
     """Test EditorStack.save_copy as()."""
     editor_stack, qtbot = editor_bot