diff --git a/qt/python/CMakeLists.txt b/qt/python/CMakeLists.txt
index f285432aea4f493ec4231c1cfc489b272914b11c..08e5cbf0865bb638d2154ff7447b5cc4852c6dca 100644
--- a/qt/python/CMakeLists.txt
+++ b/qt/python/CMakeLists.txt
@@ -43,6 +43,7 @@ if ( ENABLE_WORKBENCH )
     mantidqt/utils/test/test_qt_utils.py
 
     mantidqt/widgets/codeeditor/test_codeeditor.py
+    mantidqt/widgets/codeeditor/test_executablecodeeditor.py
     mantidqt/widgets/codeeditor/test_execution.py
     mantidqt/widgets/codeeditor/test_multifileeditor.py
 
diff --git a/qt/python/mantidqt/widgets/codeeditor/editor.py b/qt/python/mantidqt/widgets/codeeditor/editor.py
index 2ce2ae4fbd425c2979d57e8a95b69f0c11d0e34a..0aed423995f7bcb0ac2c2940c8e4b8c1adaf8ef6 100644
--- a/qt/python/mantidqt/widgets/codeeditor/editor.py
+++ b/qt/python/mantidqt/widgets/codeeditor/editor.py
@@ -14,21 +14,70 @@
 #
 #  You should have received a copy of the GNU General Public License
 #  along with this program.  If not, see <http://www.gnu.org/licenses/>.
-from __future__ import (absolute_import)
+from __future__ import (absolute_import, unicode_literals)
 
 # 3rd party imports
-from qtpy.QtWidgets import QTabWidget, QVBoxLayout, QWidget
+from qtpy.QtWidgets import QStatusBar, QTabWidget, QVBoxLayout, QWidget
 
 # local imports
 from mantidqt.utils.qt import import_qtlib
 from .execution import PythonCodeExecution
 
-EDITOR_LANGUAGE = "Python"
+DEFAULT_EDITOR_LANGUAGE = "Python"
+
+EXECUTION_CLS = PythonCodeExecution
+
+IDLE_STATUS_MSG = "Status: Idle"
+
+RUNNING_STATUS_MSG = "Status: Running"
 
 # Import single-file editor from C++ wrapping
 CodeEditor = import_qtlib('_widgetscore', 'mantidqt.widgets', 'ScriptEditor')
 
 
