def test_notify_presenter_clears_error(self):
     presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
     presenter.register_master(self.main_presenter)
     # This unit test will verify that notifying cut presenter will cause the error to be cleared on the view.
     # The actual subsequent procedure will fail, however this irrelevant to this. Hence the try, except blocks
     for command in [x for x in dir(Command) if x[0] != "_"]:
         try:
             presenter.notify(command)
         except ValueError:
             pass
         self.powder_view.clear_displayed_error.assert_called()
         self.powder_view.reset_mock()
示例#2
0
 def test_notify_presenter_clears_error(self):
     presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
     presenter.register_master(self.main_presenter)
     # This unit test will verify that notifying cut presenter will cause the error to be cleared on the view.
     # The actual subsequent procedure will fail, however this irrelevant to this. Hence the try, except blocks
     for command in [x for x in dir(Command) if x[0] != "_"]:
         try:
             presenter.notify(command)
         except ValueError:
             pass
         self.powder_view.clear_displayed_error.assert_called()
         self.powder_view.reset_mock()
示例#3
0
 def test_axis_switching_2(self):
     powder_presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
     dropbox_contents = self.powder_view.populate_powder_u2.call_args[0][0]
     # Makes u2 == u1 == DeltaE
     self.powder_view.set_powder_u1.reset_mock()
     self.powder_view.set_powder_u2.reset_mock()
     self.powder_view.get_powder_u1 = mock.Mock(return_value=dropbox_contents[2])
     self.powder_view.get_powder_u2 = mock.Mock(return_value=dropbox_contents[2])
     # Now set u2 to change, and check that u2 is not subsequently affected, but u1 is called.
     powder_presenter.notify(Command.U2Changed)
     self.powder_view.set_powder_u2.assert_not_called()
     # Since we set u1==u2==DeltaE, u1 must now be the first non-DeltaE unit
     self.powder_view.set_powder_u1.assert_called_once_with(dropbox_contents[0])
示例#4
0
 def test_axis_switching_1(self):
     powder_presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
     dropbox_contents = self.powder_view.populate_powder_u1.call_args[0][0]
     # Makes u2 == u1
     self.powder_view.set_powder_u1.reset_mock()
     self.powder_view.set_powder_u2.reset_mock()
     self.powder_view.get_powder_u1 = mock.Mock(return_value=dropbox_contents[1])
     self.powder_view.get_powder_u2 = mock.Mock(return_value=dropbox_contents[1])
     # Now set u1 to change, and check that u1 is not subsequently affected, but u2 is called.
     powder_presenter.notify(Command.U1Changed)
     self.powder_view.set_powder_u1.assert_not_called()
     # Since we set u1 to be a non-DeltaE axis, u2 must be DeltaE
     self.powder_view.set_powder_u2.assert_called_with(dropbox_contents[-1])
 def test_axis_switching_2(self):
     powder_presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
     dropbox_contents = self.powder_view.populate_powder_u2.call_args[0][0]
     # Makes u2 == u1 == DeltaE
     self.powder_view.set_powder_u1.reset_mock()
     self.powder_view.set_powder_u2.reset_mock()
     self.powder_view.get_powder_u1 = mock.Mock(return_value=dropbox_contents[2])
     self.powder_view.get_powder_u2 = mock.Mock(return_value=dropbox_contents[2])
     # Now set u2 to change, and check that u2 is not subsequently affected, but u1 is called.
     powder_presenter.notify(Command.U2Changed)
     self.powder_view.set_powder_u2.assert_not_called()
     # Since we set u1==u2==DeltaE, u1 must now be the first non-DeltaE unit
     self.powder_view.set_powder_u1.assert_called_once_with(dropbox_contents[0])
 def test_axis_switching_1(self):
     powder_presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
     dropbox_contents = self.powder_view.populate_powder_u1.call_args[0][0]
     # Makes u2 == u1
     self.powder_view.set_powder_u1.reset_mock()
     self.powder_view.set_powder_u2.reset_mock()
     self.powder_view.get_powder_u1 = mock.Mock(return_value=dropbox_contents[1])
     self.powder_view.get_powder_u2 = mock.Mock(return_value=dropbox_contents[1])
     # Now set u1 to change, and check that u1 is not subsequently affected, but u2 is called.
     powder_presenter.notify(Command.U1Changed)
     self.powder_view.set_powder_u1.assert_not_called()
     # Since we set u1 to be a non-DeltaE axis, u2 must be DeltaE
     self.powder_view.set_powder_u2.assert_called_with(dropbox_contents[-1])
