// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #include "JFJochViewerSpotListWindow.h" #include #include JFJochViewerSpotListWindow::JFJochViewerSpotListWindow(QWidget* parent) : QMainWindow(parent) { QWidget* centralWidget = new QWidget(this); setCentralWidget(centralWidget); QVBoxLayout* layout = new QVBoxLayout(centralWidget); tableView = new QTableView(this); tableModel = new QStandardItemModel(this); setupTableModel(); proxyModel = new QSortFilterProxyModel(this); proxyModel->setSourceModel(tableModel); proxyModel->setSortRole(Qt::UserRole); // numeric sort based on UserRole tableView->setModel(proxyModel); tableView->sortByColumn(2, Qt::DescendingOrder); // default: Intensity desc tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); tableView->setSortingEnabled(true); tableView->verticalHeader()->setVisible(false); tableView->horizontalHeader()->setSectionsClickable(true); tableView->horizontalHeader()->setSortIndicatorShown(true); tableView->setStyleSheet("background-color: white;"); tableView->setSelectionBehavior(QAbstractItemView::SelectRows); tableView->setSelectionMode(QAbstractItemView::SingleSelection); tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); layout->addWidget(tableView); setWindowTitle("Observed spots"); resize(800, 600); connect(tableView, &QTableView::doubleClicked, this, &JFJochViewerSpotListWindow::onTableRowDoubleClicked); } void JFJochViewerSpotListWindow::setupTableModel() { // Columns: 0..11 tableModel->setColumnCount(12); tableModel->setHeaderData(0, Qt::Horizontal, "#"); tableModel->setHeaderData(1, Qt::Horizontal, "x"); tableModel->setHeaderData(2, Qt::Horizontal, "y"); tableModel->setHeaderData(3, Qt::Horizontal, "Intensity"); tableModel->setHeaderData(4, Qt::Horizontal, "Max value"); tableModel->setHeaderData(5, Qt::Horizontal, "d [Å]"); tableModel->setHeaderData(6, Qt::Horizontal, "Ice ring"); tableModel->setHeaderData(7, Qt::Horizontal, "Indexed"); tableModel->setHeaderData(8, Qt::Horizontal, "h"); tableModel->setHeaderData(9, Qt::Horizontal, "k"); tableModel->setHeaderData(10, Qt::Horizontal, "l"); tableModel->setHeaderData(11, Qt::Horizontal, "Dist. Ewald [Å^-1]"); } void JFJochViewerSpotListWindow::addSpotRow(int index, const SpotToSave& s) { QList row; auto mkNum = [](const QVariant& userValue, const QString& displayText = QString()) { auto* it = new QStandardItem(); if (displayText.isEmpty()) { it->setData(userValue, Qt::DisplayRole); } else { it->setData(displayText, Qt::DisplayRole); } it->setData(userValue, Qt::UserRole); it->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); return it; }; row.append(mkNum(index)); // x (two decimals, right-aligned, numeric sort on value) row.append(mkNum(static_cast(s.x), QString::number(s.x, 'f', 2))); // y (two decimals, right-aligned, numeric sort on value) row.append(mkNum(static_cast(s.y), QString::number(s.y, 'f', 2))); // Intensity (right-aligned) row.append(mkNum(static_cast(s.intensity))); // Max value (right-aligned) row.append(mkNum(static_cast(s.maxc))); // d_A (right-aligned) row.append(mkNum(static_cast(s.d_A))); // Ice ring (text) { auto* it = new QStandardItem(s.ice_ring ? "Yes" : "No"); row.append(it); } // Indexed (text) { auto* it = new QStandardItem(s.indexed ? "Yes" : "No"); row.append(it); } // h (right-aligned) row.append(mkNum(static_cast(s.h))); // k (right-aligned) row.append(mkNum(static_cast(s.k))); // l (right-aligned) row.append(mkNum(static_cast(s.l))); // dist_ewald_sphere (right-aligned) row.append(mkNum(static_cast(s.dist_ewald_sphere))); tableModel->appendRow(row); } void JFJochViewerSpotListWindow::datasetLoaded(std::shared_ptr dataset) { image = {}; tableModel->removeRows(0, tableModel->rowCount()); } void JFJochViewerSpotListWindow::imageLoaded(std::shared_ptr in_image) { tableModel->removeRows(0, tableModel->rowCount()); image = in_image; if (image) { for (int i = 0; i < image->ImageData().spots.size(); ++i) addSpotRow(i, image->ImageData().spots[i]); } } void JFJochViewerSpotListWindow::open() { show(); raise(); activateWindow(); } void JFJochViewerSpotListWindow::onTableRowDoubleClicked(const QModelIndex& index) { if (!index.isValid()) return; QModelIndex src = proxyModel->mapToSource(index); int spotIndex = src.row(); if (!image) return; if (spotIndex >= 0 && spotIndex < image->ImageData().spots.size()) emit spotSelected(image->ImageData().spots[spotIndex].x, image->ImageData().spots[spotIndex].y); } void JFJochViewerSpotListWindow::closeEvent(QCloseEvent* event) { event->accept(); emit closing(); }