示例#1
0
class QuickLabelOptions(QuickOptions):

    ok_clicked = Signal()
    cancel_clicked = Signal()

    def __init__(self, label):
        super(QuickLabelOptions, self).__init__()
        self.setWindowTitle("Edit " + label.get_text())
        self.line_edit = QtWidgets.QLineEdit()
        self.line_edit.setText(label.get_text())
        self.layout.addWidget(self.line_edit)
        self.layout.addLayout(self.button_row)
        self.line_edit.show()

    @property
    def label(self):
        return self.line_edit.text()
示例#2
0
class QuickLineOptions(QuickOptions):

    ok_clicked = Signal()
    cancel_clicked = Signal()

    def __init__(self, line_options):
        super(QuickLineOptions, self).__init__()
        self.setWindowTitle("Edit line")
        self.line_widget = LegendAndLineOptionsSetter(line_options, None)
        self.layout.addWidget(self.line_widget)
        self.layout.addLayout(self.button_row)

        self.line_widget.show()

    @property
    def error_bar(self):
        return self.line_widget.error_bar

    @property
    def color(self):
        return self.line_widget.color

    @property
    def style(self):
        return self.line_widget.style

    @property
    def marker(self):
        return self.line_widget.marker

    @property
    def width(self):
        return self.line_widget.width

    @property
    def label(self):
        return self.line_widget.label

    @property
    def shown(self):
        return self.line_widget.shown

    @property
    def legend(self):
        return self.line_widget.legend
示例#3
0
class SlicePlotOptions(PlotOptionsDialog):

    cRangeEdited = Signal()
    cLogEdited = Signal()

    def __init__(self):
        super(SlicePlotOptions, self).__init__()
        self.chkXLog.hide()
        self.chkYLog.hide()
        self.cut_options.hide()
        self.setMaximumWidth(350)

        self.lneCMin.editingFinished.connect(self.cRangeEdited)
        self.lneCMax.editingFinished.connect(self.cRangeEdited)
        self.chkLogarithmic.stateChanged.connect(self.cLogEdited)

    @property
    def colorbar_range(self):
        try:
            cmin = float(str(self.lneCMin.text()))
            cmax = float(str(self.lneCMax.text()))
        except ValueError:
            return None, None
        return cmin, cmax

    @colorbar_range.setter
    def colorbar_range(self, c_range):
        try:
            cmin, cmax = c_range
        except ValueError:
            raise ValueError("pass an iterable with two items")
        self.lneCMin.setText(str(cmin))
        self.lneCMax.setText(str(cmax))

    @property
    def colorbar_log(self):
        return self.chkLogarithmic.isChecked()

    @colorbar_log.setter
    def colorbar_log(self, value):
        self.chkLogarithmic.setChecked(value)
