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

0001 /***************************************************************************
0002 File                 : CursorDock.cpp
0003 Project              : LabPlot
0004 Description          : This dock represents the data from the cursors in the cartesian plots
0005 --------------------------------------------------------------------
0006 Copyright            : (C) 2019 Martin Marmsoler (martin.marmsoler@gmail.com)
0007 Copyright            : (C) 2019-2020 Alexander Semke (alexander.semke@web.de)
0008 
0009 ***************************************************************************/
0010 
0011 /***************************************************************************
0012 *                                                                         *
0013 *  This program is free software; you can redistribute it and/or modify   *
0014 *  it under the terms of the GNU General Public License as published by   *
0015 *  the Free Software Foundation; either version 2 of the License, or      *
0016 *  (at your option) any later version.                                    *
0017 *                                                                         *
0018 *  This program is distributed in the hope that it will be useful,        *
0019 *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
0020 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
0021 *  GNU General Public License for more details.                           *
0022 *                                                                         *
0023 *   You should have received a copy of the GNU General Public License     *
0024 *   along with this program; if not, write to the Free Software           *
0025 *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
0026 *   Boston, MA  02110-1301  USA                                           *
0027 *                                                                         *
0028 ***************************************************************************/
0029 
0030 #include "CursorDock.h"
0031 #include "ui_cursordock.h"
0032 #include "backend/worksheet/Worksheet.h"
0033 #include "backend/worksheet/WorksheetPrivate.h"
0034 #include "backend/worksheet/plots/cartesian/CartesianPlot.h"
0035 #include "backend/worksheet/plots/cartesian/XYCurve.h"
0036 #include "backend/worksheet/TreeModel.h"
0037 
0038 #include <QKeyEvent>
0039 #include <QMenu>
0040 #include <QClipboard>
0041 
0042 CursorDock::CursorDock(QWidget* parent) : QWidget(parent), ui(new Ui::CursorDock) {
0043     ui->setupUi(this);
0044     ui->tvCursorData->setModel(nullptr);
0045 
0046     ui->bCollapseAll->setIcon(QIcon::fromTheme(QLatin1String("collapse-all")));
0047     ui->bExpandAll->setIcon(QIcon::fromTheme(QLatin1String("expand-all")));
0048 
0049     ui->bCollapseAll->setToolTip(i18n("Collapse all curves"));
0050     ui->bExpandAll->setToolTip(i18n("Expand all curves"));
0051 
0052     connect(ui->bCollapseAll, &QPushButton::clicked, this, &CursorDock::collapseAll);
0053     connect(ui->bExpandAll, &QPushButton::clicked, this, &CursorDock::expandAll);
0054     connect(ui->cbCursor0en, &QCheckBox::clicked, this, &CursorDock::cursor0EnableChanged);
0055     connect(ui->cbCursor1en, &QCheckBox::clicked, this, &CursorDock::cursor1EnableChanged);
0056 
0057     //CTRL+C copies only the last cell in the selection, we want to copy the whole selection.
0058     //install event filters to handle CTRL+C key events.
0059     ui->tvCursorData->installEventFilter(this);
0060 
0061     ui->tvCursorData->setContextMenuPolicy(Qt::CustomContextMenu);
0062     connect(ui->tvCursorData, &QTreeView::customContextMenuRequested,
0063             this, &CursorDock::contextMenuRequested);
0064 }
0065 
0066 void CursorDock::setWorksheet(Worksheet* worksheet) {
0067     m_initializing = true;
0068 
0069     ui->tvCursorData->setModel(worksheet->cursorModel());
0070     ui->tvCursorData->resizeColumnToContents(0);
0071     m_plotList = worksheet->children<CartesianPlot>();
0072     if (m_plotList.isEmpty())
0073         return;
0074 
0075     m_plot = m_plotList.first();
0076 
0077     bool cursor0Enabled = m_plot->cursor0Enable();
0078     bool cursor1Enabled = m_plot->cursor1Enable();
0079     ui->cbCursor0en->setChecked(cursor0Enabled);
0080     ui->cbCursor1en->setChecked(cursor1Enabled);
0081 
0082     ui->tvCursorData->setColumnHidden(static_cast<int>(WorksheetPrivate::TreeModelColumn::CURSOR0), !cursor0Enabled);
0083     ui->tvCursorData->setColumnHidden(static_cast<int>(WorksheetPrivate::TreeModelColumn::CURSOR1), !cursor1Enabled);
0084     if (cursor0Enabled && cursor1Enabled)
0085         ui->tvCursorData->setColumnHidden(static_cast<int>(WorksheetPrivate::TreeModelColumn::CURSORDIFF), false);
0086     else
0087         ui->tvCursorData->setColumnHidden(static_cast<int>(WorksheetPrivate::TreeModelColumn::CURSORDIFF), true);
0088 
0089     ui->tvCursorData->expandAll();
0090 
0091     // connect all plots as a workaround to not be able to know which plot is selected
0092     for (auto connection: selectedPlotsConnection)
0093         disconnect(connection);
0094     for (auto* plot : m_plotList) {
0095         selectedPlotsConnection << connect(plot, &CartesianPlot::cursor0EnableChanged, this, &CursorDock::plotCursor0EnableChanged);
0096         selectedPlotsConnection << connect(plot, &CartesianPlot::cursor1EnableChanged, this, &CursorDock::plotCursor1EnableChanged);
0097     }
0098 
0099     m_initializing = false;
0100 }
0101 
0102 CursorDock::~CursorDock() {
0103     delete ui;
0104 }
0105 
0106 void CursorDock::collapseAll() {
0107     ui->tvCursorData->collapseAll();
0108 }
0109 
0110 void CursorDock::expandAll() {
0111     ui->tvCursorData->expandAll();
0112 }
0113 
0114 void CursorDock::cursor0EnableChanged(bool enable) {
0115     if (m_initializing)
0116         return;
0117 
0118     for (auto* plot : m_plotList)
0119         plot->setCursor0Enable(enable);
0120 }
0121 
0122 void CursorDock::cursor1EnableChanged(bool enable) {
0123     if (m_initializing)
0124         return;
0125 
0126     for (auto* plot : m_plotList)
0127         plot->setCursor1Enable(enable);
0128 }
0129 
0130 // #############################################################
0131 // back from plot
0132 // #############################################################
0133 void CursorDock::plotCursor0EnableChanged(bool enable) {
0134     m_initializing = true;
0135 
0136     ui->cbCursor0en->setChecked(enable);
0137     ui->tvCursorData->setColumnHidden(static_cast<int>(WorksheetPrivate::TreeModelColumn::CURSOR0), !enable);
0138     if (enable && ui->cbCursor1en->isChecked())
0139         ui->tvCursorData->setColumnHidden(static_cast<int>(WorksheetPrivate::TreeModelColumn::CURSORDIFF), false);
0140     else
0141         ui->tvCursorData->setColumnHidden(static_cast<int>(WorksheetPrivate::TreeModelColumn::CURSORDIFF), true);
0142 
0143     m_initializing = false;
0144 }
0145 
0146 void CursorDock::plotCursor1EnableChanged(bool enable) {
0147     m_initializing = true;
0148 
0149     ui->cbCursor1en->setChecked(enable);
0150     ui->tvCursorData->setColumnHidden(static_cast<int>(WorksheetPrivate::TreeModelColumn::CURSOR1), !enable);
0151     if (enable && ui->cbCursor0en->isChecked())
0152         ui->tvCursorData->setColumnHidden(static_cast<int>(WorksheetPrivate::TreeModelColumn::CURSORDIFF), false);
0153     else
0154         ui->tvCursorData->setColumnHidden(static_cast<int>(WorksheetPrivate::TreeModelColumn::CURSORDIFF), true);
0155 
0156     m_initializing = false;
0157 }
0158 
0159 bool CursorDock::eventFilter(QObject* obj, QEvent* event) {
0160     if (event->type() == QEvent::KeyPress && obj == ui->tvCursorData) {
0161         auto* key_event = static_cast<QKeyEvent*>(event);
0162         if (key_event->matches(QKeySequence::Copy)) {
0163             resultCopy();
0164             return true;
0165         }
0166     }
0167     return QWidget::eventFilter(obj, event);
0168 }
0169 
0170 void CursorDock::contextMenuRequested(QPoint pos) {
0171     auto* menu = new QMenu;
0172     menu->addAction(i18n("Copy Selection"), this, &CursorDock::resultCopy, QKeySequence::Copy);
0173     menu->addAction(i18n("Copy All"), this, &CursorDock::resultCopyAll);
0174     menu->exec(ui->tvCursorData->mapToGlobal(pos));
0175 }
0176 
0177 void CursorDock::resultCopy() {
0178     QString str;
0179     auto* model = ui->tvCursorData->model();
0180     auto* selection = ui->tvCursorData->selectionModel();
0181     const auto& indices = selection->selectedRows();
0182     for (auto index : indices) {
0183         int row = index.row();
0184         auto parent = index.parent();
0185         for (int col = 0; col < model->columnCount(); ++col) {
0186             if (col != 0)
0187                 str += QLatin1Char('\t');
0188             str += model->data(model->index(row, col, parent)).toString();
0189         }
0190 
0191         str += QLatin1Char('\n');
0192     }
0193 
0194     QApplication::clipboard()->setText(str);
0195 }
0196 
0197 void CursorDock::resultCopyAll() {
0198     QString str;
0199     auto* model = ui->tvCursorData->model();
0200     for (int row = 0; row < model->rowCount(); ++row) {
0201         for (int col = 0; col < model->columnCount(); ++col) {
0202             if (col != 0)
0203                 str += QLatin1Char('\t');
0204             str += model->data(model->index(row, col)).toString();
0205         }
0206 
0207         str += QLatin1Char('\n');
0208 
0209         //iterate over all children of the current row
0210         auto index = model->index(row, 0);
0211         for (int row = 0; row < model->rowCount(index); ++row) {
0212             for (int col = 0; col < model->columnCount(); ++col) {
0213                 if (col != 0)
0214                     str += QLatin1Char('\t');
0215                 str += model->data(model->index(row, col, index)).toString();
0216             }
0217 
0218             str += QLatin1Char('\n');
0219         }
0220     }
0221 
0222     QApplication::clipboard()->setText(str);
0223 }