+class ExecutableCodeEditor(QWidget):
+
+    def __init__(self, language=DEFAULT_EDITOR_LANGUAGE, parent=None):
+        """
+
+        :param language: Language for syntax highlighting
+        :param user_globals: Dictionary for global context of execution.
+        :param user_locals: Dictionary for local context of execution
+        :param parent: A parent QWidget
+        """
+        super(ExecutableCodeEditor, self).__init__(parent)
+
+        # layout
+        self.editor = CodeEditor(language, self)
+        self.status = QStatusBar(self)
+        layout = QVBoxLayout()
+        layout.addWidget(self.editor)
+        layout.addWidget(self.status)
+        self.setLayout(layout)
+        layout.setContentsMargins(0, 0, 0, 0)
+
+        self.presenter = ExecutableCodeEditorPresenter(self)
+
+    def execute_all_async(self):
+        self.presenter.req_execute_all_async()
+
+
+class ExecutableCodeEditorPresenter(object):
+    """Presenter part of MVP to control actions on the editor"""
+
+    def __init__(self, view, model=None):
+        self.view = view
+        self.model = model if model is not None else PythonCodeExecution()
+        self.view.status.showMessage(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.model.execute_async(text)
+
+
 class MultiFileCodeEditor(QWidget):
     """Provides a tabbed widget for editing multiple files"""
 
@@ -41,9 +90,10 @@ class MultiFileCodeEditor(QWidget):
         layout = QVBoxLayout()
         layout.addWidget(self.editors)
         self.setLayout(layout)
+        layout.setContentsMargins(0, 0, 0, 0)
 
         # add a single editor by default
-        self.append_new_editor(EDITOR_LANGUAGE)
+        self.append_new_editor(DEFAULT_EDITOR_LANGUAGE)
 
     @property
     def editor_count(self):
@@ -51,4 +101,4 @@ class MultiFileCodeEditor(QWidget):
 
     def append_new_editor(self, language):
         title = "New"
-        self.editors.addTab(CodeEditor(language, self.editors), title)
+        self.editors.addTab(ExecutableCodeEditor(language, self.editors), title)
diff --git a/qt/python/mantidqt/widgets/codeeditor/test/test_codeeditor.py b/qt/python/mantidqt/widgets/codeeditor/test/test_codeeditor.py
index 24e91063f2b1699ab2c79394608f6f91447736dc..ff465ee2e81bc3e85f031a3bdd98d9e234e68434 100644
--- a/qt/python/mantidqt/widgets/codeeditor/test/test_codeeditor.py
+++ b/qt/python/mantidqt/widgets/codeeditor/test/test_codeeditor.py
@@ -19,8 +19,6 @@ from __future__ import (absolute_import, unicode_literals)
 # system imports
 import unittest
 
-# third-party library imports
-
 # local imports
 from mantidqt.widgets.codeeditor.editor import CodeEditor
 from mantidqt.utils.qt.testing import requires_qapp
@@ -31,8 +29,9 @@ TEST_LANG = "Python"
 @requires_qapp
 class CodeEditorTest(unittest.TestCase):
 
+    # ---------------------------------------------------------------
     # Success tests
-
+    # ---------------------------------------------------------------
     def test_construction_accepts_Python_as_language(self):
         CodeEditor(TEST_LANG)
 
@@ -61,8 +60,9 @@ class CodeEditorTest(unittest.TestCase):
         widget.setReadOnly(True)
         self.assertTrue(widget.isReadOnly())
 
+    # ---------------------------------------------------------------
     # Failure tests
-
+    # ---------------------------------------------------------------
     def test_construction_raises_error_for_unknown_language(self):
         # self.assertRaises causes a segfault here for some reason...
         try:
diff --git a/qt/python/mantidqt/widgets/codeeditor/test/test_executablecodeeditor.py b/qt/python/mantidqt/widgets/codeeditor/test/test_executablecodeeditor.py
new file mode 100644
index 0000000000000000000000000000000000000000..ec30f4610ab4e400e06a7e124f06509c1be8a44a
--- /dev/null
+++ b/qt/python/mantidqt/widgets/codeeditor/test/test_executablecodeeditor.py
@@ -0,0 +1,73 @@
+#    This file is part of the mantid workbench.
+#
+#    Copyright (C) 2017 mantidproject
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+from __future__ import (absolute_import, unicode_literals)
+
+# std imports
+import unittest
+
+# 3rd party imports
+from qtpy.QtWidgets import QStatusBar
+import six
+
+# local imports
+from mantidqt.widgets.codeeditor.editor import ExecutableCodeEditor, ExecutableCodeEditorPresenter
+from mantidqt.widgets.codeeditor.execution import PythonCodeExecution
+
+if six.PY2:
+    import mock
+else:
+    from unittest import mock
+
+
+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)
+
+    def test_construction_sets_idle_status(self):
+        ExecutableCodeEditorPresenter(self.view, self.model)
+        self.view.status.showMessage.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()
+
+        presenter = ExecutableCodeEditorPresenter(self.view, self.model)
+        self.view.status.showMessage.reset_mock()
+        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()
+
+    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.view.text.assert_called_once_with()
+        self.view.status.showMessage.assert_called_once_with("Status: Running")
+        self.model.execute_async.assert_called_once_with(code_str)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/qt/python/mantidqt/widgets/codeeditor/test/test_multifileeditor.py b/qt/python/mantidqt/widgets/codeeditor/test/test_multifileeditor.py
index d14387c10feb80e173b6683be31d6141ba2cb393..b0834dbb536b92bd08cc340585aaa545522c8f79 100644
--- a/qt/python/mantidqt/widgets/codeeditor/test/test_multifileeditor.py
+++ b/qt/python/mantidqt/widgets/codeeditor/test/test_multifileeditor.py
@@ -35,11 +35,6 @@ class MultiFileCodeEditorTest(unittest.TestCase):
         widget = MultiFileCodeEditor()
         self.assertEqual(1, widget.editor_count)
 
-    def test_execute_current_file_executes_correct_tab(self):
-        # set up code in current tab
-        widget = MultiFileCodeEditor()
-        editor = self.current_editor()
-
 
 if __name__ == '__main__':
     unittest.main()