示例#4
0
class CutWidget(CutView, QWidget):
    error_occurred = Signal('QString')
    busy = Signal(bool)

    def __init__(self, parent=None, *args, **kwargs):
        QWidget.__init__(self, parent, *args, **kwargs)
        load_ui(__file__, 'cut.ui', self)
        self._command_lookup = {
            self.btnCutPlot: Command.Plot,
            self.btnCutPlotOver: Command.PlotOver,
            self.btnCutSaveToWorkspace: Command.SaveToWorkspace
        }
        for button in self._command_lookup.keys():
            button.clicked.connect(self._btn_clicked)
        self._presenter = CutWidgetPresenter(self)
        self.cmbCutAxis.currentIndexChanged.connect(self.axis_changed)
        self._minimumStep = None
        self.lneCutStep.editingFinished.connect(self._step_edited)
        self.enable_integration_axis(False)
        self.set_validators()

    def _btn_clicked(self):
        sender = self.sender()
        command = self._command_lookup[sender]
        if self._step_edited():
            self._presenter.notify(command)

    def _step_edited(self):
        """Checks that user inputted step size is not too small."""
        if self._minimumStep:
            try:
                value = float(self.lneCutStep.text())
            except ValueError:
                value = 0.0
                self.display_error('Invalid cut step parameter. Using default.')
            if value == 0.0:
                self.lneCutStep.setText('%.5f' % (self._minimumStep))
                self.display_error('Setting step size to default.')
            elif value < (self._minimumStep / 100.):
                self.display_error('Step size too small!')
                return False
        return True

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

    def axis_changed(self, _changed_index):
        self._presenter.notify(Command.AxisChanged)

    def enable_integration_axis(self, enabled):
        if enabled:
            self.integrationStack.setCurrentIndex(1)
            self.label_250.show()
        else:
            self.integrationStack.setCurrentIndex(0)
            self.label_250.hide()

    def integration_axis_shown(self):
        return self.integration_axis.current_index == 1

    def get_presenter(self):
        return self._presenter

    def get_cut_axis(self):
        return str(self.cmbCutAxis.currentText())

    def get_cut_axis_start(self):
        return str(self.lneCutStart.text())

    def get_cut_axis_step(self):
        return str(self.lneCutStep.text())

    def get_cut_axis_end(self):
        return str(self.lneCutEnd.text())

    def get_integration_axis(self):
        if self.integration_axis_shown:
            return str(self.cmbIntegrationAxis.currentText())
        else:
            return None

    def get_integration_start(self):
        return str(self.lneCutIntegrationStart.text())

    def get_integration_end(self):
        return str(self.lneCutIntegrationEnd.text())

    def get_integration_width(self):
        return str(self.lneCutIntegrationWidth.text())

    def get_intensity_start(self):
        return str(self.lneEditCutIntensityStart.text())

    def get_intensity_end(self):
        return str(self.lneCutIntensityEnd.text())

    def get_intensity_is_norm_to_one(self):
        return self.rdoCutNormToOne.isChecked()

    def get_smoothing(self):
        return str(self.lneCutSmoothing.text())

    def set_cut_axis(self, axis_name):
        index = [ind for ind in range(self.cmbCutAxis.count()) if str(self.cmbCutAxis.itemText(ind)) == axis_name]
        if index:
            self.cmbCutAxis.blockSignals(True)
            self.cmbCutAxis.setCurrentIndex(index[0])
            self.cmbCutAxis.blockSignals(False)

    def set_minimum_step(self, value):
        self._minimumStep = value

    def get_minimum_step(self):
        return self._minimumStep

    def populate_cut_axis_options(self, options):
        self.cmbCutAxis.blockSignals(True)
        self.cmbCutAxis.clear()
        for option in options:
            self.cmbCutAxis.addItem(option)
        self.cmbCutAxis.blockSignals(False)

    def populate_integration_axis_options(self, options):
        self.cmbIntegrationAxis.blockSignals(True)
        self.cmbIntegrationAxis.clear()
        for option in options:
            self.cmbIntegrationAxis.addItem(option)
        self.cmbIntegrationAxis.setEnabled(len(options) > 1)
        self.cmbIntegrationAxis.blockSignals(False)

    def populate_cut_params(self, cut_start=None, cut_end=None, cut_step=None):
        if cut_start is not None:
            self.lneCutStart.setText(cut_start)
        if cut_end is not None:
            self.lneCutEnd.setText(cut_end)
        if cut_step is not None:
            self.lneCutStep.setText(cut_step)

    def populate_integration_params(self, integration_start=None, integration_end=None):
        if integration_start is not None:
            self.lneCutIntegrationStart.setText(integration_start)
        if integration_end is not None:
            self.lneCutIntegrationEnd.setText(integration_end)

    def clear_input_fields(self, **kwargs):
        if 'keep_axes' not in kwargs or not kwargs['keep_axes']:
            self.populate_cut_axis_options([])
        self.populate_cut_params("", "", "")
        self.populate_integration_params("", "")
        self.lneCutIntegrationWidth.setText("")
        self.lneCutSmoothing.setText("")
        self.rdoCutNormToOne.setChecked(0)

    def is_fields_cleared(self):
        current_fields = self.get_input_fields()
        cleared_fields = {'cut_parameters': ['', '', ''],
                          'integration_range': ['', ''],
                          'integration_width': '',
                          'smoothing': '',
                          'normtounity': False}
        for k in cleared_fields:
            if current_fields[k] != cleared_fields[k]:
                return False
        return True

    def populate_input_fields(self, saved_input):
        self.populate_cut_params(*saved_input['cut_parameters'])
        self.populate_integration_params(*saved_input['integration_range'])
        self.lneCutIntegrationWidth.setText(saved_input['integration_width'])
        self.lneCutSmoothing.setText(saved_input['smoothing'])
        self.rdoCutNormToOne.setChecked(saved_input['normtounity'])

    def get_input_fields(self):
        saved_input = dict()
        saved_input['axes'] = [str(self.cmbCutAxis.itemText(ind)) for ind in range(self.cmbCutAxis.count())]
        saved_input['cut_parameters'] = [self.get_cut_axis_start(),
                                         self.get_cut_axis_end(),
                                         self.get_cut_axis_step()]
        saved_input['integration_range'] = [self.get_integration_start(),
                                            self.get_integration_end()]
        saved_input['integration_width'] = self.get_integration_width()
        saved_input['smoothing'] = self.get_smoothing()
        saved_input['normtounity'] = self.get_intensity_is_norm_to_one()
        return saved_input

    def enable(self):
        self.lneCutStart.setEnabled(True)
        self.lneCutEnd.setEnabled(True)
        self.lneCutStep.setEnabled(True)
        self.cmbCutAxis.setEnabled(True)

        self.lneCutIntegrationStart.setEnabled(True)
        self.lneCutIntegrationEnd.setEnabled(True)
        self.lneCutIntegrationWidth.setEnabled(True)

        self.lneEditCutIntensityStart.setEnabled(True)
        self.lneCutIntensityEnd.setEnabled(True)
        self.rdoCutNormToOne.setEnabled(True)

        self.btnCutSaveToWorkspace.setEnabled(False)
        self.btnCutPlot.setEnabled(False)
        self.btnCutPlotOver.setEnabled(False)

        self.btnCutSaveToWorkspace.setEnabled(True)
        self.btnCutPlot.setEnabled(True)
        self.btnCutPlotOver.setEnabled(True)

    def disable(self):
        self.lneCutStart.setEnabled(False)
        self.lneCutEnd.setEnabled(False)
        self.lneCutStep.setEnabled(False)
        self.cmbCutAxis.setEnabled(False)

        self.lneCutIntegrationStart.setEnabled(False)
        self.lneCutIntegrationEnd.setEnabled(False)
        self.lneCutIntegrationWidth.setEnabled(False)

        self.lneEditCutIntensityStart.setEnabled(False)
        self.lneCutIntensityEnd.setEnabled(False)
        self.rdoCutNormToOne.setEnabled(False)

        self.btnCutSaveToWorkspace.setEnabled(False)
        self.btnCutPlot.setEnabled(False)
        self.btnCutPlotOver.setEnabled(False)

    def plotting_params_only(self):
        self.disable()
        self.lneEditCutIntensityStart.setEnabled(True)
        self.lneCutIntensityEnd.setEnabled(True)
        self.rdoCutNormToOne.setEnabled(True)

        self.btnCutPlot.setEnabled(True)
        self.btnCutPlotOver.setEnabled(True)

    def set_validators(self):
        line_edits = [self.lneCutStart, self.lneCutEnd, self.lneCutIntegrationStart,
                      self.lneCutIntegrationEnd, self.lneCutIntegrationWidth, self.lneEditCutIntensityStart,
                      self.lneCutIntensityEnd]
        for line_edit in line_edits:
            line_edit.setValidator(QDoubleValidator())

    def force_normalization(self):
        self.rdoCutNormToOne.setEnabled(False)
        self.rdoCutNormToOne.setChecked(True)

    def clear_displayed_error(self):
        self.display_error("")
