Mantid
Loading...
Searching...
No Matches
FitScriptGeneratorDataTable.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2020 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
8
9#include <QAbstractItemView>
10#include <QColor>
11#include <QDoubleValidator>
12#include <QHeaderView>
13#include <QHoverEvent>
14#include <QItemSelectionModel>
15#include <QLineEdit>
16#include <QStringList>
17#include <QValidator>
18
19#include <algorithm>
20
21namespace {
22
23int WS_INDEX_MIN(0);
24int WS_INDEX_MAX(100000);
25double X_EXTENT(100000.0);
26int X_PRECISION(5);
27
28QStringList const COLUMN_HEADINGS({"Name", "WS Index", "StartX", "EndX"});
29QColor const FUNCTION_INDEX_COLOR(QColor(30, 144, 255));
30QString const TABLE_STYLESHEET("QTableWidget {\n"
31 " font-size: 8pt;\n"
32 " border: 1px solid #828790;\n"
33 "}\n"
34 "\n"
35 "QTableWidget::item:selected {\n"
36 " background-color: #c7e0ff;\n"
37 " color: #000000;\n"
38 "}"
39 "\n"
40 "QTableWidget::item:hover {\n"
41 " background-color: #c7e0ff;\n"
42 "}");
43
44QValidator *createXValidator() {
45 auto validator = new QDoubleValidator(-X_EXTENT, X_EXTENT, X_PRECISION);
46 validator->setNotation(QDoubleValidator::Notation::StandardNotation);
47 return validator;
48}
49
50QValidator *createWSIndexValidator() { return new QIntValidator(WS_INDEX_MIN, WS_INDEX_MAX); }
51
52QTableWidgetItem *createTableItem(QString const &value, Qt::AlignmentFlag const &alignment, bool editable,
53 QColor const &color = QColor(0, 0, 0)) {
54 auto item = new QTableWidgetItem(value);
55 item->setData(Qt::ForegroundRole, color);
56 item->setTextAlignment(alignment);
57 if (!editable)
58 item->setFlags(item->flags() ^ Qt::ItemIsEditable);
59 return item;
60}
61
62QTableWidgetItem *createWSIndexTableItem(int value, Qt::AlignmentFlag const &alignment, bool editable) {
63 return createTableItem(QString::number(value), alignment, editable);
64}
65
66QTableWidgetItem *createXTableItem(double value, Qt::AlignmentFlag const &alignment, bool editable) {
67 return createTableItem(QString::number(value, 'f', X_PRECISION), alignment, editable);
68}
69
70QString toFunctionIndex(MantidQt::MantidWidgets::FitDomainIndex index) {
71 return "f" + QString::number(index.value) + ".";
72}
73
74} // namespace
75
77
83 : QTableWidget(parent), m_selectedRows(), m_selectedColumn(-1), m_selectedValue(0.0),
84 m_lastHoveredIndex(QPersistentModelIndex()) {
85 this->setSelectionBehavior(QAbstractItemView::SelectRows);
86 this->setSelectionMode(QAbstractItemView::ExtendedSelection);
87 this->setShowGrid(false);
88 this->setColumnCount(COLUMN_HEADINGS.size());
89 this->setRowCount(0);
90 this->horizontalHeader()->setHighlightSections(false);
91 this->horizontalHeader()->setStretchLastSection(true);
92
93 this->setColumnWidth(ColumnIndex::WorkspaceName, 280);
94 this->setColumnWidth(ColumnIndex::WorkspaceIndex, 80);
95 this->setColumnWidth(ColumnIndex::StartX, 100);
96 this->setColumnWidth(ColumnIndex::EndX, 100);
97
98 this->setHorizontalHeaderLabels(COLUMN_HEADINGS);
99
100 this->setStyleSheet(TABLE_STYLESHEET);
101
102 this->viewport()->installEventFilter(this);
103
104 this->setItemDelegateForColumn(ColumnIndex::WorkspaceName, new CustomItemDelegate(this, ColumnIndex::WorkspaceName));
105 this->setItemDelegateForColumn(ColumnIndex::WorkspaceIndex,
106 new CustomItemDelegate(this, ColumnIndex::WorkspaceIndex));
107 this->setItemDelegateForColumn(ColumnIndex::StartX, new CustomItemDelegate(this, ColumnIndex::StartX));
108 this->setItemDelegateForColumn(ColumnIndex::EndX, new CustomItemDelegate(this, ColumnIndex::EndX));
109
110 connect(this, SIGNAL(itemClicked(QTableWidgetItem *)), this, SLOT(handleItemClicked(QTableWidgetItem *)));
111 connect(this, SIGNAL(itemSelectionChanged()), this, SLOT(handleItemSelectionChanged()));
112 disconnect(this->verticalHeader(), SIGNAL(sectionPressed(int)), this, SLOT(selectRow(int)));
113}
114
115bool FitScriptGeneratorDataTable::eventFilter(QObject *widget, QEvent *event) {
116 if (widget == this->viewport()) {
117 auto index = hoveredRowIndex(event);
118
119 if (index != m_lastHoveredIndex) {
120 if (this->item(m_lastHoveredIndex.row(), m_lastHoveredIndex.column()))
121 emit itemExited(index.isValid() ? index.row() : -1);
122 m_lastHoveredIndex = QPersistentModelIndex(index);
123 }
124 }
125 return QTableWidget::eventFilter(widget, event);
126}
127
130 m_selectedColumn = item->column();
131 if (m_selectedColumn == ColumnIndex::StartX || m_selectedColumn == ColumnIndex::EndX)
132 m_selectedValue = item->text().toDouble();
133}
134
136 auto *selectionModel = this->selectionModel();
137
138 if (!selectionModel->hasSelection()) {
139 this->blockSignals(true);
140
141 // Makes sure that multi-selection rows are stored within the selectionModel
142 // as should be expected. This prevents a bug where not all selected rows
143 // were being stored in the selection model.
144 auto itemSelection = selectionModel->selection();
145 for (auto const &selectedRow : m_selectedRows) {
146 this->selectRow(static_cast<int>(selectedRow.value));
147 itemSelection.merge(selectionModel->selection(), QItemSelectionModel::Select);
148 }
149 selectionModel->clearSelection();
150 selectionModel->select(itemSelection, QItemSelectionModel::Select);
151
152 this->blockSignals(false);
153 } else {
155 }
156}
157
158QPersistentModelIndex FitScriptGeneratorDataTable::hoveredRowIndex(QEvent *event) {
160 auto const eventType = event->type();
161 if (eventType == QEvent::HoverMove)
162 index = QPersistentModelIndex(this->indexAt(static_cast<QHoverEvent *>(event)->pos()));
163 else if (eventType == QEvent::Leave)
164 index = QPersistentModelIndex(QModelIndex());
165
166 return index;
167}
168
170 return getText(row, ColumnIndex::WorkspaceName).toStdString();
171}
172
174 return getText(row, ColumnIndex::WorkspaceIndex).toInt();
175}
176
178 return getText(row, ColumnIndex::StartX).toDouble();
179}
180
182 return getText(row, ColumnIndex::EndX).toDouble();
183}
184
185std::vector<FitDomainIndex> FitScriptGeneratorDataTable::allRows() const {
186 std::vector<FitDomainIndex> rowIndices;
187 rowIndices.reserve(this->rowCount());
188 for (auto index = 0; index < this->rowCount(); ++index)
189 rowIndices.emplace_back(FitDomainIndex(index));
190
191 std::reverse(rowIndices.begin(), rowIndices.end());
192 return rowIndices;
193}
194
195std::vector<FitDomainIndex> FitScriptGeneratorDataTable::selectedRows() const {
196 std::vector<FitDomainIndex> rowIndices;
197
198 auto const selectionModel = this->selectionModel();
199 if (selectionModel->hasSelection()) {
200 const auto selectedRows = selectionModel->selectedRows();
201 std::transform(
202 selectedRows.cbegin(), selectedRows.cend(), std::back_inserter(rowIndices),
203 [](const auto &rowIndex) { return std::move(FitDomainIndex(static_cast<std::size_t>(rowIndex.row()))); });
204 std::reverse(rowIndices.begin(), rowIndices.end());
205 }
206 return rowIndices;
207}
208
210 if (hasLoadedData()) {
211 auto const rows = selectedRows();
212 return rows.size() > 0 ? rows[0] : FitDomainIndex{0};
213 }
214
215 throw std::runtime_error("There is no currentRow as data has not been loaded yet.");
216}
217
218bool FitScriptGeneratorDataTable::hasLoadedData() const { return this->rowCount() > 0; }
219
221 auto const rows = selectedRows();
222 if (rows.empty())
223 return "";
224 return this->verticalHeaderItem(static_cast<int>(rows[0].value))->text();
225}
226
227void FitScriptGeneratorDataTable::renameWorkspace(QString const &workspaceName, QString const &newName) {
228 for (auto rowIndex = 0; rowIndex < this->rowCount(); ++rowIndex) {
229 auto tableItem = this->item(rowIndex, ColumnIndex::WorkspaceName);
230 if (tableItem->text() == workspaceName)
231 tableItem->setText(newName);
232 }
233}
234
236 this->removeRow(static_cast<int>(domainIndex.value));
238
240
241 if (m_selectedRows.empty() && this->rowCount() > 0)
242 this->selectRow(0);
243
245}
246
247void FitScriptGeneratorDataTable::addDomain(QString const &workspaceName, MantidWidgets::WorkspaceIndex workspaceIndex,
248 double startX, double endX) {
249 this->blockSignals(true);
250
251 auto const rowIndex = this->rowCount();
252 this->insertRow(rowIndex);
253
254 this->setVerticalHeaderItem(rowIndex, createTableItem(toFunctionIndex(FitDomainIndex(rowIndex)), Qt::AlignCenter,
255 false, FUNCTION_INDEX_COLOR));
256 this->setItem(rowIndex, ColumnIndex::WorkspaceName, createTableItem(workspaceName, Qt::AlignVCenter, false));
257 this->setItem(rowIndex, ColumnIndex::WorkspaceIndex,
258 createWSIndexTableItem(static_cast<int>(workspaceIndex.value), Qt::AlignCenter, false));
259 this->setItem(rowIndex, ColumnIndex::StartX, createXTableItem(startX, Qt::AlignCenter, true));
260 this->setItem(rowIndex, ColumnIndex::EndX, createXTableItem(endX, Qt::AlignCenter, true));
261
262 if (!this->selectionModel()->hasSelection()) {
263 m_selectedRows.emplace_back(rowIndex);
264 this->selectRow(rowIndex);
265 }
266
267 this->blockSignals(false);
268}
269
271 for (auto i = FitDomainIndex(0); i < FitDomainIndex(this->rowCount()); ++i)
272 this->setVerticalHeaderItem(static_cast<int>(i.value),
273 createTableItem(toFunctionIndex(i), Qt::AlignCenter, false, FUNCTION_INDEX_COLOR));
274}
275
277 return this->item(static_cast<int>(row.value), column)->text();
278}
279
281 if (!m_selectedRows.empty() && m_selectedColumn >= 0)
282 setSelectedXValue(this->item(static_cast<int>(m_selectedRows[0].value), m_selectedColumn)->text().toDouble());
283}
284
286
288 this->verticalHeader()->setVisible(visible);
289}
290
292 this->blockSignals(true);
293 if (!m_selectedRows.empty())
294 this->setItem(static_cast<int>(m_selectedRows[0].value), m_selectedColumn,
295 createXTableItem(xValue, Qt::AlignCenter, true));
296 this->blockSignals(false);
297}
298
304 : QStyledItemDelegate(parent), m_tableWidget(parent), m_columnIndex(index), m_hoveredIndex(-1) {
305 m_tableWidget = parent;
306 m_tableWidget->setMouseTracking(true);
307
308 connect(m_tableWidget, SIGNAL(itemEntered(QTableWidgetItem *)), this, SLOT(handleItemEntered(QTableWidgetItem *)));
309 connect(m_tableWidget, SIGNAL(itemExited(int)), this, SLOT(handleItemExited(int)));
310}
311
312void CustomItemDelegate::handleItemEntered(QTableWidgetItem *item) {
313 m_hoveredIndex = item->row();
314 m_tableWidget->viewport()->update();
315}
316
317void CustomItemDelegate::handleItemExited(int newRowIndex) { m_hoveredIndex = newRowIndex; }
318
319QWidget *CustomItemDelegate::createEditor(QWidget *parent, QStyleOptionViewItem const &option,
320 QModelIndex const &index) const {
321 Q_UNUSED(option);
322 Q_UNUSED(index);
323
324 auto lineEdit = new QLineEdit(parent);
325 switch (m_columnIndex) {
326 case ColumnIndex::WorkspaceName:
327 break;
328 case ColumnIndex::WorkspaceIndex:
329 lineEdit->setValidator(createWSIndexValidator());
330 break;
331 case ColumnIndex::StartX:
332 lineEdit->setValidator(createXValidator());
333 break;
334 case ColumnIndex::EndX:
335 lineEdit->setValidator(createXValidator());
336 break;
337 }
338
339 return lineEdit;
340}
341
342void CustomItemDelegate::paint(QPainter *painter, QStyleOptionViewItem const &option, QModelIndex const &index) const {
343 auto opt = QStyleOptionViewItem(option);
344 if (index.row() == m_hoveredIndex)
345 opt.state |= QStyle::State_MouseOver;
346 QStyledItemDelegate::paint(painter, opt, index);
347}
348
349} // namespace MantidQt::MantidWidgets
double value
The value of the point.
Definition: FitMW.cpp:51
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
This class is used for formating the type of data allowed in each of the tables columns.
QWidget * createEditor(QWidget *parent, QStyleOptionViewItem const &option, QModelIndex const &index) const override
void paint(QPainter *painter, QStyleOptionViewItem const &option, QModelIndex const &index) const override
CustomItemDelegate(FitScriptGeneratorDataTable *parent, ColumnIndex const &index)
CustomItemDelegate class methods.
This class represents the table widget which holds domain data for the FitScriptGenerator interface.
void renameWorkspace(QString const &workspaceName, QString const &newName)
QString getText(FitDomainIndex row, int column) const
void addDomain(QString const &workspaceName, MantidWidgets::WorkspaceIndex workspaceIndex, double startX, double endX)
void removeDomain(MantidWidgets::FitDomainIndex domainIndex)
MantidWidgets::WorkspaceIndex workspaceIndex(FitDomainIndex row) const
bool eventFilter(QObject *widget, QEvent *event) override
FitScriptGeneratorDataTable(QWidget *parent=nullptr)
FitScriptGeneratorDataTable class methods.
IndexType< 0 > FitDomainIndex
Definition: IndexTypes.h:59
A struct to impliment strongly typed integers, without implicit conversion.
Definition: IndexTypes.h:24
IntImplementationType value
Definition: IndexTypes.h:26