示例#7
0
class PowderProjectionPresenterTest(unittest.TestCase):
    def setUp(self):
        # Set up a mock view, presenter, main view and main presenter
        self.powder_view = mock.create_autospec(PowderView)
        self.projection_calculator = mock.create_autospec(ProjectionCalculator)
        self.projection_calculator.configure_mock(**{'available_axes.return_value': ['|Q|', '2Theta', 'DeltaE']})
        self.projection_calculator.configure_mock(**{'available_units.return_value': ['meV', 'cm-1']})
        self.main_presenter = mock.create_autospec(MainPresenterInterface)
        self.mainview = mock.create_autospec(MainView)
        self.mainview.get_presenter = mock.Mock(return_value=self.main_presenter)

    def test_constructor_success(self):
        self.powder_presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)

    def test_constructor_failure_with_incorrect_powder_view(self):
        with self.assertRaises(TypeError):
            self.powder_presenter = PowderProjectionPresenter(self.projection_calculator, self.powder_view)

    def test_constructor_failure_with_incorrect_projection_calculator(self):
        with self.assertRaises(TypeError):
            self.powder_presenter = PowderProjectionPresenter(self.powder_view, MainView)

    def test_constructor_incorrect_powder_view_fail(self):
        self.assertRaises(TypeError, PowderProjectionPresenter, self.mainview, self.mainview, self.projection_calculator)

    def test_constructor_incorrect_main_view_fail(self):
        self.assertRaises(TypeError, PowderProjectionPresenter, self.powder_view, self.powder_view, self.projection_calculator)

    def test_constructor_incorrect_projection_calculator_fail(self):
        self.assertRaises(TypeError, PowderProjectionPresenter, self.powder_view, self.mainview, None)

    def test_register_master(self):
        powder_presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
        powder_presenter.register_master(self.main_presenter)

    def test_register_master_invalid_master_fail(self):
        powder_presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
        self.assertRaises(AssertionError, powder_presenter.register_master, 3)

    def test_calculate_projection_success(self):
        selected_workspace = 'a'
        # Setting up main presenter to report that the current selected workspace is selected_workspace
        self.main_presenter.get_selected_workspaces = mock.Mock(return_value=[selected_workspace])
        self.powder_presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
        self.powder_presenter.register_master(self.main_presenter)
        # Setup view to report DeltaE and |Q| as selected axis to project two
        u1 = 'DeltaE'
        u2 = '|Q|'
        self.powder_view.get_powder_u1 = mock.Mock(return_value=u1)
        self.powder_view.get_powder_u2 = mock.Mock(return_value=u2)
        self.powder_presenter.notify(Command.CalculatePowderProjection)
        self.main_presenter.get_selected_workspaces.assert_called_once_with()
        self.powder_view.get_powder_u1.assert_called_once_with()
        self.powder_view.get_powder_u2.assert_called_once_with()
        # TODO edit after recieving binning specs (test binning recieved from user if appropriate)
        #TODO make test more strict after recieving binning specs
        #self.projection_calculator.calculate_projection.assert_called_once_with(input_workspace=selected_workspace,
        #                           output_workspace=output_workspace,qbinning=???,axis1=u1,axis2=u2)
        self.projection_calculator.calculate_projection.assert_called_once()
        self.main_presenter.update_displayed_workspaces.assert_called_once()
        self.main_presenter.set_selected_workspaces.assert_called_once()

    def test_notify_presenter_with_unrecognised_command_raise_exception(self):
        self.powder_presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
        unrecognised_command = 1234567
        self.assertRaises(ValueError, self.powder_presenter.notify, unrecognised_command)

    def test_calculate_projection_equal_axis_error(self):
        selected_workspace = 'a'
        # Setting up main presenter to report that the current selected workspace is selected_workspace
        self.main_presenter.get_selected_workspaces = mock.Mock(return_value=[selected_workspace])
        self.powder_presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
        # Setup view to report DeltaE and |Q| as selected axis to project two
        u1 = 'DeltaE'
        u2 = 'DeltaE'
        self.powder_view.get_powder_u1 = mock.Mock(return_value=u1)
        self.powder_view.get_powder_u2 = mock.Mock(return_value=u2)
        self.powder_presenter.register_master(self.main_presenter)
        self.assertRaises(ValueError, self.powder_presenter.notify, Command.CalculatePowderProjection)
        self.main_presenter.get_selected_workspaces.assert_called_once_with()
        self.powder_view.get_powder_u1.assert_called_once_with()
        self.powder_view.get_powder_u2.assert_called_once_with()

        self.projection_calculator.calculate_projection.assert_not_called()

    def test_calculate_projection_multiple_selection(self):
        selected_workspaces = []
        # Setting up main presenter to report that the current selected workspace is selected_workspace
        self.main_presenter.get_selected_workspaces = mock.Mock(return_value=selected_workspaces)
        self.powder_presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
        self.powder_presenter.register_master(self.main_presenter)
        # Setup view to report DeltaE and |Q| as selected axis to project two
        u1 = 'DeltaE'
        u2 = '|Q|'
        self.powder_view.get_powder_u1 = mock.Mock(return_value=u1)
        self.powder_view.get_powder_u2 = mock.Mock(return_value=u2)
        self.powder_view.display_message_box = mock.Mock()
        self.powder_presenter.notify(Command.CalculatePowderProjection)
        self.powder_view.display_message_box.assert_called_once_with("No workspace is selected")
        self.main_presenter.get_selected_workspaces.assert_called_once_with()
        self.powder_view.get_powder_u1.assert_called_once_with()
        self.powder_view.get_powder_u2.assert_called_once_with()

        self.projection_calculator.calculate_projection.assert_not_called()

    def test_notify_presenter_clears_error(self):
        presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
        presenter.register_master(self.main_presenter)
        # This unit test will verify that notifying cut presenter will cause the error to be cleared on the view.
        # The actual subsequent procedure will fail, however this irrelevant to this. Hence the try, except blocks
        for command in [x for x in dir(Command) if x[0] != "_"]:
            try:
                presenter.notify(command)
            except ValueError:
                pass
            self.powder_view.clear_displayed_error.assert_called()
            self.powder_view.reset_mock()

    def test_axis_switching_1(self):
        powder_presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
        dropbox_contents = self.powder_view.populate_powder_u1.call_args[0][0]
        # Makes u2 == u1
        self.powder_view.set_powder_u1.reset_mock()
        self.powder_view.set_powder_u2.reset_mock()
        self.powder_view.get_powder_u1 = mock.Mock(return_value=dropbox_contents[1])
        self.powder_view.get_powder_u2 = mock.Mock(return_value=dropbox_contents[1])
        # Now set u1 to change, and check that u1 is not subsequently affected, but u2 is called.
        powder_presenter.notify(Command.U1Changed)
        self.powder_view.set_powder_u1.assert_not_called()
        # Since we set u1 to be a non-DeltaE axis, u2 must be DeltaE
        self.powder_view.set_powder_u2.assert_called_with(dropbox_contents[-1])

    def test_axis_switching_2(self):
        powder_presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
        dropbox_contents = self.powder_view.populate_powder_u2.call_args[0][0]
        # Makes u2 == u1 == DeltaE
        self.powder_view.set_powder_u1.reset_mock()
        self.powder_view.set_powder_u2.reset_mock()
        self.powder_view.get_powder_u1 = mock.Mock(return_value=dropbox_contents[2])
        self.powder_view.get_powder_u2 = mock.Mock(return_value=dropbox_contents[2])
        # Now set u2 to change, and check that u2 is not subsequently affected, but u1 is called.
        powder_presenter.notify(Command.U2Changed)
        self.powder_view.set_powder_u2.assert_not_called()
        # Since we set u1==u2==DeltaE, u1 must now be the first non-DeltaE unit
        self.powder_view.set_powder_u1.assert_called_once_with(dropbox_contents[0])