示例#5
0
class CutPlotOptions(PlotOptionsDialog):

    xLogEdited = Signal()
    yLogEdited = Signal()
    showLegendsEdited = Signal()

    def __init__(self):
        super(CutPlotOptions, self).__init__()
        self._line_widgets = []
        self.groupBox_4.hide()

        self.chkXLog.stateChanged.connect(self.xLogEdited)
        self.chkYLog.stateChanged.connect(self.yLogEdited)
        self.chkShowLegends.stateChanged.connect(self.showLegendsEdited)

    def set_line_options(self, line_options):
        for line in line_options:
            line_widget = LegendAndLineOptionsSetter(line,
                                                     self.color_validator)
            self.verticalLayout_legend.addWidget(line_widget)
            self._line_widgets.append(line_widget)

    def get_line_options(self):
        all_line_options = []
        for line_widget in self._line_widgets:
            line_options = {}
            for option in [
                    'shown', 'color', 'style', 'width', 'marker', 'legend',
                    'label', 'error_bar'
            ]:
                line_options[option] = getattr(line_widget, option)
            all_line_options.append(line_options)
        return all_line_options

    def color_validator(self, selected):
        count = 0
        for line_widget in self._line_widgets:
            if line_widget.get_color_index() == selected:
                count += 1
        if count <= 1:
            return True
        msg_box = QtWidgets.QMessageBox(self)
        msg_box.setWindowTitle("Selection Invalid")
        msg_box.setIcon(QtWidgets.QMessageBox.Warning)
        msg_box.setText("Cannot have two lines the same colour.")
        msg_box.exec_()
        return False

    @property
    def x_log(self):
        return self.chkXLog.isChecked()

    @x_log.setter
    def x_log(self, value):
        self.chkXLog.setChecked(value)

    @property
    def y_log(self):
        return self.chkYLog.isChecked()

    @y_log.setter
    def y_log(self, value):
        self.chkYLog.setChecked(value)

    @property
    def show_legends(self):
        return self.chkShowLegends.isChecked()

    @show_legends.setter
    def show_legends(self, value):
        self.chkShowLegends.setChecked(value)
