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 }