view.py 11.2 KB
Newer Older
1
2
3
# Mantid Repository : https://github.com/mantidproject/mantid
#
# Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4
5
#   NScD Oak Ridge National Laboratory, European Spallation Source,
#   Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6
7
8
9
# SPDX - License - Identifier: GPL - 3.0 +
#  This file is part of the mantid workbench.
#
#
10
11
12
from functools import partial

from qtpy import QtGui
13
from qtpy.QtCore import Qt
14
from qtpy.QtGui import QKeySequence
15
from qtpy.QtWidgets import (QAbstractItemView, QAction, QHeaderView, QMessageBox, QTabWidget, QTableView, QMenu)
16

17
import mantidqt.icons
18
from mantidqt.widgets.workspacedisplay.matrix.table_view_model import MatrixWorkspaceTableViewModelType
19
from mantidqt.plotting.functions import can_overplot
20
21


22
23
24
25
26
27
28
29
class MatrixWorkspaceTableView(QTableView):
    def __init__(self, parent):
        super(MatrixWorkspaceTableView, self).__init__(parent)
        self.setSelectionBehavior(QAbstractItemView.SelectItems)

        header = self.horizontalHeader()
        header.sectionDoubleClicked.connect(self.handle_double_click)

30
31
32
    def resizeEvent(self, event):
        super(MatrixWorkspaceTableView, self).resizeEvent(event)

33
34
35
36
37
38
39
        header = self.horizontalHeader()
        header.setSectionResizeMode(QHeaderView.Interactive)

    def handle_double_click(self, section):
        header = self.horizontalHeader()
        header.resizeSection(section, header.defaultSectionSize())

40

41
class MatrixWorkspaceDisplayView(QTabWidget):
42

43
    def __init__(self, presenter, parent=None, window_flags=Qt.Window):
44
45
46
        super(MatrixWorkspaceDisplayView, self).__init__(parent)

        self.presenter = presenter
47
        self.COPY_ICON = mantidqt.icons.get_icon("mdi.content-copy")
48
        self.GRAPH_ICON = mantidqt.icons.get_icon("mdi.chart-line")
Conor Finn's avatar
Conor Finn committed
49
        self.TABLE_ICON = mantidqt.icons.get_icon("mdi.table")
50

51
52
53
54
55
56
        # change the default color of the rows - makes them light blue
        # monitors and masked rows are colored in the table's custom model
        palette = self.palette()
        palette.setColor(QtGui.QPalette.Base, QtGui.QColor(128, 255, 255))
        self.setPalette(palette)

57
        self.setAttribute(Qt.WA_DeleteOnClose, True)
58
        self.setWindowFlags(window_flags)
59

60
61
62
        self.active_tab_index = 0
        self.currentChanged.connect(self.set_scroll_position_on_new_focused_tab)

63
64
        # local list to keep track of the added tabs
        self.tabs = []
65

66
67
68
        self.table_y = self.add_table("Y values")
        self.table_x = self.add_table("X values")
        self.table_e = self.add_table("E values")
69
70
71

        if self.presenter.hasDx:
            self.table_dx = self.add_table("dX values")
72

73
    def add_table(self, label):
74
75
        tab = MatrixWorkspaceTableView(self)

76
77
78
79
80
81
82
83
84
        self.addTab(tab, label)
        self.tabs.append(tab)
        return tab

    def keyPressEvent(self, event):
        if event.matches(QKeySequence.Copy):
            self.presenter.action_keypress_copy(self.tabs[self.currentIndex()])
        super(MatrixWorkspaceDisplayView, self).keyPressEvent(event)

85
86
87
    def get_active_tab(self):
        return self.tabs[self.active_tab_index]

88
    def set_scroll_position_on_new_focused_tab(self, new_tab_index):
89
        """
90
        Updates the new focused tab's scroll position to match the old one.
91
        :type new_tab_index: int
92
        :param new_tab_index: The widget position index in the parent's widget list
93
        """
94
95
        old_tab = self.widget(self.active_tab_index)
        new_tab = self.widget(new_tab_index)
