File indexing completed on 2025-10-26 03:35:36
0001 /* 0002 File : ROOTOptionsWidget.cpp 0003 Project : LabPlot 0004 Description : widget providing options for the import of ROOT data 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2018 Christoph Roick <chrisito@gmx.de> 0007 SPDX-FileCopyrightText: 2022 Stefan Gerlach <stefan.gerlach@uni.kn> 0008 0009 SPDX-License-Identifier: GPL-2.0-or-later 0010 */ 0011 0012 #include "ROOTOptionsWidget.h" 0013 #include "ImportFileWidget.h" 0014 0015 #include "backend/datasources/filters/ROOTFilter.h" 0016 #include "backend/lib/macros.h" 0017 0018 ROOTOptionsWidget::ROOTOptionsWidget(QWidget* parent, ImportFileWidget* fileWidget) 0019 : QWidget(parent) 0020 , m_fileWidget(fileWidget) { 0021 ui.setupUi(parent); 0022 histItem = new QTreeWidgetItem(ui.twContent, QStringList(i18n("Histograms"))); 0023 histItem->setFlags(Qt::ItemIsEnabled); 0024 treeItem = new QTreeWidgetItem(ui.twContent, QStringList(i18n("Trees and Tuples"))); 0025 treeItem->setFlags(Qt::ItemIsEnabled); 0026 0027 connect(ui.twContent, &QTreeWidget::itemSelectionChanged, this, &ROOTOptionsWidget::rootObjectSelectionChanged); 0028 connect(ui.bRefreshPreview, &QPushButton::clicked, fileWidget, &ImportFileWidget::refreshPreview); 0029 } 0030 0031 void ROOTOptionsWidget::clear() { 0032 qDeleteAll(histItem->takeChildren()); 0033 qDeleteAll(treeItem->takeChildren()); 0034 ui.twPreview->clearContents(); 0035 } 0036 0037 void fillTree(QTreeWidgetItem* node, const ROOTFilter::Directory& dir) { 0038 node->setFlags(Qt::ItemIsEnabled); 0039 for (const auto& child : dir.children) 0040 fillTree(new QTreeWidgetItem(node, QStringList(child.name)), child); 0041 for (const auto& content : dir.content) 0042 (new QTreeWidgetItem(node, QStringList(content.first)))->setData(0, Qt::UserRole, content.second); 0043 } 0044 0045 QMultiHash<QStringList, QVector<QStringList>> 0046 findLeaves(QTreeWidgetItem* node, ROOTFilter* filter, const QString& fileName, const QStringList& path = QStringList{}) { 0047 QMultiHash<QStringList, QVector<QStringList>> leaves; 0048 if (node->childCount() > 0) { 0049 for (int i = 0; i < node->childCount(); ++i) 0050 leaves.unite(findLeaves(node->child(i), filter, fileName, path + QStringList(node->child(i)->text(0)))); 0051 } else { 0052 leaves.insert(path, filter->listLeaves(fileName, node->data(0, Qt::UserRole).toLongLong())); 0053 } 0054 return leaves; 0055 } 0056 0057 void ROOTOptionsWidget::updateContent(ROOTFilter* filter, const QString& fileName) { 0058 DEBUG(Q_FUNC_INFO); 0059 0060 qDeleteAll(histItem->takeChildren()); 0061 qDeleteAll(treeItem->takeChildren()); 0062 fillTree(histItem, filter->listHistograms(fileName)); 0063 fillTree(treeItem, filter->listTrees(fileName)); 0064 leaves = findLeaves(treeItem, filter, fileName); 0065 } 0066 0067 void ROOTOptionsWidget::rootObjectSelectionChanged() { 0068 DEBUG("rootObjectSelectionChanged()"); 0069 auto items = ui.twContent->selectedItems(); 0070 QDEBUG("SELECTED ITEMS =" << items); 0071 0072 ui.twColumns->clear(); 0073 0074 if (items.isEmpty()) { 0075 ui.twColumns->setHeaderHidden(true); 0076 return; 0077 } 0078 0079 QTreeWidgetItem* p = items.first(); 0080 QStringList path; 0081 while (p && p != histItem && p != treeItem) { 0082 path.prepend(p->text(0)); 0083 p = p->parent(); 0084 } 0085 0086 if (p == histItem) { 0087 ui.twColumns->setColumnCount(1); 0088 ui.twColumns->setHeaderHidden(false); 0089 ui.twColumns->setHeaderLabels(QStringList(i18n("Histogram Data"))); 0090 0091 auto center = new QTreeWidgetItem(ui.twColumns, QStringList(i18n("Bin Center"))); 0092 center->setData(0, Qt::UserRole, QStringList(QStringLiteral("center"))); 0093 center->setSelected(true); 0094 center->setFirstColumnSpanned(true); 0095 auto low = new QTreeWidgetItem(ui.twColumns, QStringList(i18n("Low Edge"))); 0096 low->setData(0, Qt::UserRole, QStringList(QStringLiteral("low"))); 0097 low->setFirstColumnSpanned(true); 0098 auto content = new QTreeWidgetItem(ui.twColumns, QStringList(i18n("Content"))); 0099 content->setData(0, Qt::UserRole, QStringList(QStringLiteral("content"))); 0100 content->setSelected(true); 0101 content->setFirstColumnSpanned(true); 0102 auto error = new QTreeWidgetItem(ui.twColumns, QStringList(i18n("Error"))); 0103 error->setData(0, Qt::UserRole, QStringList(QStringLiteral("error"))); 0104 error->setSelected(true); 0105 error->setFirstColumnSpanned(true); 0106 0107 if (!histselected) { 0108 histselected = true; 0109 ui.sbFirst->setMaximum(0); 0110 ui.sbLast->setMaximum(0); 0111 } 0112 } else if (p == treeItem) { 0113 ui.twColumns->setColumnCount(2); 0114 ui.twColumns->setHeaderHidden(false); 0115 ui.twColumns->setHeaderLabels(QStringList({i18n("Branch/Leaf"), i18n("Array Size")})); 0116 0117 auto it = leaves.find(path); 0118 if (it != leaves.end()) { 0119 for (const auto& l : it.value()) { 0120 auto leaf = new QTreeWidgetItem(ui.twColumns, l); 0121 bool ok = false; 0122 if (l.count() > 1) { 0123 QString index(l.back()); 0124 if (index.at(0) == QLatin1Char('[') && index.at(index.size() - 1) == QLatin1Char(']')) { 0125 size_t elements = index.mid(1, index.length() - 2).toUInt(&ok); 0126 if (ok) { 0127 leaf->setFlags(Qt::ItemIsEnabled); 0128 QStringList elname({l.at(l.count() - 2), QString()}); 0129 QStringList eldata(elname); 0130 if (l.count() > 2) 0131 eldata.prepend(l.front()); 0132 for (size_t i = 0; i < elements; ++i) { 0133 eldata.last() = elname.last() = QStringLiteral("[%1]").arg(i); 0134 auto el = new QTreeWidgetItem(leaf, elname); 0135 el->setData(0, Qt::UserRole, eldata); 0136 } 0137 } 0138 } 0139 } else 0140 leaf->setFirstColumnSpanned(true); 0141 0142 if (!ok) 0143 leaf->setData(0, Qt::UserRole, l); 0144 } 0145 0146 ui.twColumns->header()->setSectionResizeMode(QHeaderView::ResizeToContents); 0147 } 0148 0149 if (histselected) { 0150 histselected = false; 0151 ui.sbFirst->setMaximum(0); 0152 ui.sbLast->setMaximum(0); 0153 } 0154 } 0155 0156 m_fileWidget->refreshPreview(); 0157 } 0158 0159 const QStringList ROOTOptionsWidget::selectedNames() const { 0160 QStringList names; 0161 0162 for (QTreeWidgetItem* item : ui.twContent->selectedItems()) { 0163 QString path; 0164 while (item && item != histItem && item != treeItem) { 0165 path.prepend(QLatin1Char('/') + item->text(0)); 0166 item = item->parent(); 0167 } 0168 path[0] = QLatin1Char(':'); 0169 if (item == histItem) 0170 names << QStringLiteral("Hist") + path; 0171 else if (item == treeItem) 0172 names << QStringLiteral("Tree") + path; 0173 } 0174 0175 return names; 0176 } 0177 0178 QVector<QStringList> ROOTOptionsWidget::columns() const { 0179 QVector<QStringList> cols; 0180 0181 // ui.twColumns->selectedItems() returns the items in the order of selection. 0182 // Iterate through the tree to retain the displayed order. 0183 for (int t = 0; t < ui.twColumns->topLevelItemCount(); ++t) { 0184 auto titem = ui.twColumns->topLevelItem(t); 0185 if (titem->isSelected()) 0186 cols << titem->data(0, Qt::UserRole).toStringList(); 0187 for (int c = 0; c < titem->childCount(); ++c) { 0188 auto citem = titem->child(c); 0189 if (citem->isSelected()) 0190 cols << citem->data(0, Qt::UserRole).toStringList(); 0191 } 0192 } 0193 0194 return cols; 0195 } 0196 0197 void ROOTOptionsWidget::setNRows(int nrows) { 0198 // try to retain the range settings: 0199 // - if nrows was not 0, keep start row, 0200 // else set it to one after underflow 0201 // - if nrows didn't change, keep end row, 0202 // else set it to one before overflow 0203 const int max = std::max(nrows - 1, 0); 0204 int firstval = ui.sbFirst->value(); 0205 if (ui.sbFirst->maximum() == 0) 0206 firstval = std::min(nrows - 1, histselected ? 1 : 0); 0207 ui.sbFirst->setMaximum(max); 0208 ui.sbFirst->setValue(firstval); 0209 0210 int lastval = max == ui.sbLast->maximum() ? ui.sbLast->value() : std::max(max - (histselected ? 1 : 0), 0); 0211 ui.sbLast->setMaximum(max); 0212 ui.sbLast->setValue(lastval); 0213 }