Skip to content

Commit

Permalink
Merge from 3.x: PR #7205
Browse files Browse the repository at this point in the history
Fixes #937
  • Loading branch information
ccordoba12 committed Nov 12, 2018
2 parents 51e77ca + f2e93de commit 4733c44
Show file tree
Hide file tree
Showing 13 changed files with 250 additions and 232 deletions.
61 changes: 32 additions & 29 deletions spyder/app/mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -1226,6 +1226,7 @@ def add_ipm_action(text, path):
if isinstance(child, QMenu):
try:
child.aboutToShow.connect(self.update_edit_menu)
child.aboutToShow.connect(self.update_search_menu)
except TypeError:
pass

Expand Down Expand Up @@ -1523,6 +1524,7 @@ def setup_layout(self, default=False):

def setup_default_layouts(self, index, settings):
"""Setup default layouts when run for the first time"""
self.maximize_dockwidget(restore=True)
self.set_window_settings(*settings)
self.setUpdatesEnabled(False)

Expand Down Expand Up @@ -2072,20 +2074,13 @@ 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 = QApplication.focusWidget()
from spyder.plugins.console.widgets.shell import ShellBaseWidget
from spyder.plugins.editor.widgets.editor import TextEditBaseWidget
from spyder.plugins.ipythonconsole.widgets import ControlWidget

# if focused widget isn't valid try the last focused
if not isinstance(widget, (ShellBaseWidget, TextEditBaseWidget,
ControlWidget)):
widget = self.previous_focused_widget
widget = QApplication.focusWidget()

textedit_properties = None
if isinstance(widget, (ShellBaseWidget, TextEditBaseWidget,
ControlWidget)):
console = isinstance(widget, (ShellBaseWidget, ControlWidget))
if isinstance(widget, (TextEditBaseWidget, ControlWidget)):
console = isinstance(widget, ControlWidget)
not_readonly = not widget.isReadOnly()
readwrite_editor = not_readonly and not console
textedit_properties = (console, not_readonly, readwrite_editor)
Expand All @@ -2096,7 +2091,8 @@ def update_edit_menu(self):
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
# !!! Below this line, widget is expected to be a QPlainTextEdit
# instance
console, not_readonly, readwrite_editor = textedit_properties

# Editor has focus and there is no file opened in it
Expand Down Expand Up @@ -2129,19 +2125,27 @@ def update_edit_menu(self):

def update_search_menu(self):
"""Update search menu"""
if self.menuBar().hasFocus():
return
# Disabling all actions except the last one
# (which is Find in files) to begin with
for child in self.search_menu.actions()[:-1]:
child.setEnabled(False)

widget, textedit_properties = self.get_focus_widget_properties()
for action in self.editor.search_menu_actions:
try:
action.setEnabled(self.editor.isAncestorOf(widget))
except RuntimeError:
pass
if textedit_properties is None: # widget is not an editor/console
return
#!!! Below this line, widget is expected to be a QPlainTextEdit instance
_x, _y, readwrite_editor = textedit_properties

# !!! Below this line, widget is expected to be a QPlainTextEdit
# instance
console, not_readonly, readwrite_editor = textedit_properties

# Find actions only trigger an effect in the Editor
if not console:
for action in self.search_menu.actions():
try:
action.setEnabled(True)
except RuntimeError:
pass

# Disable the replace action for read-only files
self.search_menu_actions[3].setEnabled(readwrite_editor)

Expand Down Expand Up @@ -2602,13 +2606,12 @@ def global_callback(self):
action = self.sender()
callback = from_qvariant(action.data(), to_text_string)
from spyder.plugins.editor.widgets.editor import TextEditBaseWidget
from spyder.plugins.ipythonconsole.widgets import ControlWidget

# If focused widget isn't valid try the last focused
if not isinstance(widget, TextEditBaseWidget):
widget = self.previous_focused_widget

if isinstance(widget, TextEditBaseWidget):
if isinstance(widget, (TextEditBaseWidget, ControlWidget)):
getattr(widget, callback)()
else:
return

def redirect_internalshell_stdio(self, state):
if state:
Expand Down Expand Up @@ -2641,11 +2644,10 @@ def execute_in_external_console(self, lines, focus_to_editor):
to the Editor.
"""
console = self.ipyconsole
console.visibility_changed(True)
console.raise_()
console.switch_to_plugin()
console.execute_code(lines)
if focus_to_editor:
self.editor.visibility_changed(True)
self.editor.switch_to_plugin()

def open_file(self, fname, external=False):
"""
Expand Down Expand Up @@ -2968,7 +2970,8 @@ def restart(self, reset=False):

# ---- Interactive Tours
def show_tour(self, index):
""" """
"""Show interactive tour."""
self.maximize_dockwidget(restore=True)
frames = self.tours_available[index]
self.tour.set_tour(index, frames, self)
self.tour.start_tour()
Expand Down
9 changes: 5 additions & 4 deletions spyder/plugins/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,11 @@ def create_configwidget(self, parent):
return configwidget

