diff --git a/qt/python/mantidqt/widgets/codeeditor/editor.py b/qt/python/mantidqt/widgets/codeeditor/editor.py index 0aed423995f7bcb0ac2c2940c8e4b8c1adaf8ef6..badf4f3f7f3aae0db8eeb5899280b9af4318cbff 100644 --- a/qt/python/mantidqt/widgets/codeeditor/editor.py +++ b/qt/python/mantidqt/widgets/codeeditor/editor.py @@ -17,6 +17,7 @@ from __future__ import (absolute_import, unicode_literals) # 3rd party imports +from qtpy.QtCore import QObject, Signal from qtpy.QtWidgets import QStatusBar, QTabWidget, QVBoxLayout, QWidget # local imports @@ -48,11 +49,11 @@ class ExecutableCodeEditor(QWidget): super(ExecutableCodeEditor, self).__init__(parent) # layout - self.editor = CodeEditor(language, self) - self.status = QStatusBar(self) + self._editor = CodeEditor(language, self) + self._status = QStatusBar(self) layout = QVBoxLayout() - layout.addWidget(self.editor) - layout.addWidget(self.status) + layout.addWidget(self._editor) + layout.addWidget(self._status) self.setLayout(layout) layout.setContentsMargins(0, 0, 0, 0) @@ -61,22 +62,34 @@ class ExecutableCodeEditor(QWidget): def execute_all_async(self): self.presenter.req_execute_all_async() + def set_editor_readonly(self, ro): + self._editor.setReadOnly(ro) -class ExecutableCodeEditorPresenter(object): + def set_status_message(self, msg): + self._status.showMessage(msg) + + +class ExecutableCodeEditorPresenter(QObject): """Presenter part of MVP to control actions on the editor""" - def __init__(self, view, model=None): + def __init__(self, view): + super(ExecutableCodeEditorPresenter, self).__init__() self.view = view - self.model = model if model is not None else PythonCodeExecution() - self.view.status.showMessage(IDLE_STATUS_MSG) + self.model = PythonCodeExecution(success_cb=self._on_exec_success) + + self.view.set_status_message(IDLE_STATUS_MSG) def req_execute_all_async(self): text = self.view.text() if not text: return - self.view.status.showMessage(RUNNING_STATUS_MSG) + self.view.set_editor_read_only() + self.view.set_status_message(RUNNING_STATUS_MSG) self.model.execute_async(text) + def _on_exec_success(self): + self.view.set_status_message(IDLE_STATUS_MSG) + class MultiFileCodeEditor(QWidget): """Provides a tabbed widget for editing multiple files""" diff --git a/qt/python/mantidqt/widgets/codeeditor/execution.py b/qt/python/mantidqt/widgets/codeeditor/execution.py index f5ac9f9d8e73c264472390488939aa28e8e16574..d7002b2ef50f9fc4547a1faa61960a23f8d1a068 100644 --- a/qt/python/mantidqt/widgets/codeeditor/execution.py +++ b/qt/python/mantidqt/widgets/codeeditor/execution.py @@ -42,9 +42,9 @@ class PythonCodeExecution(object): def success_cb_wrap(_): success_cb() else: def success_cb_wrap(_): pass - self.on_success = success_cb_wrap - self.on_error = error_cb - self.on_progress_update = progress_cb + self._on_success = success_cb_wrap + self._on_error = error_cb + self._on_progress_update = progress_cb self._globals_ns, self._locals_ns = None, None self.reset_context() @@ -75,7 +75,7 @@ class PythonCodeExecution(object): # as these are not useful in this context t = AsyncTask(self.execute, args=(code_str,), stack_chop=3, - success_cb=self.on_success, error_cb=self.on_error) + success_cb=self._on_success, error_cb=self._on_error) t.start() return t @@ -89,7 +89,7 @@ class PythonCodeExecution(object): :raises: Any error that the code generates """ # execute whole string if no reporting is required - if self.on_progress_update is None: + if self._on_progress_update is None: self._do_exec(code_str) else: self._execute_as_blocks(code_str) @@ -100,7 +100,7 @@ class PythonCodeExecution(object): # will raise a SyntaxError if any of the code is invalid compile(code_str, "<string>", mode='exec') - progress_cb = self.on_progress_update + progress_cb = self._on_progress_update for block in code_blocks(code_str): progress_cb(block.lineno) self._do_exec(block.code_obj) diff --git a/qt/python/mantidqt/widgets/codeeditor/test/test_executablecodeeditor.py b/qt/python/mantidqt/widgets/codeeditor/test/test_executablecodeeditor.py index ec30f4610ab4e400e06a7e124f06509c1be8a44a..464b8565c010305f4bb4196da12e5a7097553c57 100644 --- a/qt/python/mantidqt/widgets/codeeditor/test/test_executablecodeeditor.py +++ b/qt/python/mantidqt/widgets/codeeditor/test/test_executablecodeeditor.py @@ -37,35 +37,35 @@ class ExecutableCodeEditorPresenterTest(unittest.TestCase): def setUp(self): self.view = mock.create_autospec(ExecutableCodeEditor) - self.view.status = mock.create_autospec(QStatusBar) - self.view.status.showMessage = mock.MagicMock() - self.model = mock.create_autospec(PythonCodeExecution) + self.view.set_status_message = mock.MagicMock() + self.view.set_editor_readonly = mock.MagicMock() + + self.presenter = ExecutableCodeEditorPresenter(self.view) + self.view.set_status_message.reset_mock() def test_construction_sets_idle_status(self): - ExecutableCodeEditorPresenter(self.view, self.model) - self.view.status.showMessage.assert_called_once_with("Status: Idle") + ExecutableCodeEditorPresenter(self.view) + self.view.set_status_message.assert_called_once_with("Status: Idle") def test_execute_all_async_with_empty_code_does_nothing(self): self.view.text = mock.MagicMock(return_value="") - self.model.execute_async = mock.MagicMock() + self.presenter.model.execute_async = mock.MagicMock() - presenter = ExecutableCodeEditorPresenter(self.view, self.model) - self.view.status.showMessage.reset_mock() - presenter.req_execute_all_async() + self.presenter.req_execute_all_async() self.view.text.assert_called_once_with() - self.view.status.showMessage.assert_not_called() - self.model.execute_async.assert_not_called() + self.view.set_editor_readonly.assert_not_called() + self.view.set_status_message.assert_not_called() + self.presenter.model.execute_async.assert_not_called() def test_execute_all_async_with_successful_code(self): code_str = "x = 1 + 2" self.view.text = mock.MagicMock(return_value=code_str) self.model.execute_async = mock.MagicMock() - presenter = ExecutableCodeEditorPresenter(self.view, self.model) - self.view.status.showMessage.reset_mock() - presenter.req_execute_all_async() + self.presenter.req_execute_all_async() self.view.text.assert_called_once_with() - self.view.status.showMessage.assert_called_once_with("Status: Running") + self.view.set_editor_readonly.assert_called_once_with(True) + self.view.set_status_message.assert_called_once_with("Status: Running") self.model.execute_async.assert_called_once_with(code_str)