class PowderProjectionPresenterTest(unittest.TestCase):
    def setUp(self):
        # Set up a mock view, presenter, main view and main presenter
        self.powder_view = mock.create_autospec(PowderView)
        self.projection_calculator = mock.create_autospec(ProjectionCalculator)
        self.projection_calculator.configure_mock(**{'available_axes.return_value': ['|Q|', '2Theta', 'DeltaE']})
        self.main_presenter = mock.create_autospec(MainPresenterInterface)
        self.mainview = mock.create_autospec(MainView)
        self.mainview.get_presenter = mock.Mock(return_value=self.main_presenter)

    def test_constructor_success(self):
        self.powder_presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)

    def test_constructor_failure_with_incorrect_powder_view(self):
        with self.assertRaises(TypeError):
            self.powder_presenter = PowderProjectionPresenter(self.projection_calculator, self.powder_view)

    def test_constructor_failure_with_incorrect_projection_calculator(self):
        with self.assertRaises(TypeError):
            self.powder_presenter = PowderProjectionPresenter(self.powder_view, MainView)

    def test_constructor_incorrect_powder_view_fail(self):
        self.assertRaises(TypeError, PowderProjectionPresenter, self.mainview, self.mainview, self.projection_calculator)

    def test_constructor_incorrect_main_view_fail(self):
        self.assertRaises(TypeError, PowderProjectionPresenter, self.powder_view, self.powder_view, self.projection_calculator)

    def test_constructor_incorrect_projection_calculator_fail(self):
        self.assertRaises(TypeError, PowderProjectionPresenter, self.powder_view, self.mainview, None)

    def test_register_master(self):
        powder_presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
        powder_presenter.register_master(self.main_presenter)

    def test_register_master_invalid_master_fail(self):
        powder_presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
        self.assertRaises(AssertionError, powder_presenter.register_master, 3)

    def test_calculate_projection_success(self):
        selected_workspace = 'a'
        # Setting up main presenter to report that the current selected workspace is selected_workspace
        self.main_presenter.get_selected_workspaces = mock.Mock(return_value=[selected_workspace])
        self.powder_presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
        self.powder_presenter.register_master(self.main_presenter)
        # Setup view to report DeltaE and |Q| as selected axis to project two
        u1 = 'DeltaE'
        u2 = '|Q|'
        self.powder_view.get_powder_u1 = mock.Mock(return_value=u1)
        self.powder_view.get_powder_u2 = mock.Mock(return_value=u2)
        self.powder_presenter.notify(Command.CalculatePowderProjection)
        self.main_presenter.get_selected_workspaces.assert_called_once_with()
        self.powder_view.get_powder_u1.assert_called_once_with()
        self.powder_view.get_powder_u2.assert_called_once_with()
        # TODO edit after recieving binning specs (test binning recieved from user if appropriate)
        #TODO make test more strict after recieving binning specs
        #self.projection_calculator.calculate_projection.assert_called_once_with(input_workspace=selected_workspace,
        #                           output_workspace=output_workspace,qbinning=???,axis1=u1,axis2=u2)
        self.projection_calculator.calculate_projection.assert_called_once()
        self.main_presenter.update_displayed_workspaces.assert_called_once()
        self.main_presenter.set_selected_workspaces.assert_called_once()

    def test_notify_presenter_with_unrecognised_command_raise_exception(self):
        self.powder_presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
        unrecognised_command = 1234567
        self.assertRaises(ValueError, self.powder_presenter.notify, unrecognised_command)

    def test_calculate_projection_equal_axis_error(self):
        selected_workspace = 'a'
        # Setting up main presenter to report that the current selected workspace is selected_workspace
        self.main_presenter.get_selected_workspaces = mock.Mock(return_value=[selected_workspace])
        self.powder_presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
        # Setup view to report DeltaE and |Q| as selected axis to project two
        u1 = 'DeltaE'
        u2 = 'DeltaE'
        self.powder_view.get_powder_u1 = mock.Mock(return_value=u1)
        self.powder_view.get_powder_u2 = mock.Mock(return_value=u2)
        self.powder_presenter.register_master(self.main_presenter)
        self.assertRaises(ValueError, self.powder_presenter.notify, Command.CalculatePowderProjection)
        self.main_presenter.get_selected_workspaces.assert_called_once_with()
        self.powder_view.get_powder_u1.assert_called_once_with()
        self.powder_view.get_powder_u2.assert_called_once_with()

        self.projection_calculator.calculate_projection.assert_not_called()

    def test_calculate_projection_multiple_selection(self):
        selected_workspaces = []
        # Setting up main presenter to report that the current selected workspace is selected_workspace
        self.main_presenter.get_selected_workspaces = mock.Mock(return_value=selected_workspaces)
        self.powder_presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
        self.powder_presenter.register_master(self.main_presenter)
        # Setup view to report DeltaE and |Q| as selected axis to project two
        u1 = 'DeltaE'
        u2 = '|Q|'
        self.powder_view.get_powder_u1 = mock.Mock(return_value=u1)
        self.powder_view.get_powder_u2 = mock.Mock(return_value=u2)
        self.powder_view.display_message_box = mock.Mock()
        self.powder_presenter.notify(Command.CalculatePowderProjection)
        self.powder_view.display_message_box.assert_called_once_with("No workspace is selected")
        self.main_presenter.get_selected_workspaces.assert_called_once_with()
        self.powder_view.get_powder_u1.assert_called_once_with()
        self.powder_view.get_powder_u2.assert_called_once_with()

        self.projection_calculator.calculate_projection.assert_not_called()

    def test_notify_presenter_clears_error(self):
        presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
        presenter.register_master(self.main_presenter)
        # This unit test will verify that notifying cut presenter will cause the error to be cleared on the view.
        # The actual subsequent procedure will fail, however this irrelevant to this. Hence the try, except blocks
        for command in [x for x in dir(Command) if x[0] != "_"]:
            try:
                presenter.notify(command)
            except ValueError:
                pass
            self.powder_view.clear_displayed_error.assert_called()
            self.powder_view.reset_mock()

    def test_axis_switching_1(self):
        powder_presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
        dropbox_contents = self.powder_view.populate_powder_u1.call_args[0][0]
        # Makes u2 == u1
        self.powder_view.set_powder_u1.reset_mock()
        self.powder_view.set_powder_u2.reset_mock()
        self.powder_view.get_powder_u1 = mock.Mock(return_value=dropbox_contents[1])
        self.powder_view.get_powder_u2 = mock.Mock(return_value=dropbox_contents[1])
        # Now set u1 to change, and check that u1 is not subsequently affected, but u2 is called.
        powder_presenter.notify(Command.U1Changed)
        self.powder_view.set_powder_u1.assert_not_called()
        # Since we set u1 to be a non-DeltaE axis, u2 must be DeltaE
        self.powder_view.set_powder_u2.assert_called_with(dropbox_contents[-1])

    def test_axis_switching_2(self):
        powder_presenter = PowderProjectionPresenter(self.powder_view, self.projection_calculator)
        dropbox_contents = self.powder_view.populate_powder_u2.call_args[0][0]
        # Makes u2 == u1 == DeltaE
        self.powder_view.set_powder_u1.reset_mock()
        self.powder_view.set_powder_u2.reset_mock()
        self.powder_view.get_powder_u1 = mock.Mock(return_value=dropbox_contents[2])
        self.powder_view.get_powder_u2 = mock.Mock(return_value=dropbox_contents[2])
        # Now set u2 to change, and check that u2 is not subsequently affected, but u1 is called.
        powder_presenter.notify(Command.U2Changed)
        self.powder_view.set_powder_u2.assert_not_called()
        # Since we set u1==u2==DeltaE, u1 must now be the first non-DeltaE unit
        self.powder_view.set_powder_u1.assert_called_once_with(dropbox_contents[0])
