File indexing completed on 2025-07-13 03:32:47

0001 /*
0002     File             : XYCorrelationCurveDock.cpp
0003     Project          : LabPlot
0004     Description      : widget for editing properties of correlation curves
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2018-2021 Stefan Gerlach <stefan.gerlach@uni.kn>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "XYCorrelationCurveDock.h"
0012 #include "backend/worksheet/plots/cartesian/XYCorrelationCurve.h"
0013 #include "commonfrontend/widgets/TreeViewComboBox.h"
0014 
0015 #include <KConfigGroup>
0016 
0017 #include <QMenu>
0018 #include <QWidgetAction>
0019 
0020 extern "C" {
0021 #include "backend/nsl/nsl_corr.h"
0022 }
0023 
0024 /*!
0025   \class XYCorrelationCurveDock
0026  \brief  Provides a widget for editing the properties of the XYCorrelationCurves
0027         (2D-curves defined by a correlation) currently selected in
0028         the project explorer.
0029 
0030   If more than one curves are set, the properties of the first column are shown.
0031   The changes of the properties are applied to all curves.
0032   The exclusions are the name, the comment and the datasets (columns) of
0033   the curves  - these properties can only be changed if there is only one single curve.
0034 
0035   \ingroup kdefrontend
0036 */
0037 
0038 XYCorrelationCurveDock::XYCorrelationCurveDock(QWidget* parent)
0039     : XYAnalysisCurveDock(parent, XYAnalysisCurveDock::RequiredDataSource::YY2) {
0040 }
0041 
0042 /*!
0043  *  // Tab "General"
0044  */
0045 void XYCorrelationCurveDock::setupGeneral() {
0046     auto* generalTab = new QWidget(ui.tabGeneral);
0047     uiGeneralTab.setupUi(generalTab);
0048     setPlotRangeCombobox(uiGeneralTab.cbPlotRanges);
0049     setBaseWidgets(uiGeneralTab.leName, uiGeneralTab.teComment, uiGeneralTab.pbRecalculate, uiGeneralTab.cbDataSourceType);
0050     setVisibilityWidgets(uiGeneralTab.chkVisible, uiGeneralTab.chkLegendVisible);
0051 
0052     auto* gridLayout = static_cast<QGridLayout*>(generalTab->layout());
0053     gridLayout->setContentsMargins(2, 2, 2, 2);
0054     gridLayout->setHorizontalSpacing(2);
0055     gridLayout->setVerticalSpacing(2);
0056 
0057     cbDataSourceCurve = new TreeViewComboBox(generalTab);
0058     gridLayout->addWidget(cbDataSourceCurve, 5, 2, 1, 3);
0059     cbXDataColumn = new TreeViewComboBox(generalTab);
0060     gridLayout->addWidget(cbXDataColumn, 6, 2, 1, 3);
0061     cbYDataColumn = new TreeViewComboBox(generalTab);
0062     gridLayout->addWidget(cbYDataColumn, 8, 2, 1, 3);
0063     cbY2DataColumn = new TreeViewComboBox(generalTab);
0064     gridLayout->addWidget(cbY2DataColumn, 9, 2, 1, 3);
0065 
0066     uiGeneralTab.leMin->setValidator(new QDoubleValidator(uiGeneralTab.leMin));
0067     uiGeneralTab.leMax->setValidator(new QDoubleValidator(uiGeneralTab.leMax));
0068 
0069     for (int i = 0; i < NSL_CORR_TYPE_COUNT; i++)
0070         uiGeneralTab.cbType->addItem(i18n(nsl_corr_type_name[i]));
0071     // nsl_corr_method_type not exposed to user
0072     for (int i = 0; i < NSL_CORR_NORM_COUNT; i++)
0073         uiGeneralTab.cbNorm->addItem(i18n(nsl_corr_norm_name[i]));
0074 
0075     auto* layout = new QHBoxLayout(ui.tabGeneral);
0076     layout->setContentsMargins(0, 0, 0, 0);
0077     layout->addWidget(generalTab);
0078 
0079     DEBUG("XYCorrelationCurveDock::setupGeneral() DONE");
0080 
0081     // Slots
0082     connect(uiGeneralTab.cbDataSourceType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYCorrelationCurveDock::dataSourceTypeChanged);
0083     connect(uiGeneralTab.sbSamplingInterval, QOverload<double>::of(&NumberSpinBox::valueChanged), this, &XYCorrelationCurveDock::samplingIntervalChanged);
0084     connect(uiGeneralTab.cbAutoRange, &QCheckBox::clicked, this, &XYCorrelationCurveDock::autoRangeChanged);
0085     connect(uiGeneralTab.leMin, &QLineEdit::textChanged, this, &XYCorrelationCurveDock::xRangeMinChanged);
0086     connect(uiGeneralTab.leMax, &QLineEdit::textChanged, this, &XYCorrelationCurveDock::xRangeMaxChanged);
0087     connect(uiGeneralTab.cbType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYCorrelationCurveDock::typeChanged);
0088     connect(uiGeneralTab.cbNorm, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYCorrelationCurveDock::normChanged);
0089     connect(uiGeneralTab.pbRecalculate, &QPushButton::clicked, this, &XYCorrelationCurveDock::recalculateClicked);
0090     connect(uiGeneralTab.cbPlotRanges, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYCorrelationCurveDock::plotRangeChanged);
0091 
0092     connect(cbDataSourceCurve, &TreeViewComboBox::currentModelIndexChanged, this, &XYCorrelationCurveDock::dataSourceCurveChanged);
0093     connect(cbXDataColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYCorrelationCurveDock::xDataColumnChanged);
0094     connect(cbYDataColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYCorrelationCurveDock::yDataColumnChanged);
0095     connect(cbY2DataColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYCorrelationCurveDock::y2DataColumnChanged);
0096 }
0097 
0098 void XYCorrelationCurveDock::initGeneralTab() {
0099     // show the properties of the first curve
0100     //  hide x-Range per default
0101     uiGeneralTab.lXRange->setEnabled(false);
0102     uiGeneralTab.cbAutoRange->setEnabled(false);
0103 
0104     uiGeneralTab.cbDataSourceType->setCurrentIndex(static_cast<int>(m_correlationCurve->dataSourceType()));
0105     this->dataSourceTypeChanged(uiGeneralTab.cbDataSourceType->currentIndex());
0106     cbDataSourceCurve->setAspect(m_correlationCurve->dataSourceCurve());
0107     cbXDataColumn->setColumn(m_correlationCurve->xDataColumn(), m_correlationCurve->xDataColumnPath());
0108     cbYDataColumn->setColumn(m_correlationCurve->yDataColumn(), m_correlationCurve->yDataColumnPath());
0109     cbY2DataColumn->setColumn(m_correlationCurve->y2DataColumn(), m_correlationCurve->y2DataColumnPath());
0110     uiGeneralTab.sbSamplingInterval->setValue(m_correlationData.samplingInterval);
0111     uiGeneralTab.cbAutoRange->setChecked(m_correlationData.autoRange);
0112 
0113     const auto numberLocale = QLocale();
0114     uiGeneralTab.leMin->setText(numberLocale.toString(m_correlationData.xRange.first()));
0115     uiGeneralTab.leMax->setText(numberLocale.toString(m_correlationData.xRange.last()));
0116     this->autoRangeChanged();
0117     y2DataColumnChanged(cbY2DataColumn->currentModelIndex());
0118 
0119     // settings
0120     uiGeneralTab.cbType->setCurrentIndex(m_correlationData.type);
0121     // m_correlationData.method not used
0122     uiGeneralTab.cbNorm->setCurrentIndex(m_correlationData.normalize);
0123 
0124     this->showCorrelationResult();
0125 
0126     uiGeneralTab.chkLegendVisible->setChecked(m_curve->legendVisible());
0127     uiGeneralTab.chkVisible->setChecked(m_curve->isVisible());
0128 
0129     // Slots
0130     connect(m_correlationCurve, &XYCorrelationCurve::dataSourceTypeChanged, this, &XYCorrelationCurveDock::curveDataSourceTypeChanged);
0131     connect(m_correlationCurve, &XYCorrelationCurve::dataSourceCurveChanged, this, &XYCorrelationCurveDock::curveDataSourceCurveChanged);
0132     connect(m_correlationCurve, &XYCorrelationCurve::xDataColumnChanged, this, &XYCorrelationCurveDock::curveXDataColumnChanged);
0133     connect(m_correlationCurve, &XYCorrelationCurve::yDataColumnChanged, this, &XYCorrelationCurveDock::curveYDataColumnChanged);
0134     connect(m_correlationCurve, &XYCorrelationCurve::y2DataColumnChanged, this, &XYCorrelationCurveDock::curveY2DataColumnChanged);
0135     connect(m_correlationCurve, &XYCorrelationCurve::correlationDataChanged, this, &XYCorrelationCurveDock::curveCorrelationDataChanged);
0136     connect(m_correlationCurve, &XYCorrelationCurve::sourceDataChanged, this, &XYCorrelationCurveDock::enableRecalculate);
0137 }
0138 
0139 void XYCorrelationCurveDock::setModel() {
0140     auto list = defaultColumnTopLevelClasses();
0141     list.append(AspectType::XYCorrelationCurve);
0142 
0143     XYAnalysisCurveDock::setModel(list);
0144 }
0145 
0146 /*!
0147   sets the curves. The properties of the curves in the list \c list can be edited in this widget.
0148 */
0149 void XYCorrelationCurveDock::setCurves(QList<XYCurve*> list) {
0150     CONDITIONAL_LOCK_RETURN;
0151     m_curvesList = list;
0152     m_curve = list.first();
0153     setAspects(list);
0154     setAnalysisCurves(list);
0155     m_correlationCurve = static_cast<XYCorrelationCurve*>(m_curve);
0156     this->setModel();
0157     m_correlationData = m_correlationCurve->correlationData();
0158 
0159     const auto numberLocale = QLocale();
0160     uiGeneralTab.sbSamplingInterval->setLocale(numberLocale);
0161 
0162     initGeneralTab();
0163     initTabs();
0164     setSymbols(list);
0165 
0166     updatePlotRangeList();
0167 }
0168 
0169 //*************************************************************
0170 //**** SLOTs for changes triggered in XYCorrelationCurveDock **
0171 //*************************************************************
0172 void XYCorrelationCurveDock::dataSourceTypeChanged(int index) {
0173     auto type = (XYAnalysisCurve::DataSourceType)index;
0174     if (type == XYAnalysisCurve::DataSourceType::Spreadsheet) {
0175         uiGeneralTab.lDataSourceCurve->hide();
0176         cbDataSourceCurve->hide();
0177         uiGeneralTab.lXColumn->show();
0178         cbXDataColumn->show();
0179         uiGeneralTab.lYColumn->show();
0180         cbYDataColumn->show();
0181         uiGeneralTab.lY2Column->show();
0182         cbY2DataColumn->show();
0183         uiGeneralTab.lSamplingInterval->show();
0184         uiGeneralTab.l2SamplingInterval->show();
0185         uiGeneralTab.sbSamplingInterval->show();
0186     } else {
0187         uiGeneralTab.lDataSourceCurve->show();
0188         cbDataSourceCurve->show();
0189         uiGeneralTab.lXColumn->hide();
0190         cbXDataColumn->hide();
0191         uiGeneralTab.lYColumn->hide();
0192         cbYDataColumn->hide();
0193         uiGeneralTab.lY2Column->hide();
0194         cbY2DataColumn->hide();
0195         uiGeneralTab.lSamplingInterval->hide();
0196         uiGeneralTab.l2SamplingInterval->hide();
0197         uiGeneralTab.sbSamplingInterval->hide();
0198     }
0199 
0200     CONDITIONAL_LOCK_RETURN;
0201 
0202     for (auto* curve : m_curvesList)
0203         static_cast<XYCorrelationCurve*>(curve)->setDataSourceType(type);
0204 
0205     enableRecalculate();
0206 }
0207 
0208 void XYCorrelationCurveDock::xDataColumnChanged(const QModelIndex& index) {
0209     CONDITIONAL_LOCK_RETURN;
0210 
0211     auto* column = static_cast<AbstractColumn*>(index.internalPointer());
0212     for (auto* curve : m_curvesList)
0213         static_cast<XYCorrelationCurve*>(curve)->setXDataColumn(column);
0214 
0215     if (column && uiGeneralTab.cbAutoRange->isChecked()) {
0216         const auto numberLocale = QLocale();
0217         uiGeneralTab.leMin->setText(numberLocale.toString(column->minimum()));
0218         uiGeneralTab.leMax->setText(numberLocale.toString(column->maximum()));
0219     }
0220 
0221     enableRecalculate();
0222 }
0223 
0224 void XYCorrelationCurveDock::samplingIntervalChanged() {
0225     double samplingInterval = uiGeneralTab.sbSamplingInterval->value();
0226     m_correlationData.samplingInterval = samplingInterval;
0227 
0228     enableRecalculate();
0229 }
0230 
0231 void XYCorrelationCurveDock::autoRangeChanged() {
0232     bool autoRange = uiGeneralTab.cbAutoRange->isChecked();
0233     m_correlationData.autoRange = autoRange;
0234 
0235     if (autoRange) {
0236         uiGeneralTab.lMin->setEnabled(false);
0237         uiGeneralTab.leMin->setEnabled(false);
0238         uiGeneralTab.lMax->setEnabled(false);
0239         uiGeneralTab.leMax->setEnabled(false);
0240 
0241         const AbstractColumn* xDataColumn = nullptr;
0242         if (m_correlationCurve->dataSourceType() == XYAnalysisCurve::DataSourceType::Spreadsheet)
0243             xDataColumn = m_correlationCurve->xDataColumn();
0244         else {
0245             if (m_correlationCurve->dataSourceCurve())
0246                 xDataColumn = m_correlationCurve->dataSourceCurve()->xColumn();
0247         }
0248 
0249         if (xDataColumn) {
0250             const auto numberLocale = QLocale();
0251             uiGeneralTab.leMin->setText(numberLocale.toString(xDataColumn->minimum()));
0252             uiGeneralTab.leMax->setText(numberLocale.toString(xDataColumn->maximum()));
0253         }
0254     } else {
0255         uiGeneralTab.lMin->setEnabled(true);
0256         uiGeneralTab.leMin->setEnabled(true);
0257         uiGeneralTab.lMax->setEnabled(true);
0258         uiGeneralTab.leMax->setEnabled(true);
0259     }
0260 }
0261 void XYCorrelationCurveDock::xRangeMinChanged() {
0262     SET_DOUBLE_FROM_LE_REC(m_correlationData.xRange.first(), uiGeneralTab.leMin);
0263 }
0264 
0265 void XYCorrelationCurveDock::xRangeMaxChanged() {
0266     SET_DOUBLE_FROM_LE_REC(m_correlationData.xRange.last(), uiGeneralTab.leMax);
0267 }
0268 
0269 void XYCorrelationCurveDock::typeChanged() {
0270     auto type = (nsl_corr_type_type)uiGeneralTab.cbType->currentIndex();
0271     m_correlationData.type = type;
0272 
0273     enableRecalculate();
0274 }
0275 
0276 void XYCorrelationCurveDock::normChanged() {
0277     auto norm = (nsl_corr_norm_type)uiGeneralTab.cbNorm->currentIndex();
0278     m_correlationData.normalize = norm;
0279 
0280     enableRecalculate();
0281 }
0282 
0283 void XYCorrelationCurveDock::recalculateClicked() {
0284     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
0285 
0286     for (auto* curve : m_curvesList)
0287         static_cast<XYCorrelationCurve*>(curve)->setCorrelationData(m_correlationData);
0288 
0289     uiGeneralTab.pbRecalculate->setEnabled(false);
0290     Q_EMIT info(i18n("Correlation status: %1", m_correlationCurve->correlationResult().status));
0291     QApplication::restoreOverrideCursor();
0292 }
0293 
0294 /*!
0295  * show the result and details of the correlation
0296  */
0297 void XYCorrelationCurveDock::showCorrelationResult() {
0298     showResult(m_correlationCurve, uiGeneralTab.teResult);
0299 }
0300 
0301 //*************************************************************
0302 //*********** SLOTs for changes triggered in XYCurve **********
0303 //*************************************************************
0304 // General-Tab
0305 void XYCorrelationCurveDock::curveXDataColumnChanged(const AbstractColumn* column) {
0306     DEBUG("XYCorrelationCurveDock::curveXDataColumnChanged()");
0307     if (column) {
0308         DEBUG("X Column available");
0309         uiGeneralTab.lXRange->setEnabled(true);
0310         uiGeneralTab.cbAutoRange->setEnabled(true);
0311         uiGeneralTab.lSamplingInterval->setEnabled(false);
0312         uiGeneralTab.l2SamplingInterval->setEnabled(false);
0313         uiGeneralTab.sbSamplingInterval->setEnabled(false);
0314     } else {
0315         DEBUG("X Column not available");
0316         uiGeneralTab.lXRange->setEnabled(false);
0317         uiGeneralTab.cbAutoRange->setEnabled(false);
0318         uiGeneralTab.lSamplingInterval->setEnabled(true);
0319         uiGeneralTab.l2SamplingInterval->setEnabled(true);
0320         uiGeneralTab.sbSamplingInterval->setEnabled(true);
0321     }
0322     CONDITIONAL_LOCK_RETURN;
0323     cbXDataColumn->setColumn(column, m_correlationCurve->xDataColumnPath());
0324     enableRecalculate();
0325 }
0326 
0327 void XYCorrelationCurveDock::curveY2DataColumnChanged(const AbstractColumn* column) {
0328     CONDITIONAL_LOCK_RETURN;
0329     cbY2DataColumn->setColumn(column, m_correlationCurve->y2DataColumnPath());
0330     enableRecalculate();
0331 }
0332 
0333 void XYCorrelationCurveDock::curveCorrelationDataChanged(const XYCorrelationCurve::CorrelationData& correlationData) {
0334     CONDITIONAL_LOCK_RETURN;
0335     m_correlationData = correlationData;
0336 
0337     this->showCorrelationResult();
0338 }