示例#6
0
class PlotOptionsDialog(QtWidgets.QDialog):

    titleEdited = Signal()
    xLabelEdited = Signal()
    yLabelEdited = Signal()
    xRangeEdited = Signal()
    yRangeEdited = Signal()
    xGridEdited = Signal()
    yGridEdited = Signal()

    def __init__(self, parent=None):
        QtWidgets.QDialog.__init__(self, parent)
        load_ui(__file__, 'plot_options.ui', self)

        self.lneFigureTitle.editingFinished.connect(self.titleEdited)
        self.lneXAxisLabel.editingFinished.connect(self.xLabelEdited)
        self.lneYAxisLabel.editingFinished.connect(self.yLabelEdited)
        self.lneXMin.editingFinished.connect(self.xRangeEdited)
        self.lneXMax.editingFinished.connect(self.xRangeEdited)
        self.lneYMin.editingFinished.connect(self.yRangeEdited)
        self.lneYMax.editingFinished.connect(self.yRangeEdited)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)
        self.chkXGrid.stateChanged.connect(self.xGridEdited)
        self.chkYGrid.stateChanged.connect(self.yGridEdited)

    @property
    def x_range(self):
        try:
            xmin = float(str(self.lneXMin.text()))
            xmax = float(str(self.lneXMax.text()))
        except ValueError:
            return None, None
        return xmin, xmax

    @x_range.setter
    def x_range(self, x_range):
        try:
            xmin, xmax = x_range
        except ValueError:
            raise ValueError("pass an iterable with two items")
        self.lneXMin.setText(str(xmin))
        self.lneXMax.setText(str(xmax))

    @property
    def y_range(self):
        try:
            ymin = float(str(self.lneYMin.text()))
            ymax = float(str(self.lneYMax.text()))
        except ValueError:
            return None, None
        return ymin, ymax

    @y_range.setter
    def y_range(self, yrange):
        try:
            ymin, ymax = yrange
        except ValueError:
            raise ValueError("pass an iterable with two items")
        self.lneYMin.setText(str(ymin))
        self.lneYMax.setText(str(ymax))

    @property
    def title(self):
        return self.lneFigureTitle.text()

    @title.setter
    def title(self, value):
        self.lneFigureTitle.setText(value)

    @property
    def x_label(self):
        return self.lneXAxisLabel.text()

    @x_label.setter
    def x_label(self, value):
        self.lneXAxisLabel.setText(value)

    @property
    def y_label(self):
        return self.lneYAxisLabel.text()

    @y_label.setter
    def y_label(self, value):
        self.lneYAxisLabel.setText(value)

    @property
    def x_grid(self):
        return self.chkXGrid.isChecked()

    @x_grid.setter
    def x_grid(self, value):
        self.chkXGrid.setChecked(value)

    @property
    def y_grid(self):
        return self.chkYGrid.isChecked()

    @y_grid.setter
    def y_grid(self, value):
        self.chkYGrid.setChecked(value)
