Skip to content
Snippets Groups Projects
Commit 3f381d58 authored by Martyn Gigg's avatar Martyn Gigg
Browse files

Checkpoint work on editor

Refs #0
parent a4554424
No related branches found
No related tags found
No related merge requests found
......@@ -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"""
......
......@@ -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)
......
......@@ -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)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment