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

0001 /*
0002     File             : XYFourierTransformCurveDock.cpp
0003     Project          : LabPlot
0004     Description      : widget for editing properties of Fourier transform curves
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2016-2021 Stefan Gerlach <stefan.gerlach@uni.kn>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "XYFourierTransformCurveDock.h"
0012 #include "backend/worksheet/plots/cartesian/XYFourierTransformCurve.h"
0013 #include "commonfrontend/widgets/TreeViewComboBox.h"
0014 
0015 /*!
0016   \class XYFourierTransformCurveDock
0017  \brief  Provides a widget for editing the properties of the XYFourierTransformCurves
0018         (2D-curves defined by a Fourier transform) currently selected in
0019         the project explorer.
0020 
0021   If more than one curves are set, the properties of the first column are shown.
0022   The changes of the properties are applied to all curves.
0023   The exclusions are the name, the comment and the datasets (columns) of
0024   the curves  - these properties can only be changed if there is only one single curve.
0025 
0026   \ingroup kdefrontend
0027 */
0028 
0029 XYFourierTransformCurveDock::XYFourierTransformCurveDock(QWidget* parent)
0030     : XYAnalysisCurveDock(parent) {
0031 }
0032 
0033 /*!
0034  *  // Tab "General"
0035  */
0036 void XYFourierTransformCurveDock::setupGeneral() {
0037     auto* generalTab = new QWidget(ui.tabGeneral);
0038     uiGeneralTab.setupUi(generalTab);
0039     setPlotRangeCombobox(uiGeneralTab.cbPlotRanges);
0040     setBaseWidgets(uiGeneralTab.leName, uiGeneralTab.teComment, uiGeneralTab.pbRecalculate);
0041     setVisibilityWidgets(uiGeneralTab.chkVisible, uiGeneralTab.chkLegendVisible);
0042 
0043     auto* gridLayout = static_cast<QGridLayout*>(generalTab->layout());
0044     gridLayout->setContentsMargins(2, 2, 2, 2);
0045     gridLayout->setHorizontalSpacing(2);
0046     gridLayout->setVerticalSpacing(2);
0047 
0048     cbXDataColumn = new TreeViewComboBox(generalTab);
0049     gridLayout->addWidget(cbXDataColumn, 5, 2, 1, 2);
0050     cbYDataColumn = new TreeViewComboBox(generalTab);
0051     gridLayout->addWidget(cbYDataColumn, 6, 2, 1, 2);
0052 
0053     for (int i = 0; i < NSL_SF_WINDOW_TYPE_COUNT; i++)
0054         uiGeneralTab.cbWindowType->addItem(i18n(nsl_sf_window_type_name[i]));
0055     for (int i = 0; i < NSL_DFT_RESULT_TYPE_COUNT; i++)
0056         uiGeneralTab.cbType->addItem(i18n(nsl_dft_result_type_name[i]));
0057     for (int i = 0; i < NSL_DFT_XSCALE_COUNT; i++)
0058         uiGeneralTab.cbXScale->addItem(i18n(nsl_dft_xscale_name[i]));
0059 
0060     uiGeneralTab.leMin->setValidator(new QDoubleValidator(uiGeneralTab.leMin));
0061     uiGeneralTab.leMax->setValidator(new QDoubleValidator(uiGeneralTab.leMax));
0062 
0063     auto* layout = new QHBoxLayout(ui.tabGeneral);
0064     layout->setContentsMargins(0, 0, 0, 0);
0065     layout->addWidget(generalTab);
0066 
0067     // Slots
0068     connect(uiGeneralTab.cbAutoRange, &QCheckBox::clicked, this, &XYFourierTransformCurveDock::autoRangeChanged);
0069     connect(uiGeneralTab.leMin, &QLineEdit::textChanged, this, &XYFourierTransformCurveDock::xRangeMinChanged);
0070     connect(uiGeneralTab.leMax, &QLineEdit::textChanged, this, &XYFourierTransformCurveDock::xRangeMaxChanged);
0071     connect(uiGeneralTab.cbWindowType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYFourierTransformCurveDock::windowTypeChanged);
0072     connect(uiGeneralTab.cbType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYFourierTransformCurveDock::typeChanged);
0073     connect(uiGeneralTab.cbTwoSided, &QCheckBox::toggled, this, &XYFourierTransformCurveDock::twoSidedChanged);
0074     connect(uiGeneralTab.cbShifted, &QCheckBox::toggled, this, &XYFourierTransformCurveDock::shiftedChanged);
0075     connect(uiGeneralTab.cbXScale, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYFourierTransformCurveDock::xScaleChanged);
0076     connect(uiGeneralTab.pbRecalculate, &QPushButton::clicked, this, &XYFourierTransformCurveDock::recalculateClicked);
0077 
0078     connect(cbXDataColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYFourierTransformCurveDock::xDataColumnChanged);
0079     connect(cbYDataColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYFourierTransformCurveDock::yDataColumnChanged);
0080 }
0081 
0082 void XYFourierTransformCurveDock::initGeneralTab() {
0083     // show the properties of the first curve
0084     cbXDataColumn->setColumn(m_transformCurve->xDataColumn(), m_transformCurve->xDataColumnPath());
0085     cbYDataColumn->setColumn(m_transformCurve->yDataColumn(), m_transformCurve->yDataColumnPath());
0086     uiGeneralTab.cbAutoRange->setChecked(m_transformData.autoRange);
0087     const auto numberLocale = QLocale();
0088     uiGeneralTab.leMin->setText(numberLocale.toString(m_transformData.xRange.first()));
0089     uiGeneralTab.leMax->setText(numberLocale.toString(m_transformData.xRange.last()));
0090     this->autoRangeChanged();
0091 
0092     uiGeneralTab.cbWindowType->setCurrentIndex(m_transformData.windowType);
0093     this->windowTypeChanged();
0094     uiGeneralTab.cbType->setCurrentIndex(m_transformData.type);
0095     this->typeChanged();
0096     uiGeneralTab.cbTwoSided->setChecked(m_transformData.twoSided);
0097     this->twoSidedChanged(); // show/hide shifted check box
0098     uiGeneralTab.cbShifted->setChecked(m_transformData.shifted);
0099     this->shiftedChanged();
0100     uiGeneralTab.cbXScale->setCurrentIndex(m_transformData.xScale);
0101     this->xScaleChanged();
0102     this->showTransformResult();
0103 
0104     // enable the "recalculate"-button if the source data was changed since the last transform
0105     uiGeneralTab.pbRecalculate->setEnabled(m_transformCurve->isSourceDataChangedSinceLastRecalc());
0106 
0107     uiGeneralTab.chkLegendVisible->setChecked(m_curve->legendVisible());
0108     uiGeneralTab.chkVisible->setChecked(m_curve->isVisible());
0109 
0110     // Slots
0111     connect(m_transformCurve, &XYFourierTransformCurve::xDataColumnChanged, this, &XYFourierTransformCurveDock::curveXDataColumnChanged);
0112     connect(m_transformCurve, &XYFourierTransformCurve::yDataColumnChanged, this, &XYFourierTransformCurveDock::curveYDataColumnChanged);
0113     connect(m_transformCurve, &XYFourierTransformCurve::transformDataChanged, this, &XYFourierTransformCurveDock::curveTransformDataChanged);
0114     connect(m_transformCurve, &XYFourierTransformCurve::sourceDataChanged, this, &XYFourierTransformCurveDock::enableRecalculate);
0115 }
0116 
0117 void XYFourierTransformCurveDock::setModel() {
0118     auto list = defaultColumnTopLevelClasses();
0119     list.append(AspectType::XYFitCurve);
0120 
0121     XYAnalysisCurveDock::setModel(list);
0122 }
0123 
0124 /*!
0125   sets the curves. The properties of the curves in the list \c list can be edited in this widget.
0126 */
0127 void XYFourierTransformCurveDock::setCurves(QList<XYCurve*> list) {
0128     CONDITIONAL_LOCK_RETURN;
0129     m_curvesList = list;
0130     m_curve = list.first();
0131     setAspects(list);
0132     setAnalysisCurves(list);
0133     m_transformCurve = static_cast<XYFourierTransformCurve*>(m_curve);
0134     this->setModel();
0135     m_transformData = m_transformCurve->transformData();
0136 
0137     initGeneralTab();
0138     initTabs();
0139     setSymbols(list);
0140 
0141     updatePlotRangeList();
0142 }
0143 
0144 //*************************************************************
0145 //**** SLOTs for changes triggered in XYFitCurveDock *****
0146 //*************************************************************
0147 void XYFourierTransformCurveDock::xDataColumnChanged(const QModelIndex& index) {
0148     CONDITIONAL_LOCK_RETURN;
0149 
0150     auto* column = static_cast<AbstractColumn*>(index.internalPointer());
0151 
0152     for (auto* curve : m_curvesList)
0153         static_cast<XYFourierTransformCurve*>(curve)->setXDataColumn(column);
0154 
0155     if (column) {
0156         if (uiGeneralTab.cbAutoRange->isChecked()) {
0157             const auto numberLocale = QLocale();
0158             uiGeneralTab.leMin->setText(numberLocale.toString(column->minimum()));
0159             uiGeneralTab.leMax->setText(numberLocale.toString(column->maximum()));
0160         }
0161     }
0162 
0163     enableRecalculate();
0164 }
0165 
0166 void XYFourierTransformCurveDock::autoRangeChanged() {
0167     bool autoRange = uiGeneralTab.cbAutoRange->isChecked();
0168     m_transformData.autoRange = autoRange;
0169 
0170     if (autoRange) {
0171         uiGeneralTab.lMin->setEnabled(false);
0172         uiGeneralTab.leMin->setEnabled(false);
0173         uiGeneralTab.lMax->setEnabled(false);
0174         uiGeneralTab.leMax->setEnabled(false);
0175         m_transformCurve = static_cast<XYFourierTransformCurve*>(m_curve);
0176         if (m_transformCurve->xDataColumn()) {
0177             const auto numberLocale = QLocale();
0178             uiGeneralTab.leMin->setText(numberLocale.toString(m_transformCurve->xDataColumn()->minimum()));
0179             uiGeneralTab.leMax->setText(numberLocale.toString(m_transformCurve->xDataColumn()->maximum()));
0180         }
0181     } else {
0182         uiGeneralTab.lMin->setEnabled(true);
0183         uiGeneralTab.leMin->setEnabled(true);
0184         uiGeneralTab.lMax->setEnabled(true);
0185         uiGeneralTab.leMax->setEnabled(true);
0186     }
0187 }
0188 void XYFourierTransformCurveDock::xRangeMinChanged() {
0189     SET_DOUBLE_FROM_LE_REC(m_transformData.xRange.first(), uiGeneralTab.leMin);
0190 }
0191 
0192 void XYFourierTransformCurveDock::xRangeMaxChanged() {
0193     SET_DOUBLE_FROM_LE_REC(m_transformData.xRange.last(), uiGeneralTab.leMax);
0194 }
0195 
0196 void XYFourierTransformCurveDock::windowTypeChanged() {
0197     auto windowType = (nsl_sf_window_type)uiGeneralTab.cbWindowType->currentIndex();
0198     m_transformData.windowType = windowType;
0199 
0200     enableRecalculate();
0201 }
0202 
0203 void XYFourierTransformCurveDock::typeChanged() {
0204     auto type = (nsl_dft_result_type)uiGeneralTab.cbType->currentIndex();
0205     m_transformData.type = type;
0206 
0207     enableRecalculate();
0208 }
0209 
0210 void XYFourierTransformCurveDock::twoSidedChanged() {
0211     bool checked = uiGeneralTab.cbTwoSided->isChecked();
0212     m_transformData.twoSided = checked;
0213 
0214     if (checked)
0215         uiGeneralTab.cbShifted->setEnabled(true);
0216     else {
0217         uiGeneralTab.cbShifted->setEnabled(false);
0218         uiGeneralTab.cbShifted->setChecked(false);
0219     }
0220 
0221     enableRecalculate();
0222 }
0223 
0224 void XYFourierTransformCurveDock::shiftedChanged() {
0225     bool checked = uiGeneralTab.cbShifted->isChecked();
0226     m_transformData.shifted = checked;
0227 
0228     enableRecalculate();
0229 }
0230 
0231 void XYFourierTransformCurveDock::xScaleChanged() {
0232     auto xScale = (nsl_dft_xscale)uiGeneralTab.cbXScale->currentIndex();
0233     m_transformData.xScale = xScale;
0234 
0235     enableRecalculate();
0236 }
0237 
0238 void XYFourierTransformCurveDock::recalculateClicked() {
0239     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
0240     for (auto* curve : m_curvesList)
0241         static_cast<XYFourierTransformCurve*>(curve)->setTransformData(m_transformData);
0242 
0243     uiGeneralTab.pbRecalculate->setEnabled(false);
0244     Q_EMIT info(i18n("Fourier transformation status: %1", m_transformCurve->result().status));
0245     QApplication::restoreOverrideCursor();
0246 }
0247 
0248 /*!
0249  * show the result and details of the transform
0250  */
0251 void XYFourierTransformCurveDock::showTransformResult() {
0252     showResult(m_transformCurve, uiGeneralTab.teResult);
0253 }
0254 
0255 //*************************************************************
0256 //*********** SLOTs for changes triggered in XYCurve **********
0257 //*************************************************************
0258 // General-Tab
0259 void XYFourierTransformCurveDock::curveTransformDataChanged(const XYFourierTransformCurve::TransformData& transformData) {
0260     CONDITIONAL_LOCK_RETURN;
0261     m_transformData = transformData;
0262     uiGeneralTab.cbType->setCurrentIndex(m_transformData.type);
0263     this->typeChanged();
0264 
0265     this->showTransformResult();
0266 }