示例#7
0
class WorkspaceManagerWidget(WorkspaceView, QWidget):
    """A Widget that allows user to perform basic workspace save/load/rename/delete operations on workspaces"""

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

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        load_ui(__file__, 'workspacemanager.ui', self)
        self.button_mappings = {}
        self._main_window = None
        self.onscreen_workspaces = []
        self.tab = None
        self.tab_to_list = {
            TAB_2D: self.listWorkspaces2D,
            TAB_EVENT: self.listWorkspacesEvent,
            TAB_HISTO: self.listWorkspacesHisto
        }
        self.tabWidget.currentChanged.connect(self.tab_changed_method)
        self.listWorkspaces2D.itemSelectionChanged.connect(
            self.list_item_changed)
        self.listWorkspacesEvent.itemSelectionChanged.connect(
            self.list_item_changed)
        self.listWorkspacesHisto.itemSelectionChanged.connect(
            self.list_item_changed)
        self._presenter = WorkspaceManagerPresenter(self)

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

    def tab_changed_method(self, tab_index):
        self.clear_selection()
        self.tab = tab_index
        if self.tabWidget.tabText(tab_index)[-1:] == "*":
            self.tabWidget.setTabText(tab_index,
                                      self.tabWidget.tabText(tab_index)[:-1])
        self.tab_changed.emit(tab_index)

    def clear_selection(self):
        for ws_list in [
                self.listWorkspaces2D, self.listWorkspacesEvent,
                self.listWorkspacesHisto
        ]:
            ws_list.clearSelection()

    def current_list(self):
        return self.tab_to_list[self.tabWidget.currentIndex()]

    def current_tab(self):
        return self.tab if self.tab is not None else self.tabWidget.currentIndex(
        )

    def change_tab(self, tab):
        self.tabWidget.setCurrentIndex(tab)

    def highlight_tab(self, tab):
        tab_text = self.tabWidget.tabText(tab)
        if not tab_text.endswith('*'):
            self.tabWidget.setTabText(tab, tab_text + '*')

    def _btn_clicked(self):
        sender = self.sender()
        try:
            command = self.button_mappings[sender]
        except KeyError:
            raise Exception('Invalid sender')
        self._presenter.notify(command)

    def add_workspace(self, workspace):
        item = QListWidgetItem(workspace)
        self.onscreen_workspaces.append(workspace)
        workspace = get_workspace_handle(workspace)
        if isinstance(workspace, PixelWorkspace):
            self.listWorkspacesEvent.addItem(item)
        elif isinstance(workspace, HistogramWorkspace):
            self.listWorkspacesHisto.addItem(item)
        elif isinstance(workspace, Workspace):
            self.listWorkspaces2D.addItem(item)
        else:
            raise TypeError("Loaded file is not a valid workspace")

    def display_loaded_workspaces(self, workspaces):
        for workspace in workspaces:
            if workspace not in self.onscreen_workspaces:
                self.add_workspace(workspace)
        for workspace in self.onscreen_workspaces:
            if workspace not in workspaces:
                self.remove_workspace(workspace)

    def remove_workspace(self, workspace):
        """Remove workspace from list.

        Must be done in seperate function because items are removed by index and removing an items may alter the indexes
        of other items"""
        self.onscreen_workspaces.remove(workspace)
        for ws_list in [
                self.listWorkspaces2D, self.listWorkspacesEvent,
                self.listWorkspacesHisto
        ]:
            for index in range(ws_list.count()):
                if ws_list.item(index).text() == workspace:
                    ws_list.takeItem(index)
                    return

    def add_workspace_dialog(self):
        items = []
        current_list = self.current_list()
        for i in range(current_list.count()):
            item = current_list.item(i).text()
            items.append(item)
        dialog = QInputDialog()
        dialog.setWindowTitle("Add Workspace")
        dialog.setLabelText("Choose a workspace to add:")
        dialog.setOptions(QInputDialog.UseListViewForComboBoxItems)
        dialog.setComboBoxItems(items)
        dialog.exec_()
        return dialog.textValue()

    def subtraction_input(self):
        sub_input = SubtractInputBox(self.listWorkspaces2D, self)
        if sub_input.exec_():
            return sub_input.user_input()
        else:
            raise RuntimeError('dialog cancelled')

    def get_workspace_selected(self):
        selected_workspaces = [
            str(x.text()) for x in self.current_list().selectedItems()
        ]
        return selected_workspaces

    def set_workspace_selected(self, index):
        current_list = self.current_list()
        if QT_VERSION.startswith('5'):
            for item_index in range(current_list.count()):
                current_list.item(item_index).setSelected(False)
            for this_index in (index
                               if hasattr(index, "__iter__") else [index]):
                current_list.item(this_index).setSelected(True)
        else:
            for item_index in range(current_list.count()):
                current_list.setItemSelected(current_list.item(item_index),
                                             False)
            for this_index in (index
                               if hasattr(index, "__iter__") else [index]):
                current_list.setItemSelected(current_list.item(this_index),
                                             True)

    def get_workspace_index(self, ws_name):
        current_list = self.current_list()
        for index in range(current_list.count()):
            if str(current_list.item(index).text()) == ws_name:
                return index
        return -1

    def get_workspace_to_load_path(self):
        paths = QFileDialog.getOpenFileNames()
        return paths[0] if isinstance(
            paths, tuple) else [str(filename) for filename in paths]

    def get_workspace_new_name(self):
        name, success = QInputDialog.getText(
            self, "Workspace New Name",
            "Enter the new name for the workspace :      ")
        # The message above was padded with spaces to allow the whole title to show up
        if not success:
            raise ValueError('No Valid Name supplied')
        return str(name)

    def error_select_only_one_workspace(self):
        self._display_error(
            'Please select only one workspace and then try again')

    def error_select_one_or_more_workspaces(self):
        self._display_error(
            'Please select one or more workspaces the try again')

    def error_select_one_workspace(self):
        self._display_error('Please select a workspace then try again')

    def error_select_more_than_one_workspaces(self):
        self._display_error(
            'Please select more than one projected workspaces then try again')

    def error_invalid_save_path(self):
        self._display_error('No files were saved')

    def get_presenter(self):
        return self._presenter

    def list_item_changed(self):
        self._presenter.notify(Command.SelectionChanged)

    def error_unable_to_save(self):
        self._display_error("Something went wrong while trying to save")

    def clear_displayed_error(self):
        self._display_error("")