def switch_to_plugin(self):
"""Switch to plugin
This method is called when pressing plugin's shortcut key"""
if not self.ismaximized:
self.dockwidget.show()
"""Switch to plugin."""
if (self.main.last_plugin is not None and
self.main.last_plugin.ismaximized and
self.main.last_plugin is not self):
self.main.maximize_dockwidget()
if not self.toggle_view_action.isChecked():
self.toggle_view_action.setChecked(True)
self.visibility_changed(True)
Expand Down
5 changes: 1 addition & 4 deletions spyder/plugins/breakpoints/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,4 @@ def apply_plugin_settings(self, options):

def show(self):
"""Show the breakpoints dockwidget"""
if self.dockwidget and not self.ismaximized:
self.dockwidget.setVisible(True)
self.dockwidget.setFocus()
self.dockwidget.raise_()
self.switch_to_plugin()
41 changes: 26 additions & 15 deletions spyder/plugins/editor/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -461,8 +461,6 @@ def __init__(self, parent, ignore_last_opened_files=False):
self.pythonfile_dependent_actions = []
self.dock_toolbar_actions = None
self.edit_menu_actions = None #XXX: find another way to notify Spyder
# (see spyder.py: 'update_edit_menu' method)
self.search_menu_actions = None #XXX: same thing ('update_search_menu')
self.stack_menu_actions = None
self.checkable_actions = {}

Expand Down Expand Up @@ -1173,8 +1171,7 @@ def get_plugin_actions(self):
self.main.edit_toolbar_actions += edit_toolbar_actions

# ---- Search menu/toolbar construction ----
self.search_menu_actions = [gotoline_action]
self.main.search_menu_actions += self.search_menu_actions
self.main.search_menu_actions += [gotoline_action]
self.main.search_toolbar_actions += [gotoline_action]