示例#9
0
class PowderWidget(PowderView, QWidget):
    """This widget is not usable without a main window which implements mainview"""

    error_occurred = Signal('QString')
    busy = Signal(bool)

    def __init__(self, parent=None, *args, **kwargs):
        QWidget.__init__(self, parent, *args, **kwargs)
        load_ui(__file__, 'powder.ui', self)
        self.btnPowderCalculateProjection.clicked.connect(self._btn_clicked)
        self._presenter = PowderProjectionPresenter(self, MantidProjectionCalculator())
        self.cmbPowderU1.currentIndexChanged.connect(self._u1_changed)
        self.cmbPowderU2.currentIndexChanged.connect(self._u2_changed)

    def get_presenter(self):
        return self._presenter

    def _u1_changed(self):
        self._presenter.notify(Command.U1Changed)

    def _u2_changed(self):
        self._presenter.notify(Command.U2Changed)

    def _btn_clicked(self):
        self._presenter.notify(Command.CalculatePowderProjection)

    def get_powder_u1(self):
        return str(self.cmbPowderU1.currentText())

    def get_powder_u2(self):
        return str(self.cmbPowderU2.currentText())

    def set_powder_u1(self, name):
        # Signals are blocked to prevent self._u1_changed being called here (it would be false alarm)
        self.cmbPowderU1.blockSignals(True)
        self.cmbPowderU1.setCurrentIndex(self._name_to_index[name])
        self.cmbPowderU1.blockSignals(False)

    def set_powder_u2(self, name):
        # Signals are blocked to prevent self._u2_changed being called here (it would be false alarm)
        self.cmbPowderU2.blockSignals(True)
        self.cmbPowderU2.setCurrentIndex(self._name_to_index[name])
        self.cmbPowderU2.blockSignals(False)

    def populate_powder_u1(self, u1_options):
        # Signals are blocked to prevent self._u1_changed being called here (it would be false alarm)
        self.cmbPowderU1.blockSignals(True)
        self.cmbPowderU1.clear()
        self._name_to_index = {}
        for idx, value in enumerate(u1_options):
            self.cmbPowderU1.addItem(value)
            self._name_to_index[value] = idx
        self.cmbPowderU1.blockSignals(False)

    def populate_powder_u2(self, u2_options):
        # Signals are blocked to prevent self._u2_changed being called here (it would be false alarm)
        self.cmbPowderU2.blockSignals(True)
        self.cmbPowderU2.clear()
        for value in u2_options:
            self.cmbPowderU2.addItem(value)
        self.cmbPowderU2.blockSignals(False)

    def disable_calculate_projections(self, disable):
        self.groupBox.setDisabled(disable)

    def display_projection_error(self, message):
        self.error_msg.setText(message)

    def clear_displayed_error(self):
        self._display_error("")

    def _display_error(self, error_string):
        self.error_occurred.emit(error_string)

    def display_message_box(self, message):
        msg_box = QMessageBox()
        msg_box.setWindowTitle('Powder Projection Error')
        msg_box.setText(message)
        msg_box.exec_()