96

97
98
99
        new_tab.horizontalScrollBar().setValue(old_tab.horizontalScrollBar().value())
        new_tab.verticalScrollBar().setValue(old_tab.verticalScrollBar().value())
        self.active_tab_index = new_tab_index
100

101
    def set_context_menu_actions(self, table):
102
103
        """
        Sets up the context menu actions for the table
104
        :type table: QTableView
105
106
107
108
109
110
        :param table: The table whose context menu actions will be set up.
        :param ws_read_function: The read function used to efficiently retrieve data directly from the workspace
        """
        copy_action = QAction(self.COPY_ICON, "Copy", table)
        # sets the first (table) parameter of the copy action callback
        # so that each context menu can copy the data from the correct table
111
        decorated_copy_action_with_correct_table = partial(self.presenter.action_copy_cells, table)
112
113
114
115
116
117
        copy_action.triggered.connect(decorated_copy_action_with_correct_table)

        table.setContextMenuPolicy(Qt.ActionsContextMenu)
        table.addAction(copy_action)

        horizontalHeader = table.horizontalHeader()
118
        horizontalHeader.setContextMenuPolicy(Qt.CustomContextMenu)
119
        horizontalHeader.setSectionResizeMode(QHeaderView.Fixed)
120
        horizontalHeader.customContextMenuRequested.connect(self.bin_context_menu_opened)
121
122

        verticalHeader = table.verticalHeader()
123
        verticalHeader.setContextMenuPolicy(Qt.CustomContextMenu)
124
        verticalHeader.setSectionResizeMode(QHeaderView.Fixed)
125
        verticalHeader.customContextMenuRequested.connect(self.spectra_context_menu_opened)
126

127
    def set_model(self, model_x, model_y, model_e, model_dx):
128
129
130
        self._set_table_model(self.table_x, model_x, MatrixWorkspaceTableViewModelType.x)
        self._set_table_model(self.table_y, model_y, MatrixWorkspaceTableViewModelType.y)
        self._set_table_model(self.table_e, model_e, MatrixWorkspaceTableViewModelType.e)
131
132
        if self.presenter.hasDx:
            self._set_table_model(self.table_dx, model_dx, MatrixWorkspaceTableViewModelType.dx)
133
134
135
136
137
138
139

    @staticmethod
    def _set_table_model(table, model, expected_model_type):
        assert model.type == expected_model_type, \
            "The model for the table with {0} values has a wrong model type: {1}".format(expected_model_type.upper(),
                                                                                         model.model_type)
        table.setModel(model)
140

141
142
143
144
145
146
147
    def ask_confirmation(self, message, title="Mantid Workbench"):
        """
        :param message:
        :return:
        """
        reply = QMessageBox.question(self, title, message, QMessageBox.Yes, QMessageBox.No)
        return True if reply == QMessageBox.Yes else False
148
149

    def setup_bin_context_menu(self, table):
150
        context_menu = QMenu(self)
151
152
153
154
155
        self.setup_copy_bin_actions(context_menu, table)
        self.setup_plot_bin_actions(context_menu, table)
        return context_menu

    def setup_spectra_context_menu(self, table):
