Repository: spyder-ide/spyder

Issue:
Edit menu items greyed out after update to Spyder 3.1.0
## Description of your problem
After updating to Spyder 3.1.0, all items in the "Edit" dropdown menu are greyed out and unselectable. The keyboard shortcuts (e.g. CTRL-Z, CTRL-C, CTRL-V, ...) do work, however. 
**What steps will reproduce the problem?**

1. Update from version 3.0.1 to 3.1.0 via conda update (including all additional updates requested by conda)
2. Start Spyder, open an arbitrary file
3. Click on "Edit" to see the pulldown menu

**What is the expected output? What do you see instead?**
The entries should be activated, instead they are greyed out and cannot be selected.

**Please provide any additional information below**


## Versions and main components

* Spyder Version: 3.1.0
* Python Version:  3.5.2
* Operating system: Win7, 64 bit
* PyQt 5.6.0

## Dependencies
jedi >=0.8.1     :  0.9.0 (OK)
matplotlib >=1.0 :  1.5.3 (OK)
nbconvert >=4.0  :  4.2.0 (OK)
numpy >=1.7      :  1.11.1 (OK)
pandas >=0.13.1  :  0.18.1 (OK)
pep8 >=0.6       :  1.7.0 (OK)
pyflakes >=0.6.0 :  1.3.0 (OK)
pygments >=2.0   :  2.1.3 (OK)
pylint >=0.25    :  1.5.4 (OK)
qtconsole >=4.2.0:  4.2.1 (OK)
rope >=0.9.4     :  0.9.4-1 (OK)
sphinx >=0.6.6   :  1.3.1 (OK)
sympy >=0.7.3    :  1.0 (OK)



Discussion:
You're totally right. I don't how that happened :-)

@rlaverde, could you take a look at this one and have a PR for today? It doesn't seem like a hard issue. the thing is we have a signal somewhere that activates/deactivates the entries in the Edit menu depending on whether there's text selected on the Editor or not.

I think we should remove that signal and make those entries activate all the time.
It's a good motivation to learn more keyboard shortcuts :-P

Resolving patch:
diff --git a/spyder/app/mainwindow.py b/spyder/app/mainwindow.py
--- a/spyder/app/mainwindow.py
+++ b/spyder/app/mainwindow.py
@@ -216,22 +216,6 @@ def get_focus_python_shell():
         return widget.shell
 
 
-def get_focus_widget_properties():
-    """Get properties of focus widget
-    Returns tuple (widget, properties) where properties is a tuple of
-    booleans: (is_console, not_readonly, readwrite_editor)"""
-    widget = QApplication.focusWidget()
-    from spyder.widgets.shell import ShellBaseWidget
-    from spyder.widgets.editor import TextEditBaseWidget
-    textedit_properties = None
-    if isinstance(widget, (ShellBaseWidget, TextEditBaseWidget)):
-        console = isinstance(widget, ShellBaseWidget)
-        not_readonly = not widget.isReadOnly()
-        readwrite_editor = not_readonly and not console
-        textedit_properties = (console, not_readonly, readwrite_editor)
-    return widget, textedit_properties
-
-
 #==============================================================================
 # Main Window
 #==============================================================================
@@ -1956,15 +1940,29 @@ def hide_shortcuts(self, menu):
                 if element._shown_shortcut is not None:
                     element.setShortcut(QKeySequence())
 
+    def get_focus_widget_properties(self):
+        """Get properties of focus widget
+        Returns tuple (widget, properties) where properties is a tuple of
+        booleans: (is_console, not_readonly, readwrite_editor)"""
+        widget = self.focusWidget()
+        from spyder.widgets.shell import ShellBaseWidget
+        from spyder.widgets.editor import TextEditBaseWidget
+
+        # if focused widget isn't valid try the last focused
+        if not isinstance(widget, (ShellBaseWidget, TextEditBaseWidget)):
+            widget = self.previous_focused_widget
+
+        textedit_properties = None
+        if isinstance(widget, (ShellBaseWidget, TextEditBaseWidget)):
+            console = isinstance(widget, ShellBaseWidget)
+            not_readonly = not widget.isReadOnly()
+            readwrite_editor = not_readonly and not console
+            textedit_properties = (console, not_readonly, readwrite_editor)
+        return widget, textedit_properties
+
     def update_edit_menu(self):
         """Update edit menu"""
-        if self.menuBar().hasFocus():
-            return
-        # Disabling all actions to begin with
-        for child in self.edit_menu.actions():
-            child.setEnabled(False)
-
-        widget, textedit_properties = get_focus_widget_properties()
+        widget, textedit_properties = self.get_focus_widget_properties()
         if textedit_properties is None: # widget is not an editor/console
             return
         #!!! Below this line, widget is expected to be a QPlainTextEdit instance
@@ -1974,6 +1972,10 @@ def update_edit_menu(self):
         if not console and not_readonly and not self.editor.is_file_opened():
             return
 
+        # Disabling all actions to begin with
+        for child in self.edit_menu.actions():
+            child.setEnabled(False)
+
         self.selectall_action.setEnabled(True)
 
         # Undo, redo
@@ -1999,7 +2001,7 @@ def update_search_menu(self):
         if self.menuBar().hasFocus():
             return
 
-        widget, textedit_properties = get_focus_widget_properties()
+        widget, textedit_properties = self.get_focus_widget_properties()
         for action in self.editor.search_menu_actions:
             action.setEnabled(self.editor.isAncestorOf(widget))
         if textedit_properties is None: # widget is not an editor/console
@@ -2117,6 +2119,8 @@ def change_last_focused_widget(self, old, now):
         elif now is not None:
             self.last_focused_widget = now
 
+        self.previous_focused_widget =  old
+
     def closing(self, cancelable=False):
         """Exit tasks"""
         if self.already_closed or self.is_starting_up:
@@ -2366,6 +2370,11 @@ def global_callback(self):
         action = self.sender()
         callback = from_qvariant(action.data(), to_text_string)
         from spyder.widgets.editor import TextEditBaseWidget
+
+        # if focused widget isn't valid try the last focused^M
+        if not isinstance(widget, TextEditBaseWidget):
+            widget = self.previous_focused_widget
+
         if isinstance(widget, TextEditBaseWidget):
             getattr(widget, callback)()
 


Test patch:
diff --git a/spyder/plugins/tests/test_ipythonconsole.py b/spyder/plugins/tests/test_ipythonconsole.py
--- a/spyder/plugins/tests/test_ipythonconsole.py
+++ b/spyder/plugins/tests/test_ipythonconsole.py
@@ -4,6 +4,8 @@
 # Licensed under the terms of the MIT License
 #
 
+import os
+
 import pytest
 from qtpy.QtCore import Qt
 from pytestqt import qtbot
@@ -23,6 +25,7 @@ def ipyconsole_bot(qtbot):
 
 # Tests
 #-------------------------------
+@pytest.mark.skipif(os.name == 'nt', reason="It's timing out on Windows")
 def test_sys_argv_clear(ipyconsole_bot):
     qtbot, ipyconsole = ipyconsole_bot
     shell = ipyconsole.get_current_shellwidget()