示例#10
0
class PowderWidget(PowderView, QWidget):
    """This widget is not usable without a main window which implements mainview"""

    error_occurred = Signal('QString')
    busy = Signal(bool)

    def __init__(self, parent=None, *args, **kwargs):
        QWidget.__init__(self, parent, *args, **kwargs)
        load_ui(__file__, 'powder.ui', self)
        self.btnPowderCalculateProjection.clicked.connect(self._btn_clicked)
        self._presenter = PowderProjectionPresenter(
            self, MantidProjectionCalculator())
        self.cmbPowderU1.currentIndexChanged.connect(self._u1_changed)
        self.cmbPowderU2.currentIndexChanged.connect(self._u2_changed)

    def get_presenter(self):
        return self._presenter

    def _u1_changed(self):
        self._presenter.notify(Command.U1Changed)

    def _u2_changed(self):
        self._presenter.notify(Command.U2Changed)

    def _btn_clicked(self):
        self._presenter.notify(Command.CalculatePowderProjection)

    def get_powder_u1(self):
        return str(self.cmbPowderU1.currentText())

    def get_powder_u2(self):
        return str(self.cmbPowderU2.currentText())

    def set_powder_u1(self, name):
        # Signals are blocked to prevent self._u1_changed being called here (it would be false alarm)
        self.cmbPowderU1.blockSignals(True)
        self.cmbPowderU1.setCurrentIndex(self._name_to_index[name])
        self.cmbPowderU1.blockSignals(False)

    def set_powder_u2(self, name):
        # Signals are blocked to prevent self._u2_changed being called here (it would be false alarm)
        self.cmbPowderU2.blockSignals(True)
        self.cmbPowderU2.setCurrentIndex(self._name_to_index[name])
        self.cmbPowderU2.blockSignals(False)

    def populate_powder_u1(self, u1_options):
        # Signals are blocked to prevent self._u1_changed being called here (it would be false alarm)
        self.cmbPowderU1.blockSignals(True)
        self.cmbPowderU1.clear()
        # Assuming that u1 and u2 both have the same possible units.
        self._name_to_index = {}
        for idx, value in enumerate(u1_options):
            self.cmbPowderU1.addItem(value)
            self._name_to_index[value] = idx
        self.cmbPowderU1.blockSignals(False)

    def populate_powder_u2(self, u2_options):
        # Signals are blocked to prevent self._u2_changed being called here (it would be false alarm)
        self.cmbPowderU2.blockSignals(True)
        self.cmbPowderU2.clear()
        for value in u2_options:
            self.cmbPowderU2.addItem(value)
        self.cmbPowderU2.blockSignals(False)

    def populate_powder_projection_units(self, powder_projection_units):
        self.cmbPowderUnits.clear()
        for unit in powder_projection_units:
            self.cmbPowderUnits.addItem(unit)

    def get_powder_units(self):
        return str(self.cmbPowderUnits.currentText())

    def disable_calculate_projections(self, disable):
        self.groupBox.setDisabled(disable)

    def display_projection_error(self, message):
        self.error_msg.setText(message)

    def clear_displayed_error(self):
        self._display_error("")

    def _display_error(self, error_string):
        self.error_occurred.emit(error_string)

    def display_message_box(self, message):
        msg_box = QMessageBox()
        msg_box.setWindowTitle('Powder Projection Error')
        msg_box.setText(message)
        msg_box.exec_()