File indexing completed on 2024-05-12 15:27:53

0001 /***************************************************************************
0002 File                 : ROOTOptionsWidget.cpp
0003 Project              : LabPlot
0004 Description          : widget providing options for the import of ROOT data
0005 --------------------------------------------------------------------
0006 Copyright            : (C) 2018 Christoph Roick (chrisito@gmx.de)
0007 ***************************************************************************/
0008 
0009 /***************************************************************************
0010  *                                                                         *
0011  *  This program is free software; you can redistribute it and/or modify   *
0012  *  it under the terms of the GNU General Public License as published by   *
0013  *  the Free Software Foundation; either version 2 of the License, or      *
0014  *  (at your option) any later version.                                    *
0015  *                                                                         *
0016  *  This program is distributed in the hope that it will be useful,        *
0017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
0018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
0019  *  GNU General Public License for more details.                           *
0020  *                                                                         *
0021  *   You should have received a copy of the GNU General Public License     *
0022  *   along with this program; if not, write to the Free Software           *
0023  *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
0024  *   Boston, MA  02110-1301  USA                                           *
0025  *                                                                         *
0026  ***************************************************************************/
0027 
0028 #include "ROOTOptionsWidget.h"
0029 #include "ImportFileWidget.h"
0030 
0031 #include "backend/datasources/filters/ROOTFilter.h"
0032 #include "backend/lib/macros.h"
0033 
0034 ROOTOptionsWidget::ROOTOptionsWidget(QWidget* parent, ImportFileWidget* fileWidget) : QWidget(parent), m_fileWidget(fileWidget) {
0035     ui.setupUi(parent);
0036     histItem = new QTreeWidgetItem(ui.twContent, QStringList(i18n("Histograms")));
0037     histItem->setFlags(Qt::ItemIsEnabled);
0038     treeItem = new QTreeWidgetItem(ui.twContent, QStringList(i18n("Trees and Tuples")));
0039     treeItem->setFlags(Qt::ItemIsEnabled);
0040 
0041     connect(ui.twContent, &QTreeWidget::itemSelectionChanged, this, &ROOTOptionsWidget::rootObjectSelectionChanged);
0042     connect(ui.bRefreshPreview, &QPushButton::clicked, fileWidget, &ImportFileWidget::refreshPreview);
0043 }
0044 
0045 void ROOTOptionsWidget::clear() {
0046     qDeleteAll(histItem->takeChildren());
0047     qDeleteAll(treeItem->takeChildren());
0048     ui.twPreview->clearContents();
0049 }
0050 
0051 void fillTree(QTreeWidgetItem* node, const ROOTFilter::Directory& dir)
0052 {
0053     node->setFlags(Qt::ItemIsEnabled);
0054     for (const ROOTFilter::Directory& child : dir.children)
0055         fillTree(new QTreeWidgetItem(node, QStringList(child.name)), child);
0056     for (const auto& content : dir.content)
0057         (new QTreeWidgetItem(node, QStringList(content.first)))->setData(0, Qt::UserRole, content.second);
0058 }
0059 
0060 QHash<QStringList, QVector<QStringList> > findLeaves(
0061     QTreeWidgetItem* node,
0062     ROOTFilter* filter,
0063     const QString& fileName, const QStringList& path = QStringList{}
0064 ) {
0065     QHash<QStringList, QVector<QStringList> > leaves;
0066     if (node->childCount() > 0) {
0067         for (int i = 0; i < node->childCount(); ++i)
0068             leaves.unite(findLeaves(node->child(i), filter, fileName, path + QStringList(node->child(i)->text(0))));
0069     } else {
0070         leaves[path] = filter->listLeaves(fileName, node->data(0, Qt::UserRole).toLongLong());
0071     }
0072     return leaves;
0073 }
0074 
0075 void ROOTOptionsWidget::updateContent(ROOTFilter* filter, const QString& fileName) {
0076     DEBUG("updateContent()");
0077 
0078     qDeleteAll(histItem->takeChildren());
0079     qDeleteAll(treeItem->takeChildren());
0080     fillTree(histItem, filter->listHistograms(fileName));
0081     fillTree(treeItem, filter->listTrees(fileName));
0082     leaves = findLeaves(treeItem, filter, fileName);
0083 }
0084 
0085 void ROOTOptionsWidget::rootObjectSelectionChanged() {
0086     DEBUG("rootObjectSelectionChanged()");
0087     auto items = ui.twContent->selectedItems();
0088     QDEBUG("SELECTED ITEMS =" << items);
0089 
0090     ui.twColumns->clear();
0091 
0092     if (items.isEmpty()) {
0093         ui.twColumns->setHeaderHidden(true);
0094         return;
0095     }
0096 
0097     QTreeWidgetItem* p = items.first();
0098     QStringList path;
0099     while (p && p != histItem && p != treeItem) {
0100         path.prepend(p->text(0));
0101         p = p->parent();
0102     }
0103 
0104     if (p == histItem) {
0105         ui.twColumns->setColumnCount(1);
0106         ui.twColumns->setHeaderHidden(false);
0107         ui.twColumns->setHeaderLabels(QStringList(i18n("Histogram Data")));
0108 
0109         auto center = new QTreeWidgetItem(ui.twColumns, QStringList(i18n("Bin Center")));
0110         center->setData(0, Qt::UserRole, QStringList(QStringLiteral("center")));
0111         center->setSelected(true);
0112         center->setFirstColumnSpanned(true);
0113         auto low = new QTreeWidgetItem(ui.twColumns, QStringList(i18n("Low Edge")));
0114         low->setData(0, Qt::UserRole, QStringList(QStringLiteral("low")));
0115         low->setFirstColumnSpanned(true);
0116         auto content = new QTreeWidgetItem(ui.twColumns, QStringList(i18n("Content")));
0117         content->setData(0, Qt::UserRole, QStringList(QStringLiteral("content")));
0118         content->setSelected(true);
0119         content->setFirstColumnSpanned(true);
0120         auto error = new QTreeWidgetItem(ui.twColumns, QStringList(i18n("Error")));
0121         error->setData(0, Qt::UserRole, QStringList(QStringLiteral("error")));
0122         error->setSelected(true);
0123         error->setFirstColumnSpanned(true);
0124 
0125         if (!histselected) {
0126             histselected = true;
0127             ui.sbFirst->setMaximum(0);
0128             ui.sbLast->setMaximum(0);
0129         }
0130     } else if (p == treeItem) {
0131         ui.twColumns->setColumnCount(2);
0132         ui.twColumns->setHeaderHidden(false);
0133         ui.twColumns->setHeaderLabels(QStringList({i18n("Branch/Leaf"), i18n("Array Size")}));
0134 
0135         auto it = leaves.find(path);
0136         if (it != leaves.end()) {
0137             for (const auto& l : it.value()) {
0138                 auto leaf = new QTreeWidgetItem(ui.twColumns, l);
0139                 bool ok = false;
0140                 if (l.count() > 1) {
0141                     QString index(l.back());
0142                     if (index.at(0) == '[' && index.at(index.size() - 1) == ']') {
0143                         size_t elements = index.midRef(1, index.length() - 2).toUInt(&ok);
0144                         if (ok) {
0145                             leaf->setFlags(Qt::ItemIsEnabled);
0146                             QStringList elname({l.at(l.count() - 2), QString()});
0147                             QStringList eldata(elname);
0148                             if (l.count() > 2)
0149                                 eldata.prepend(l.front());
0150                             for (size_t i = 0; i < elements; ++i) {
0151                                 eldata.last() = elname.last() = QString("[%1]").arg(i);
0152                                 auto el = new QTreeWidgetItem(leaf, elname);
0153                                 el->setData(0, Qt::UserRole, eldata);
0154                             }
0155                         }
0156                     }
0157                 } else
0158                     leaf->setFirstColumnSpanned(true);
0159 
0160                 if (!ok)
0161                     leaf->setData(0, Qt::UserRole, l);
0162             }
0163 
0164             ui.twColumns->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
0165         }
0166 
0167         if (histselected) {
0168             histselected = false;
0169             ui.sbFirst->setMaximum(0);
0170             ui.sbLast->setMaximum(0);
0171         }
0172     }
0173 
0174     m_fileWidget->refreshPreview();
0175 }
0176 
0177 const QStringList ROOTOptionsWidget::selectedNames() const {
0178     QStringList names;
0179 
0180     for (QTreeWidgetItem* item : ui.twContent->selectedItems()) {
0181         QString path;
0182         while (item && item != histItem && item != treeItem) {
0183             path.prepend('/' + item->text(0));
0184             item = item->parent();
0185         }
0186         path[0] = ':';
0187         if (item == histItem)
0188             names << QStringLiteral("Hist") + path;
0189         else if (item == treeItem)
0190             names << QStringLiteral("Tree") + path;
0191     }
0192 
0193     return names;
0194 }
0195 
0196 QVector<QStringList> ROOTOptionsWidget::columns() const {
0197     QVector<QStringList> cols;
0198 
0199     // ui.twColumns->selectedItems() returns the items in the order of selection.
0200     // Iterate through the tree to retain the displayed order.
0201     for (int t = 0; t < ui.twColumns->topLevelItemCount(); ++t) {
0202         auto titem = ui.twColumns->topLevelItem(t);
0203         if (titem->isSelected())
0204             cols << titem->data(0, Qt::UserRole).toStringList();
0205         for (int c = 0; c < titem->childCount(); ++c) {
0206             auto citem = titem->child(c);
0207             if (citem->isSelected())
0208                 cols << citem->data(0, Qt::UserRole).toStringList();
0209         }
0210     }
0211 
0212     return cols;
0213 }
0214 
0215 void ROOTOptionsWidget::setNRows(int nrows) {
0216     // try to retain the range settings:
0217     // - if nrows was not 0, keep start row,
0218     //   else set it to one after underflow
0219     // - if nrows didn't change, keep end row,
0220     //   else set it to one before overflow
0221     const int max = qMax(nrows - 1, 0);
0222     int firstval = ui.sbFirst->value();
0223     if (ui.sbFirst->maximum() == 0)
0224         firstval = qMin(nrows - 1, histselected ? 1 : 0);
0225     ui.sbFirst->setMaximum(max);
0226     ui.sbFirst->setValue(firstval);
0227 
0228     int lastval = max == ui.sbLast->maximum() ? ui.sbLast->value()
0229                                               : qMax(max - (histselected ? 1 : 0), 0);
0230     ui.sbLast->setMaximum(max);
0231     ui.sbLast->setValue(lastval);
0232 }