示例#8
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_()
示例#9
0
class SliceWidget(SliceView, QWidget):
    error_occurred = Signal('QString')
    busy = Signal(bool)

    def __init__(self, parent=None, *args, **kwargs):
        """This Widget provides basic control over displaying slices. This widget is NOT USABLE without a main window

        The main window must implement MainView"""
        QWidget.__init__(self, parent, *args, **kwargs)
        load_ui(__file__, 'slice.ui', self)
        self.btnSliceDisplay.clicked.connect(self._btn_clicked)
        self.display_errors_to_statusbar = True
        self._presenter = SliceWidgetPresenter(self)
        # Each time the fields are populated, set a minimum step size
        self._minimumStep = {}
        self.lneSliceXStep.editingFinished.connect(
            lambda: self._step_edited('x', self.lneSliceXStep))
        self.lneSliceYStep.editingFinished.connect(
            lambda: self._step_edited('y', self.lneSliceYStep))
        self.enable_units_choice(False)
        self.cmbSliceXAxis.currentIndexChanged.connect(
            lambda ind: self._change_axes(1, ind))
        self.cmbSliceYAxis.currentIndexChanged.connect(
            lambda ind: self._change_axes(2, ind))
        self.set_validators()

    def get_presenter(self):
        return self._presenter

    def _btn_clicked(self):
        if self._step_edited('x', self.lneSliceXStep) and self._step_edited(
                'y', self.lneSliceXStep):
            self._presenter.notify(Command.DisplaySlice)

    def _step_edited(self, idx, lineEdit):
        """Checks that user inputted step size is not too small."""
        if self._minimumStep:
            try:
                value = float(lineEdit.text())
            except ValueError:
                value = 0
                self._display_error(
                    'Invalid step parameter. Using default value.')
            if value == 0:
                lineEdit.setText(str(self._minimumStep[idx]))
                self._display_error('Setting step size to default.')
            elif value < (self._minimumStep[idx] / 100.):
                self._display_error('Step size too small!')
                return False
        return True

    def _change_axes(self, axis, idx):
        """Makes sure u1 and u2 are always different, and updates default limits/steps values."""
        curr_axis = axis - 1
        other_axis = axis % 2
        axes_handle = [self.cmbSliceXAxis, self.cmbSliceYAxis]
        num_items = axes_handle[other_axis].count()
        if num_items < 2:
            return
        axes = [
            self.cmbSliceXAxis.currentText(),
            self.cmbSliceYAxis.currentText()
        ]
        index = [
            self.cmbSliceXAxis.currentIndex(),
            self.cmbSliceYAxis.currentIndex()
        ]
        axes_set = [
            self.cmbSliceXAxis.setCurrentIndex,
            self.cmbSliceYAxis.setCurrentIndex
        ]
        if axes[curr_axis] == axes[other_axis]:
            new_index = (index[other_axis] + 1) % num_items
            axes_set[other_axis](new_index)
        self._presenter.populate_slice_params()

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

    def enable_units_choice(self, enabled):
        if enabled:
            # TODO implement conversion from meV to cm-1
            pass
            #self.cmbSliceUnits.show()
            #self.label_16.show()
        else:
            self.cmbSliceUnits.hide()
            self.label_16.hide()

    def get_units(self):
        return self.cmbSliceUnits.currentText()

    def get_slice_x_axis(self):
        return str(self.cmbSliceXAxis.currentText())

    def get_slice_y_axis(self):
        return str(self.cmbSliceYAxis.currentText())

    def get_slice_is_norm_to_one(self):
        return self.rdoSliceNormToOne.isChecked()

    def get_slice_smoothing(self):
        return str(self.lneSliceSmoothing.text())

    def get_slice_x_start(self):
        return str(self.lneSliceXStart.text())

    def get_slice_x_end(self):
        return str(self.lneSliceXEnd.text())

    def get_slice_x_step(self):
        return str(self.lneSliceXStep.text())

    def get_slice_y_start(self):
        return str(self.lneSliceYStart.text())

    def get_slice_y_end(self):
        return str(self.lneSliceYEnd.text())

    def get_slice_y_step(self):
        return str(self.lneSliceYStep.text())

    def get_slice_colourmap(self):
        return str(self.cmbSliceColormap.currentText())

    def get_slice_intensity_start(self):
        return str(self.lneSliceIntensityStart.text())

    def get_slice_intensity_end(self):
        return str(self.lneSliceIntensityEnd.text())

    def populate_colormap_options(self, colormaps):
        self.cmbSliceColormap.clear()
        for colormap in colormaps:
            self.cmbSliceColormap.addItem(colormap)

    def populate_slice_x_options(self, options):
        self.cmbSliceXAxis.clear()
        for option in options:
            self.cmbSliceXAxis.addItem(option)

    def populate_slice_y_options(self, options):
        self.cmbSliceYAxis.clear()
        for option in options:
            self.cmbSliceYAxis.addItem(option)

    def error_select_one_workspace(self):
        self._display_error('Please select a workspace to slice')

    def error_invalid_x_params(self):
        self._display_error('Invalid parameters for the x axis of the slice')

    def error_invalid_intensity_params(self):
        self._display_error(
            'Invalid parameters for the intensity of the slice')

    def error_invalid_plot_parameters(self):
        self._display_error('Invalid parameters for the slice')

    def error_invalid_smoothing_params(self):
        self._display_error('Invalid value for smoothing')

    def error_invalid_y_units(self):
        self._display_error('Invalid selection of the y axis')

    def error_invalid_y_params(self):
        self._display_error('Invalid parameters for the y axis of the slice')

    def error_invalid_x_units(self):
        self._display_error('Invalid selection of the x axis')

    def error(self, string):
        self._display_error(string)

    def populate_slice_x_params(self, x_start, x_end, x_step):
        self.lneSliceXStart.setText(x_start)
        self.lneSliceXEnd.setText(x_end)
        self.lneSliceXStep.setText(x_step)
        if x_step:
            self._minimumStep['x'] = float(x_step)

    def populate_slice_y_params(self, y_start, y_end, y_step):
        self.lneSliceYStart.setText(y_start)
        self.lneSliceYEnd.setText(y_end)
        self.lneSliceYStep.setText(y_step)
        if y_step:
            self._minimumStep['y'] = float(y_step)

    def clear_input_fields(self):
        self.populate_slice_x_options([])
        self.populate_slice_y_options([])
        self.populate_slice_x_params("", "", "")
        self.populate_slice_y_params("", "", "")
        self.lneSliceIntensityStart.setText("")
        self.lneSliceIntensityEnd.setText("")
        self.rdoSliceNormToOne.setChecked(0)
        self._minimumStep = {}

    def disable(self):
        self.cmbSliceXAxis.setEnabled(False)
        self.cmbSliceYAxis.setEnabled(False)
        self.lneSliceXStart.setEnabled(False)
        self.lneSliceXEnd.setEnabled(False)
        self.lneSliceXStep.setEnabled(False)
        self.lneSliceYStart.setEnabled(False)
        self.lneSliceYEnd.setEnabled(False)
        self.lneSliceYStep.setEnabled(False)
        self.lneSliceIntensityStart.setEnabled(False)
        self.lneSliceIntensityEnd.setEnabled(False)
        self.rdoSliceNormToOne.setEnabled(False)
        self.btnSliceDisplay.setEnabled(False)
        self.cmbSliceColormap.setEnabled(False)

    def enable(self):
        self.cmbSliceXAxis.setEnabled(True)
        self.cmbSliceYAxis.setEnabled(True)
        self.lneSliceXStart.setEnabled(True)
        self.lneSliceXEnd.setEnabled(True)
        self.lneSliceXStep.setEnabled(True)
        self.lneSliceYStart.setEnabled(True)
        self.lneSliceYEnd.setEnabled(True)
        self.lneSliceYStep.setEnabled(True)
        self.lneSliceIntensityStart.setEnabled(True)
        self.lneSliceIntensityEnd.setEnabled(True)
        self.rdoSliceNormToOne.setEnabled(True)
        self.btnSliceDisplay.setEnabled(True)
        self.cmbSliceColormap.setEnabled(True)

    def set_validators(self):
        line_edits = [
            self.lneSliceXStart, self.lneSliceXEnd, self.lneSliceXStep,
            self.lneSliceYStart, self.lneSliceYEnd, self.lneSliceYStep,
            self.lneSliceIntensityStart, self.lneSliceIntensityEnd
        ]
        for line_edit in line_edits:
            line_edit.setValidator(QDoubleValidator())

    def clear_displayed_error(self):
        self._display_error("")