# ---- Run menu/toolbar construction ----
Expand Down Expand Up @@ -1315,6 +1312,7 @@ def _create_checkable_action(self, text, conf_name, editorstack_method):
used to update the changes in each editorstack.
"""
def toogle(checked):
self.switch_to_plugin()
self._toggle_checkable_action(checked, editorstack_method,
conf_name)
action = create_action(self, text, toggled=toogle)
Expand Down Expand Up @@ -1724,13 +1722,13 @@ def update_warning_menu(self):
filename = self.get_current_filename()
for message, line_number in check_results:
error = 'syntax' in message
text = message[:1].upper()+message[1:]
text = message[:1].upper() + message[1:]
icon = ima.icon('error') if error else ima.icon('warning')
# QAction.triggered works differently for PySide and PyQt
if not API == 'pyside':
slot = lambda _checked, _l=line_number: self.load(filename, goto=_l)
else:
slot = lambda _l=line_number: self.load(filename, goto=_l)

def slot():
self.switch_to_plugin()
self.load(filename, goto=line_number)

action = create_action(self, text=text, icon=icon, triggered=slot)
self.warning_menu.addAction(action)

Expand All @@ -1742,11 +1740,11 @@ def update_todo_menu(self):
filename = self.get_current_filename()
for text, line0 in results:
icon = ima.icon('todo')
# QAction.triggered works differently for PySide and PyQt
if not API == 'pyside':
slot = lambda _checked, _l=line0: self.load(filename, goto=_l)
else:
slot = lambda _l=line0: self.load(filename, goto=_l)

def slot():
self.switch_to_plugin()
self.load(filename, goto=line0)

action = create_action(self, text=text, icon=icon, triggered=slot)
self.todo_menu.addAction(action)
self.update_todo_actions()
Expand Down Expand Up @@ -2346,20 +2344,23 @@ def unblockcomment(self):
editor.unblockcomment()
@Slot()
def go_to_next_todo(self):
self.switch_to_plugin()
editor = self.get_current_editor()
position = editor.go_to_next_todo()
filename = self.get_current_filename()
self.add_cursor_position_to_history(filename, position)

@Slot()
def go_to_next_warning(self):
self.switch_to_plugin()
editor = self.get_current_editor()
position = editor.go_to_next_warning()
filename = self.get_current_filename()
self.add_cursor_position_to_history(filename, position)

@Slot()
def go_to_previous_warning(self):
self.switch_to_plugin()
editor = self.get_current_editor()
position = editor.go_to_previous_warning()
filename = self.get_current_filename()
Expand Down Expand Up @@ -2387,15 +2388,18 @@ def toggle_eol_chars(self, os_name, checked):
if checked:
editor = self.get_current_editor()
if self.__set_eol_chars:
self.switch_to_plugin()
editor.set_eol_chars(sourcecode.get_eol_chars_from_os_name(os_name))

@Slot()
def remove_trailing_spaces(self):
self.switch_to_plugin()
editorstack = self.get_current_editorstack()
editorstack.remove_trailing_spaces()

@Slot()
def fix_indentation(self):
self.switch_to_plugin()
editorstack = self.get_current_editorstack()
editorstack.fix_indentation()

Expand Down Expand Up @@ -2485,10 +2489,12 @@ def __move_cursor_position(self, index_move):

@Slot()
def go_to_previous_cursor_position(self):
self.switch_to_plugin()
self.__move_cursor_position(-1)

@Slot()
def go_to_next_cursor_position(self):
self.switch_to_plugin()
self.__move_cursor_position(1)

@Slot()
Expand All @@ -2503,18 +2509,21 @@ def set_or_clear_breakpoint(self):
"""Set/Clear breakpoint"""
editorstack = self.get_current_editorstack()
if editorstack is not None:
self.switch_to_plugin()
editorstack.set_or_clear_breakpoint()

@Slot()
def set_or_edit_conditional_breakpoint(self):
"""Set/Edit conditional breakpoint"""
editorstack = self.get_current_editorstack()
if editorstack is not None:
self.switch_to_plugin()
editorstack.set_or_edit_conditional_breakpoint()

@Slot()
def clear_all_breakpoints(self):
"""Clear breakpoints in all files"""
self.switch_to_plugin()
clear_all_breakpoints()
self.breakpoints_saved.emit()
editorstack = self.get_current_editorstack()
Expand All @@ -2535,6 +2544,7 @@ def clear_breakpoint(self, filename, lineno):

def debug_command(self, command):
"""Debug actions"""
self.switch_to_plugin()
self.main.ipyconsole.write_to_stdin(command)
focus_widget = self.main.ipyconsole.get_focus_widget()
if focus_widget:
Expand Down Expand Up @@ -2630,6 +2640,7 @@ def set_dialog_size(self, size):
@Slot()
def debug_file(self):
"""Debug current script"""
self.switch_to_plugin()
self.run_file(debug=True)

@Slot()
Expand Down
13 changes: 4 additions & 9 deletions spyder/plugins/help/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,26 +443,22 @@ def show_intro_message(self):

def show_rich_text(self, text, collapse=False, img_path=''):
"""Show text in rich mode"""
self.visibility_changed(True)
self.raise_()
self.switch_to_plugin()
self.switch_to_rich_text()
context = generate_context(collapse=collapse, img_path=img_path,
css_path=self.css_path)
self.render_sphinx_doc(text, context)

def show_plain_text(self, text):
"""Show text in plain mode"""
self.visibility_changed(True)
self.raise_()
self.switch_to_plugin()
self.switch_to_plain_text()
self.set_plain_text(text, is_code=False)

@Slot()
def show_tutorial(self):
"""Show the Spyder tutorial in the Help plugin, opening it if needed"""
if not self.dockwidget.isVisible():
self.dockwidget.show()
self.toggle_view_action.setChecked(True)
self.switch_to_plugin()
tutorial_path = get_module_source_path('spyder.plugins.help.utils')
tutorial = osp.join(tutorial_path, 'tutorial.rst')
text = open(tutorial).read()
Expand Down Expand Up @@ -543,8 +539,7 @@ def __eventually_raise_help(self, text, force=False):
if (self.console.dockwidget not in dockwidgets and
self.main.ipyconsole is not None and
self.main.ipyconsole.dockwidget not in dockwidgets):
self.dockwidget.show()
self.dockwidget.raise_()
self.switch_to_plugin()
self._last_texts[index] = text

def load_history(self, obj=None):
Expand Down
9 changes: 0 additions & 9 deletions spyder/plugins/help/tests/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,21 +107,14 @@ def test_help_opens_when_show_tutorial_unit(help_plugin, qtbot):
MockDockwidget = MagicMock()
MockDockwidget.return_value.isVisible.return_value = False
mockDockwidget_instance = MockDockwidget()

MockAction = Mock()
mock_toggle_view_action = MockAction()
mock_show_rich_text = Mock()

help_plugin.dockwidget = mockDockwidget_instance
help_plugin.toggle_view_action = mock_toggle_view_action
help_plugin.show_rich_text = mock_show_rich_text

help_plugin.show_tutorial()
qtbot.wait(100)

assert mockDockwidget_instance.show.call_count == 1
assert mock_toggle_view_action.setChecked.call_count == 1
mock_toggle_view_action.setChecked.assert_called_once_with(True)
assert mock_show_rich_text.call_count == 1

MockDockwidget.return_value.isVisible.return_value = True
Expand All @@ -130,8 +123,6 @@ def test_help_opens_when_show_tutorial_unit(help_plugin, qtbot):

help_plugin.show_tutorial()
qtbot.wait(100)
assert mockDockwidget_instance.show.call_count == 1
assert mock_toggle_view_action.setChecked.call_count == 1
assert mock_show_rich_text.call_count == 2


Expand Down
Loading

0 comments on commit 4733c44

Please sign in to comment.