156
        context_menu = QMenu(self)
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
        self.setup_copy_spectrum_actions(context_menu, table)
        self.setup_plot_spectrum_actions(context_menu, table)
        return context_menu

    def bin_context_menu_opened(self, position):
        """
        Open the context menu in the correct location
        :param position: The position to open the menu, e.g. where
                         the mouse button was clicked
        """
        context_menu = self.setup_bin_context_menu(self.currentWidget())
        context_menu.exec_(self.currentWidget().horizontalHeader().mapToGlobal(position))

    def spectra_context_menu_opened(self, position):
        """
        Open the context menu in the correct location
        :param position: The position to open the menu, e.g. where
                         the mouse button was clicked
        """
        context_menu = self.setup_spectra_context_menu(self.currentWidget())
        context_menu.exec_(self.currentWidget().verticalHeader().mapToGlobal(position))

    def setup_plot_bin_actions(self, context_menu, table):
        plot_bin_action = QAction(self.GRAPH_ICON, "Plot bin (values only)", self)
        plot_bin_action.triggered.connect(partial(self.presenter.action_plot_bin, table))
        plot_bin_with_errors_action = QAction(self.GRAPH_ICON, "Plot bin (values + errors)", self)
        plot_bin_with_errors_action.triggered.connect(partial(self.presenter.action_plot_bin_with_errors, table))
        overplot_bin_action = QAction(self.GRAPH_ICON, "Overplot bin (values only)", self)
        overplot_bin_action.triggered.connect(partial(self.presenter.action_overplot_bin, table))
        overplot_bin_with_errors_action = QAction(self.GRAPH_ICON, "Overplot bin (values + errors)", self)
        overplot_bin_with_errors_action.triggered.connect(partial(self.presenter.action_overplot_bin_with_errors,
                                                                  table))
        overplot_bin_action.setEnabled(can_overplot())
        overplot_bin_with_errors_action.setEnabled(can_overplot())
        separator = QAction(self)
        separator.setSeparator(True)
        list(map(context_menu.addAction, [plot_bin_action, plot_bin_with_errors_action, separator,
                                          overplot_bin_action, overplot_bin_with_errors_action]))

    def setup_plot_spectrum_actions(self, context_menu, table):
        plot_spectrum_action = QAction(self.GRAPH_ICON, "Plot spectrum (values only)", self)
        plot_spectrum_action.triggered.connect(partial(self.presenter.action_plot_spectrum, table))
        plot_spectrum_with_errors_action = QAction(self.GRAPH_ICON, "Plot spectrum (values + errors)",
                                                   self)
        plot_spectrum_with_errors_action.triggered.connect(
            partial(self.presenter.action_plot_spectrum_with_errors, table))
        overplot_spectrum_action = QAction(self.GRAPH_ICON, "Overplot spectrum (values only)", self)
        overplot_spectrum_action.triggered.connect(partial(self.presenter.action_overplot_spectrum, table))
        overplot_spectrum_with_errors_action = QAction(self.GRAPH_ICON, "Overplot spectrum (values + errors)", self)
        overplot_spectrum_with_errors_action.triggered.connect(partial(
            self.presenter.action_overplot_spectrum_with_errors, table))
        overplot_spectrum_action.setEnabled(can_overplot())
        overplot_spectrum_with_errors_action.setEnabled(can_overplot())
        separator = QAction(self)
        separator.setSeparator(True)
        list(map(context_menu.addAction, [plot_spectrum_action, plot_spectrum_with_errors_action, separator,
                                          overplot_spectrum_action, overplot_spectrum_with_errors_action]))

    def setup_copy_bin_actions(self, context_menu, table):
        copy_bin_values = QAction(self.COPY_ICON, "Copy", self)
        copy_bin_values.triggered.connect(partial(self.presenter.action_copy_bin_values, table))
        copy_bin_to_table = QAction(self.TABLE_ICON, "Copy bin to table", self)
        copy_bin_to_table.triggered.connect(partial(self.presenter.action_copy_bin_to_table, table))
        separator = QAction(self)
        separator.setSeparator(True)
        list(map(context_menu.addAction, [copy_bin_values, copy_bin_to_table, separator]))

    def setup_copy_spectrum_actions(self, context_menu, table):
        copy_spectrum_values = QAction(self.COPY_ICON, "Copy", self)
        copy_spectrum_values.triggered.connect(
            partial(self.presenter.action_copy_spectrum_values, table))
        copy_spectrum_to_table = QAction(self.TABLE_ICON, "Copy spectrum to table", self)
        copy_spectrum_to_table.triggered.connect(partial(self.presenter.action_copy_spectrum_to_table, table))
        separator = QAction(self)
        separator.setSeparator(True)
        list(map(context_menu.addAction, [copy_spectrum_values, copy_spectrum_to_table, separator]))