示例#10
0
class DataLoaderWidget(QWidget):  # and some view interface

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

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        load_ui(__file__, 'dataloader.ui', self)

        self.file_system = QFileSystemModel()
        self.directory = QDir(os.path.expanduser('~'))
        path = self.directory.absolutePath()
        self.root_path = path
        self.file_system.setRootPath(path)
        self.file_system.setNameFilters(MSLICE_EXTENSIONS)
        self.file_system.setNameFilterDisables(False)
        self.table_view.setModel(self.file_system)
        self.table_view.setRootIndex(self.file_system.index(path))
        self.txtpath.setText(path)
        self.table_view.setColumnWidth(0, 320)
        self.table_view.setColumnWidth(1, 0)
        self.table_view.setColumnWidth(3, 140)
        self.table_view.setSelectionBehavior(QAbstractItemView.SelectRows)
        self._presenter = DataLoaderPresenter(self)
        self.btnload.setEnabled(False)
        self.btnmerge.setEnabled(False)

        self.table_view.activated.connect(self.activated)
        self.table_view.clicked.connect(self.validate_selection)
        self.txtpath.editingFinished.connect(self.refresh)
        self.btnback.clicked.connect(self.back)
        self.sort.currentIndexChanged.connect(self.sort_files)
        self.btnhome.clicked.connect(self.go_to_home)
        self.btnload.clicked.connect(partial(self.load, False))
        self.btnmerge.clicked.connect(partial(self.load, True))

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Backspace:
            self.back()
        else:
            event.accept()

    def activated(self, file_clicked):
        file_clicked = file_clicked.sibling(
            file_clicked.row(),
            0)  # so clicking anywhere on row gives filename
        if self.file_system.isDir(file_clicked):
            self.enter_dir(self.file_system.fileName(file_clicked))
        else:
            self.load(False)

    def enter_dir(self, directory):
        self.directory.cd(directory)
        self._update_from_path()

    def refresh(self):
        path_entered = QDir(self.txtpath.text())
        if path_entered.exists():
            self.directory = path_entered
            self._update_from_path()
        else:
            self._display_error("Invalid file path")

    def _update_from_path(self):
        new_path = self.directory.absolutePath()
        try:
            rel_path = os.path.relpath(new_path, self.root_path)
        except ValueError:  # We are in windows and user changed to another drive
            rel_path = '..'
        if rel_path.startswith('..'):
            self.file_system.setRootPath(new_path)
            self.root_path = new_path
        self.table_view.setRootIndex(self.file_system.index(new_path))
        self.txtpath.setText(new_path)
        self._clear_displayed_error()

    def back(self):
        self.directory.cdUp()
        self._update_from_path()

    def load(self, merge):
        self._presenter.load_workspace(self.get_selected_file_paths(), merge)

    def sort_files(self, column):
        self.table_view.sortByColumn(
            column, column %
            2)  # descending order for size/modified, ascending for name/type

    def go_to_home(self):
        self.directory = QDir(os.path.expanduser('~'))
        self._update_from_path()

    def validate_selection(self):
        self.btnload.setEnabled(False)
        self.btnmerge.setEnabled(False)
        selected = self.get_selected_file_paths()
        for selection in selected:
            if self.file_system.isDir(self.file_system.index(selection)):
                return
        self.btnload.setEnabled(True)
        if len(selected) > 1:
            self.btnmerge.setEnabled(True)

    def get_selected_file_paths(self):
        selected = self.table_view.selectionModel().selectedRows()
        for i in range(len(selected)):
            selected[i] = selected[i].sibling(selected[i].row(), 0)
            selected[i] = str(
                os.path.join(self.directory.absolutePath(),
                             self.file_system.fileName(selected[i])))
        return selected

    def get_workspace_efixed(self,
                             workspace,
                             hasMultipleWS=False,
                             default_value=None):
        Ef, applyToAll, success = EfInputDialog.getEf(workspace, hasMultipleWS,
                                                      default_value)
        if not success:
            raise ValueError('Fixed final energy not given')
        return Ef, applyToAll

    def get_presenter(self):
        return self._presenter

    def error_unable_to_open_file(self, filename=None):
        self._display_error(
            'MSlice was not able to load %s' %
            ('the selected file' if filename is None else filename))

    def error_merge_different_file_formats(self):
        self._display_error('Cannot merge files with different formats')

    def no_workspace_has_been_loaded(self, filename=None):
        if filename is None:
            self._display_error('No new workspaces have been loaded')
        else:
            self._display_error('File %s has not been loaded' % filename)

    def confirm_overwrite_workspace(self):
        text = 'The workspace you want to load has the same name as an existing workspace,' \
               'Are you sure you want to overwrite it?'
        reply = QMessageBox.question(self, 'Confirm Overwrite', text,
                                     QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.No)
        if reply == QMessageBox.Yes:
            return True
        else:
            return False

    def show_busy(self, is_busy):
        self.busy.emit(is_busy)

    def error_loading_workspace(self, message):
        self._display_error(str(message))

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

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