File indexing completed on 2024-05-12 15:28:02

0001 /***************************************************************************
0002     File             : XYConvolutionCurveDock.cpp
0003     Project          : LabPlot
0004     --------------------------------------------------------------------
0005     Copyright        : (C) 2018 Stefan Gerlach (stefan.gerlach@uni.kn)
0006     Description      : widget for editing properties of convolution curves
0007 
0008  ***************************************************************************/
0009 
0010 /***************************************************************************
0011  *                                                                         *
0012  *  This program is free software; you can redistribute it and/or modify   *
0013  *  it under the terms of the GNU General Public License as published by   *
0014  *  the Free Software Foundation; either version 2 of the License, or      *
0015  *  (at your option) any later version.                                    *
0016  *                                                                         *
0017  *  This program is distributed in the hope that it will be useful,        *
0018  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
0019  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
0020  *  GNU General Public License for more details.                           *
0021  *                                                                         *
0022  *   You should have received a copy of the GNU General Public License     *
0023  *   along with this program; if not, write to the Free Software           *
0024  *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
0025  *   Boston, MA  02110-1301  USA                                           *
0026  *                                                                         *
0027  ***************************************************************************/
0028 
0029 #include "XYConvolutionCurveDock.h"
0030 #include "backend/core/AspectTreeModel.h"
0031 #include "backend/core/Project.h"
0032 #include "backend/worksheet/plots/cartesian/XYConvolutionCurve.h"
0033 #include "commonfrontend/widgets/TreeViewComboBox.h"
0034 
0035 #include <QMenu>
0036 #include <QWidgetAction>
0037 #include <QStandardItemModel>
0038 
0039 extern "C" {
0040 #include "backend/nsl/nsl_conv.h"
0041 }
0042 
0043 /*!
0044   \class XYConvolutionCurveDock
0045  \brief  Provides a widget for editing the properties of the XYConvolutionCurves
0046         (2D-curves defined by a convolution) currently selected in
0047         the project explorer.
0048 
0049   If more then one curves are set, the properties of the first column are shown.
0050   The changes of the properties are applied to all curves.
0051   The exclusions are the name, the comment and the datasets (columns) of
0052   the curves  - these properties can only be changed if there is only one single curve.
0053 
0054   \ingroup kdefrontend
0055 */
0056 
0057 XYConvolutionCurveDock::XYConvolutionCurveDock(QWidget* parent) : XYCurveDock(parent) {
0058 }
0059 
0060 /*!
0061  *  // Tab "General"
0062  */
0063 void XYConvolutionCurveDock::setupGeneral() {
0064     DEBUG("XYConvolutionCurveDock::setupGeneral()");
0065     QWidget* generalTab = new QWidget(ui.tabGeneral);
0066     uiGeneralTab.setupUi(generalTab);
0067     m_leName = uiGeneralTab.leName;
0068     m_leComment = uiGeneralTab.leComment;
0069 
0070     auto* gridLayout = static_cast<QGridLayout*>(generalTab->layout());
0071     gridLayout->setContentsMargins(2,2,2,2);
0072     gridLayout->setHorizontalSpacing(2);
0073     gridLayout->setVerticalSpacing(2);
0074 
0075     uiGeneralTab.cbDataSourceType->addItem(i18n("Spreadsheet"));
0076     uiGeneralTab.cbDataSourceType->addItem(i18n("XY-Curve"));
0077 
0078     cbDataSourceCurve = new TreeViewComboBox(generalTab);
0079     gridLayout->addWidget(cbDataSourceCurve, 5, 2, 1, 3);
0080     cbXDataColumn = new TreeViewComboBox(generalTab);
0081     gridLayout->addWidget(cbXDataColumn, 6, 2, 1, 3);
0082     cbYDataColumn = new TreeViewComboBox(generalTab);
0083     gridLayout->addWidget(cbYDataColumn, 8, 2, 1, 3);
0084     cbY2DataColumn = new TreeViewComboBox(generalTab);
0085     gridLayout->addWidget(cbY2DataColumn, 9, 2, 1, 3);
0086 
0087     for (int i = 0; i < NSL_CONV_KERNEL_COUNT; i++)
0088         uiGeneralTab.cbKernel->addItem(i18n(nsl_conv_kernel_name[i]));
0089 
0090     uiGeneralTab.sbMin->setRange(-std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
0091     uiGeneralTab.sbMax->setRange(-std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
0092 
0093     for (int i = 0; i < NSL_CONV_DIRECTION_COUNT; i++)
0094         uiGeneralTab.cbDirection->addItem(i18n(nsl_conv_direction_name[i]));
0095     for (int i = 0; i < NSL_CONV_TYPE_COUNT; i++)
0096         uiGeneralTab.cbType->addItem(i18n(nsl_conv_type_name[i]));
0097     // nsl_conv_method_type not exposed to user
0098     for (int i = 0; i < NSL_CONV_NORM_COUNT; i++)
0099         uiGeneralTab.cbNorm->addItem(i18n(nsl_conv_norm_name[i]));
0100     for (int i = 0; i < NSL_CONV_WRAP_COUNT; i++)
0101         uiGeneralTab.cbWrap->addItem(i18n(nsl_conv_wrap_name[i]));
0102 
0103     uiGeneralTab.pbRecalculate->setIcon(QIcon::fromTheme("run-build"));
0104 
0105     auto* layout = new QHBoxLayout(ui.tabGeneral);
0106     layout->setMargin(0);
0107     layout->addWidget(generalTab);
0108 
0109     DEBUG("XYConvolutionCurveDock::setupGeneral() DONE");
0110 
0111     //Slots
0112     connect(uiGeneralTab.leName, &QLineEdit::textChanged, this, &XYConvolutionCurveDock::nameChanged );
0113     connect(uiGeneralTab.leComment, &QLineEdit::textChanged, this, &XYConvolutionCurveDock::commentChanged );
0114     connect(uiGeneralTab.chkVisible, &QCheckBox::clicked, this, &XYConvolutionCurveDock::visibilityChanged);
0115     connect(uiGeneralTab.cbDataSourceType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYConvolutionCurveDock::dataSourceTypeChanged);
0116     connect(uiGeneralTab.sbSamplingInterval, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &XYConvolutionCurveDock::samplingIntervalChanged);
0117     connect(uiGeneralTab.cbKernel, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYConvolutionCurveDock::kernelChanged);
0118     connect(uiGeneralTab.sbKernelSize, QOverload<int>::of(&QSpinBox::valueChanged), this, &XYConvolutionCurveDock::kernelSizeChanged);
0119     connect(uiGeneralTab.cbAutoRange, &QCheckBox::clicked, this, &XYConvolutionCurveDock::autoRangeChanged);
0120     connect(uiGeneralTab.sbMin, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &XYConvolutionCurveDock::xRangeMinChanged);
0121     connect(uiGeneralTab.sbMax, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &XYConvolutionCurveDock::xRangeMaxChanged);
0122     connect(uiGeneralTab.cbDirection, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYConvolutionCurveDock::directionChanged);
0123     connect(uiGeneralTab.cbType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYConvolutionCurveDock::typeChanged);
0124     connect(uiGeneralTab.cbNorm, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYConvolutionCurveDock::normChanged);
0125     connect(uiGeneralTab.cbWrap, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYConvolutionCurveDock::wrapChanged);
0126     connect(uiGeneralTab.pbRecalculate, &QPushButton::clicked, this, &XYConvolutionCurveDock::recalculateClicked);
0127 
0128     connect(cbDataSourceCurve, &TreeViewComboBox::currentModelIndexChanged, this, &XYConvolutionCurveDock::dataSourceCurveChanged);
0129     connect(cbXDataColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYConvolutionCurveDock::xDataColumnChanged);
0130     connect(cbYDataColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYConvolutionCurveDock::yDataColumnChanged);
0131     connect(cbY2DataColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYConvolutionCurveDock::y2DataColumnChanged);
0132 }
0133 
0134 void XYConvolutionCurveDock::initGeneralTab() {
0135     DEBUG("XYConvolutionCurveDock::initGeneralTab()");
0136     //if there are more then one curve in the list, disable the tab "general"
0137     if (m_curvesList.size() == 1) {
0138         uiGeneralTab.lName->setEnabled(true);
0139         uiGeneralTab.leName->setEnabled(true);
0140         uiGeneralTab.lComment->setEnabled(true);
0141         uiGeneralTab.leComment->setEnabled(true);
0142 
0143         uiGeneralTab.leName->setText(m_curve->name());
0144         uiGeneralTab.leComment->setText(m_curve->comment());
0145     } else {
0146         uiGeneralTab.lName->setEnabled(false);
0147         uiGeneralTab.leName->setEnabled(false);
0148         uiGeneralTab.lComment->setEnabled(false);
0149         uiGeneralTab.leComment->setEnabled(false);
0150 
0151         uiGeneralTab.leName->setText(QString());
0152         uiGeneralTab.leComment->setText(QString());
0153     }
0154 
0155     auto* analysisCurve = dynamic_cast<XYAnalysisCurve*>(m_curve);
0156     checkColumnAvailability(cbXDataColumn, analysisCurve->xDataColumn(), analysisCurve->xDataColumnPath());
0157     checkColumnAvailability(cbYDataColumn, analysisCurve->yDataColumn(), analysisCurve->yDataColumnPath());
0158     checkColumnAvailability(cbY2DataColumn, analysisCurve->y2DataColumn(), analysisCurve->y2DataColumnPath());
0159 
0160     //show the properties of the first curve
0161     m_convolutionCurve = dynamic_cast<XYConvolutionCurve*>(m_curve);
0162 
0163     // hide x-Range per default
0164     uiGeneralTab.lXRange->setEnabled(false);
0165     uiGeneralTab.cbAutoRange->setEnabled(false);
0166 
0167     uiGeneralTab.cbDataSourceType->setCurrentIndex(static_cast<int>(m_convolutionCurve->dataSourceType()));
0168     this->dataSourceTypeChanged(uiGeneralTab.cbDataSourceType->currentIndex());
0169     XYCurveDock::setModelIndexFromAspect(cbDataSourceCurve, m_convolutionCurve->dataSourceCurve());
0170     XYCurveDock::setModelIndexFromAspect(cbXDataColumn, m_convolutionCurve->xDataColumn());
0171     XYCurveDock::setModelIndexFromAspect(cbYDataColumn, m_convolutionCurve->yDataColumn());
0172     XYCurveDock::setModelIndexFromAspect(cbY2DataColumn, m_convolutionCurve->y2DataColumn());
0173     uiGeneralTab.sbSamplingInterval->setValue(m_convolutionData.samplingInterval);
0174     uiGeneralTab.cbKernel->setCurrentIndex(m_convolutionData.kernel);
0175     uiGeneralTab.sbKernelSize->setValue((int)m_convolutionData.kernelSize);
0176     uiGeneralTab.cbAutoRange->setChecked(m_convolutionData.autoRange);
0177     uiGeneralTab.sbMin->setValue(m_convolutionData.xRange.first());
0178     uiGeneralTab.sbMax->setValue(m_convolutionData.xRange.last());
0179     this->autoRangeChanged();
0180     y2DataColumnChanged(cbY2DataColumn->currentModelIndex());
0181 
0182     // settings
0183     uiGeneralTab.cbDirection->setCurrentIndex(m_convolutionData.direction);
0184     uiGeneralTab.cbType->setCurrentIndex(m_convolutionData.type);
0185     //m_convolutionData.method not used
0186     uiGeneralTab.cbNorm->setCurrentIndex(m_convolutionData.normalize);
0187     uiGeneralTab.cbWrap->setCurrentIndex(m_convolutionData.wrap);
0188 
0189     this->directionChanged();
0190 
0191     this->showConvolutionResult();
0192 
0193     uiGeneralTab.chkVisible->setChecked( m_curve->isVisible() );
0194 
0195     //Slots
0196     connect(m_convolutionCurve, &XYConvolutionCurve::aspectDescriptionChanged, this, &XYConvolutionCurveDock::curveDescriptionChanged);
0197     connect(m_convolutionCurve, &XYConvolutionCurve::dataSourceTypeChanged, this, &XYConvolutionCurveDock::curveDataSourceTypeChanged);
0198     connect(m_convolutionCurve, &XYConvolutionCurve::dataSourceCurveChanged, this, &XYConvolutionCurveDock::curveDataSourceCurveChanged);
0199     connect(m_convolutionCurve, &XYConvolutionCurve::xDataColumnChanged, this, &XYConvolutionCurveDock::curveXDataColumnChanged);
0200     connect(m_convolutionCurve, &XYConvolutionCurve::yDataColumnChanged, this, &XYConvolutionCurveDock::curveYDataColumnChanged);
0201     connect(m_convolutionCurve, &XYConvolutionCurve::y2DataColumnChanged, this, &XYConvolutionCurveDock::curveY2DataColumnChanged);
0202     connect(m_convolutionCurve, &XYConvolutionCurve::convolutionDataChanged, this, &XYConvolutionCurveDock::curveConvolutionDataChanged);
0203     connect(m_convolutionCurve, &XYConvolutionCurve::sourceDataChanged, this, &XYConvolutionCurveDock::enableRecalculate);
0204     connect(m_convolutionCurve, QOverload<bool>::of(&XYCurve::visibilityChanged), this, &XYConvolutionCurveDock::curveVisibilityChanged);
0205 }
0206 
0207 void XYConvolutionCurveDock::setModel() {
0208     DEBUG("XYConvolutionCurveDock::setModel()");
0209     QList<AspectType> list{AspectType::Folder, AspectType::Datapicker, AspectType::Worksheet,
0210                            AspectType::CartesianPlot, AspectType::XYCurve, AspectType::XYAnalysisCurve};
0211     cbDataSourceCurve->setTopLevelClasses(list);
0212 
0213     QList<const AbstractAspect*> hiddenAspects;
0214     for (auto* curve : m_curvesList)
0215         hiddenAspects << curve;
0216     cbDataSourceCurve->setHiddenAspects(hiddenAspects);
0217 
0218     list = {AspectType::Folder, AspectType::Workbook, AspectType::Datapicker, AspectType::DatapickerCurve,
0219             AspectType::Spreadsheet, AspectType::LiveDataSource, AspectType::Column,
0220             AspectType::Worksheet, AspectType::CartesianPlot, AspectType::XYConvolution
0221            };
0222     cbXDataColumn->setTopLevelClasses(list);
0223     cbYDataColumn->setTopLevelClasses(list);
0224     cbY2DataColumn->setTopLevelClasses(list);
0225 
0226     cbDataSourceCurve->setModel(m_aspectTreeModel);
0227     cbXDataColumn->setModel(m_aspectTreeModel);
0228     cbYDataColumn->setModel(m_aspectTreeModel);
0229     cbY2DataColumn->setModel(m_aspectTreeModel);
0230 
0231     XYCurveDock::setModel();
0232     DEBUG("XYConvolutionCurveDock::setModel() DONE");
0233 }
0234 
0235 /*!
0236   sets the curves. The properties of the curves in the list \c list can be edited in this widget.
0237 */
0238 void XYConvolutionCurveDock::setCurves(QList<XYCurve*> list) {
0239     m_initializing = true;
0240     m_curvesList = list;
0241     m_curve = list.first();
0242     m_convolutionCurve = dynamic_cast<XYConvolutionCurve*>(m_curve);
0243     m_aspectTreeModel = new AspectTreeModel(m_curve->project());
0244     this->setModel();
0245     m_convolutionData = m_convolutionCurve->convolutionData();
0246 
0247     SET_NUMBER_LOCALE
0248     uiGeneralTab.sbSamplingInterval->setLocale(numberLocale);
0249     uiGeneralTab.sbMin->setLocale(numberLocale);
0250     uiGeneralTab.sbMax->setLocale(numberLocale);
0251 
0252     initGeneralTab();
0253     initTabs();
0254     m_initializing = false;
0255 
0256     //hide the "skip gaps" option after the curves were set
0257     ui.lLineSkipGaps->hide();
0258     ui.chkLineSkipGaps->hide();
0259 }
0260 
0261 //*************************************************************
0262 //**** SLOTs for changes triggered in XYConvolutionCurveDock **
0263 //*************************************************************
0264 void XYConvolutionCurveDock::dataSourceTypeChanged(int index) {
0265     auto type = (XYAnalysisCurve::DataSourceType)index;
0266     if (type == XYAnalysisCurve::DataSourceType::Spreadsheet) {
0267         uiGeneralTab.lDataSourceCurve->hide();
0268         cbDataSourceCurve->hide();
0269         uiGeneralTab.lXColumn->show();
0270         cbXDataColumn->show();
0271         uiGeneralTab.lYColumn->show();
0272         cbYDataColumn->show();
0273         uiGeneralTab.lY2Column->show();
0274         cbY2DataColumn->show();
0275         uiGeneralTab.lSamplingInterval->show();
0276         uiGeneralTab.l2SamplingInterval->show();
0277         uiGeneralTab.sbSamplingInterval->show();
0278         uiGeneralTab.lKernel->setText(i18n("or Kernel/Size:"));
0279     } else {    //xy-curve data source
0280         uiGeneralTab.lDataSourceCurve->show();
0281         cbDataSourceCurve->show();
0282         uiGeneralTab.lXColumn->hide();
0283         cbXDataColumn->hide();
0284         uiGeneralTab.lYColumn->hide();
0285         cbYDataColumn->hide();
0286         uiGeneralTab.lY2Column->hide();
0287         cbY2DataColumn->hide();
0288         uiGeneralTab.lSamplingInterval->hide();
0289         uiGeneralTab.l2SamplingInterval->hide();
0290         uiGeneralTab.sbSamplingInterval->hide();
0291         uiGeneralTab.lKernel->setEnabled(true);
0292         uiGeneralTab.lKernel->setText(i18n("with Kernel/Size:"));
0293         uiGeneralTab.cbKernel->setEnabled(true);
0294         uiGeneralTab.sbKernelSize->setEnabled(true);
0295     }
0296 
0297     if (m_initializing)
0298         return;
0299 
0300     for (auto* curve : m_curvesList)
0301         dynamic_cast<XYConvolutionCurve*>(curve)->setDataSourceType(type);
0302 
0303     enableRecalculate();
0304 }
0305 
0306 void XYConvolutionCurveDock::dataSourceCurveChanged(const QModelIndex& index) {
0307     auto* aspect = static_cast<AbstractAspect*>(index.internalPointer());
0308     auto* dataSourceCurve = dynamic_cast<XYCurve*>(aspect);
0309 
0310     if (m_initializing)
0311         return;
0312 
0313     for (auto* curve : m_curvesList)
0314         dynamic_cast<XYConvolutionCurve*>(curve)->setDataSourceCurve(dataSourceCurve);
0315 }
0316 
0317 void XYConvolutionCurveDock::xDataColumnChanged(const QModelIndex& index) {
0318     DEBUG("XYConvolutionCurveDock::xDataColumnChanged()");
0319     if (m_initializing)
0320         return;
0321 
0322     auto* aspect = static_cast<AbstractAspect*>(index.internalPointer());
0323     auto* column = dynamic_cast<AbstractColumn*>(aspect);
0324 
0325     for (auto* curve : m_curvesList)
0326         dynamic_cast<XYConvolutionCurve*>(curve)->setXDataColumn(column);
0327 
0328     if (column != nullptr) {
0329         if (uiGeneralTab.cbAutoRange->isChecked()) {
0330             uiGeneralTab.sbMin->setValue(column->minimum());
0331             uiGeneralTab.sbMax->setValue(column->maximum());
0332         }
0333     }
0334 
0335     cbXDataColumn->useCurrentIndexText(true);
0336     cbXDataColumn->setInvalid(false);
0337 }
0338 
0339 void XYConvolutionCurveDock::yDataColumnChanged(const QModelIndex& index) {
0340     if (m_initializing)
0341         return;
0342     DEBUG("yDataColumnChanged()");
0343 
0344     auto* aspect = static_cast<AbstractAspect*>(index.internalPointer());
0345     auto* column = dynamic_cast<AbstractColumn*>(aspect);
0346 
0347     for (auto* curve : m_curvesList)
0348         dynamic_cast<XYConvolutionCurve*>(curve)->setYDataColumn(column);
0349 
0350     cbYDataColumn->useCurrentIndexText(true);
0351     cbYDataColumn->setInvalid(false);
0352 }
0353 
0354 void XYConvolutionCurveDock::y2DataColumnChanged(const QModelIndex& index) {
0355     if (m_initializing)
0356         return;
0357     DEBUG("y2DataColumnChanged()");
0358 
0359     auto* aspect = static_cast<AbstractAspect*>(index.internalPointer());
0360     auto* column = dynamic_cast<AbstractColumn*>(aspect);
0361 
0362     for (auto* curve : m_curvesList)
0363         dynamic_cast<XYConvolutionCurve*>(curve)->setY2DataColumn(column);
0364 
0365     cbY2DataColumn->useCurrentIndexText(true);
0366     cbY2DataColumn->setInvalid(false);
0367 }
0368 
0369 void XYConvolutionCurveDock::samplingIntervalChanged() {
0370     double samplingInterval =  uiGeneralTab.sbSamplingInterval->value();
0371     m_convolutionData.samplingInterval = samplingInterval;
0372 
0373     enableRecalculate();
0374 }
0375 
0376 void XYConvolutionCurveDock::kernelChanged() {
0377     auto kernel = (nsl_conv_kernel_type) uiGeneralTab.cbKernel->currentIndex();
0378     m_convolutionData.kernel = kernel;
0379 
0380     //TODO: change selectable sizes
0381     uiGeneralTab.sbKernelSize->setEnabled(true);
0382     switch (kernel) {
0383     case nsl_conv_kernel_avg:   // all values allowed
0384     case nsl_conv_kernel_smooth_triangle:
0385     case nsl_conv_kernel_gaussian:
0386     case nsl_conv_kernel_lorentzian:
0387         uiGeneralTab.sbKernelSize->setMinimum(2);
0388         uiGeneralTab.sbKernelSize->setMaximum(999);
0389         uiGeneralTab.sbKernelSize->setSingleStep(1);
0390         uiGeneralTab.sbKernelSize->setValue(2);
0391         break;
0392     case nsl_conv_kernel_smooth_gaussian:
0393         uiGeneralTab.sbKernelSize->setMinimum(5);
0394         uiGeneralTab.sbKernelSize->setMaximum(9);
0395         uiGeneralTab.sbKernelSize->setSingleStep(2);
0396         uiGeneralTab.sbKernelSize->setValue(5);
0397         break;
0398     case nsl_conv_kernel_first_derivative:
0399         uiGeneralTab.sbKernelSize->setMinimum(2);
0400         uiGeneralTab.sbKernelSize->setValue(2);
0401         uiGeneralTab.sbKernelSize->setEnabled(false);
0402         break;
0403     case nsl_conv_kernel_smooth_first_derivative:
0404         uiGeneralTab.sbKernelSize->setMinimum(3);
0405         uiGeneralTab.sbKernelSize->setMaximum(999);
0406         uiGeneralTab.sbKernelSize->setSingleStep(2);
0407         uiGeneralTab.sbKernelSize->setValue(3);
0408         break;
0409     case nsl_conv_kernel_second_derivative:
0410         uiGeneralTab.sbKernelSize->setMinimum(3);
0411         uiGeneralTab.sbKernelSize->setValue(3);
0412         uiGeneralTab.sbKernelSize->setEnabled(false);
0413         break;
0414     case nsl_conv_kernel_third_derivative:
0415         uiGeneralTab.sbKernelSize->setMinimum(4);
0416         uiGeneralTab.sbKernelSize->setValue(4);
0417         uiGeneralTab.sbKernelSize->setEnabled(false);
0418         break;
0419     case nsl_conv_kernel_fourth_derivative:
0420         uiGeneralTab.sbKernelSize->setMinimum(5);
0421         uiGeneralTab.sbKernelSize->setValue(5);
0422         uiGeneralTab.sbKernelSize->setEnabled(false);
0423         break;
0424     }
0425 
0426     enableRecalculate();
0427 }
0428 
0429 void XYConvolutionCurveDock::kernelSizeChanged() {
0430     size_t kernelSize = uiGeneralTab.sbKernelSize->value();
0431     m_convolutionData.kernelSize = kernelSize;
0432 
0433     enableRecalculate();
0434 }
0435 
0436 void XYConvolutionCurveDock::autoRangeChanged() {
0437     bool autoRange = uiGeneralTab.cbAutoRange->isChecked();
0438     m_convolutionData.autoRange = autoRange;
0439 
0440     if (autoRange) {
0441         uiGeneralTab.lMin->setEnabled(false);
0442         uiGeneralTab.sbMin->setEnabled(false);
0443         uiGeneralTab.lMax->setEnabled(false);
0444         uiGeneralTab.sbMax->setEnabled(false);
0445 
0446         const AbstractColumn* xDataColumn = nullptr;
0447         if (m_convolutionCurve->dataSourceType() == XYAnalysisCurve::DataSourceType::Spreadsheet)
0448             xDataColumn = m_convolutionCurve->xDataColumn();
0449         else {
0450             if (m_convolutionCurve->dataSourceCurve())
0451                 xDataColumn = m_convolutionCurve->dataSourceCurve()->xColumn();
0452         }
0453 
0454         if (xDataColumn) {
0455             uiGeneralTab.sbMin->setValue(xDataColumn->minimum());
0456             uiGeneralTab.sbMax->setValue(xDataColumn->maximum());
0457         }
0458     } else {
0459         uiGeneralTab.lMin->setEnabled(true);
0460         uiGeneralTab.sbMin->setEnabled(true);
0461         uiGeneralTab.lMax->setEnabled(true);
0462         uiGeneralTab.sbMax->setEnabled(true);
0463     }
0464 
0465 }
0466 void XYConvolutionCurveDock::xRangeMinChanged() {
0467     double xMin = uiGeneralTab.sbMin->value();
0468 
0469     m_convolutionData.xRange.first() = xMin;
0470     enableRecalculate();
0471 }
0472 
0473 void XYConvolutionCurveDock::xRangeMaxChanged() {
0474     double xMax = uiGeneralTab.sbMax->value();
0475 
0476     m_convolutionData.xRange.last() = xMax;
0477     enableRecalculate();
0478 }
0479 
0480 void XYConvolutionCurveDock::directionChanged() {
0481     DEBUG("XYConvolutionCurveDock::directionChanged()");
0482     auto dir = (nsl_conv_direction_type) uiGeneralTab.cbDirection->currentIndex();
0483     m_convolutionData.direction = dir;
0484 
0485     // change name if still default
0486     if ( m_curve->name().compare(i18n("Convolution")) == 0  && dir == nsl_conv_direction_backward) {
0487         m_curve->setName(i18n("Deconvolution"));
0488         uiGeneralTab.leName->setText(m_curve->name());
0489     }
0490     if (m_curve->name().compare(i18n("Deconvolution")) == 0  && dir == nsl_conv_direction_forward) {
0491         m_curve->setName(i18n("Convolution"));
0492         uiGeneralTab.leName->setText(m_curve->name());
0493     }
0494 
0495     enableRecalculate();
0496 }
0497 
0498 void XYConvolutionCurveDock::typeChanged() {
0499     auto type = (nsl_conv_type_type)uiGeneralTab.cbType->currentIndex();
0500     m_convolutionData.type = type;
0501 
0502     enableRecalculate();
0503 }
0504 
0505 void XYConvolutionCurveDock::normChanged() {
0506     auto norm = (nsl_conv_norm_type)uiGeneralTab.cbNorm->currentIndex();
0507     m_convolutionData.normalize = norm;
0508 
0509     enableRecalculate();
0510 }
0511 
0512 void XYConvolutionCurveDock::wrapChanged() {
0513     auto wrap = (nsl_conv_wrap_type)uiGeneralTab.cbWrap->currentIndex();
0514     m_convolutionData.wrap = wrap;
0515 
0516     enableRecalculate();
0517 }
0518 
0519 void XYConvolutionCurveDock::recalculateClicked() {
0520     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
0521 
0522     for (auto* curve : m_curvesList)
0523         dynamic_cast<XYConvolutionCurve*>(curve)->setConvolutionData(m_convolutionData);
0524 
0525     uiGeneralTab.pbRecalculate->setEnabled(false);
0526     if (m_convolutionData.direction == nsl_conv_direction_forward)
0527         emit info(i18n("Convolution status: %1", m_convolutionCurve->convolutionResult().status));
0528     else
0529         emit info(i18n("Deconvolution status: %1", m_convolutionCurve->convolutionResult().status));
0530     QApplication::restoreOverrideCursor();
0531 }
0532 
0533 void XYConvolutionCurveDock::enableRecalculate() const {
0534     DEBUG("XYConvolutionCurveDock::enableRecalculate()");
0535     if (m_initializing)
0536         return;
0537 
0538     bool hasSourceData = false;
0539     //no convolution possible without the y-data
0540     if (m_convolutionCurve->dataSourceType() == XYAnalysisCurve::DataSourceType::Spreadsheet) {
0541         AbstractAspect* aspectY = static_cast<AbstractAspect*>(cbYDataColumn->currentModelIndex().internalPointer());
0542         hasSourceData = (aspectY != nullptr);
0543         if (aspectY) {
0544             cbYDataColumn->useCurrentIndexText(true);
0545             cbYDataColumn->setInvalid(false);
0546         }
0547     } else {
0548          hasSourceData = (m_convolutionCurve->dataSourceCurve() != nullptr);
0549     }
0550 
0551     uiGeneralTab.pbRecalculate->setEnabled(hasSourceData);
0552 }
0553 
0554 /*!
0555  * show the result and details of the convolution
0556  */
0557 void XYConvolutionCurveDock::showConvolutionResult() {
0558     const XYConvolutionCurve::ConvolutionResult& convolutionResult = m_convolutionCurve->convolutionResult();
0559     if (!convolutionResult.available) {
0560         uiGeneralTab.teResult->clear();
0561         return;
0562     }
0563 
0564     QString str = i18n("status: %1", convolutionResult.status) + "<br>";
0565 
0566     if (!convolutionResult.valid) {
0567         uiGeneralTab.teResult->setText(str);
0568         return; //result is not valid, there was an error which is shown in the status-string, nothing to show more.
0569     }
0570 
0571     SET_NUMBER_LOCALE
0572     if (convolutionResult.elapsedTime > 1000)
0573         str += i18n("calculation time: %1 s", numberLocale.toString(convolutionResult.elapsedTime/1000)) + "<br>";
0574     else
0575         str += i18n("calculation time: %1 ms", numberLocale.toString(convolutionResult.elapsedTime)) + "<br>";
0576 
0577     str += "<br><br>";
0578 
0579     uiGeneralTab.teResult->setText(str);
0580 
0581     //enable the "recalculate"-button if the source data was changed since the last convolution
0582     uiGeneralTab.pbRecalculate->setEnabled(m_convolutionCurve->isSourceDataChangedSinceLastRecalc());
0583 }
0584 
0585 //*************************************************************
0586 //*********** SLOTs for changes triggered in XYCurve **********
0587 //*************************************************************
0588 //General-Tab
0589 void XYConvolutionCurveDock::curveDescriptionChanged(const AbstractAspect* aspect) {
0590     if (m_curve != aspect)
0591         return;
0592 
0593     m_initializing = true;
0594     if (aspect->name() != uiGeneralTab.leName->text())
0595         uiGeneralTab.leName->setText(aspect->name());
0596     else if (aspect->comment() != uiGeneralTab.leComment->text())
0597         uiGeneralTab.leComment->setText(aspect->comment());
0598     m_initializing = false;
0599 }
0600 
0601 void XYConvolutionCurveDock::curveDataSourceTypeChanged(XYAnalysisCurve::DataSourceType type) {
0602     m_initializing = true;
0603     uiGeneralTab.cbDataSourceType->setCurrentIndex(static_cast<int>(type));
0604     m_initializing = false;
0605 }
0606 
0607 void XYConvolutionCurveDock::curveDataSourceCurveChanged(const XYCurve* curve) {
0608     m_initializing = true;
0609     XYCurveDock::setModelIndexFromAspect(cbDataSourceCurve, curve);
0610     m_initializing = false;
0611 }
0612 
0613 void XYConvolutionCurveDock::curveXDataColumnChanged(const AbstractColumn* column) {
0614     DEBUG("XYConvolutionCurveDock::curveXDataColumnChanged()");
0615     m_initializing = true;
0616     XYCurveDock::setModelIndexFromAspect(cbXDataColumn, column);
0617     if (column != nullptr) {
0618         DEBUG("X Column available");
0619         uiGeneralTab.lXRange->setEnabled(true);
0620         uiGeneralTab.cbAutoRange->setEnabled(true);
0621         uiGeneralTab.lSamplingInterval->setEnabled(false);
0622         uiGeneralTab.l2SamplingInterval->setEnabled(false);
0623         uiGeneralTab.sbSamplingInterval->setEnabled(false);
0624     } else {
0625         DEBUG("X Column not available");
0626         uiGeneralTab.lXRange->setEnabled(false);
0627         uiGeneralTab.cbAutoRange->setEnabled(false);
0628         uiGeneralTab.lSamplingInterval->setEnabled(true);
0629         uiGeneralTab.l2SamplingInterval->setEnabled(true);
0630         uiGeneralTab.sbSamplingInterval->setEnabled(true);
0631     }
0632     m_initializing = false;
0633 }
0634 
0635 void XYConvolutionCurveDock::curveYDataColumnChanged(const AbstractColumn* column) {
0636     DEBUG("XYConvolutionCurveDock::curveYDataColumnChanged()");
0637     m_initializing = true;
0638     XYCurveDock::setModelIndexFromAspect(cbYDataColumn, column);
0639     m_initializing = false;
0640 }
0641 
0642 void XYConvolutionCurveDock::curveY2DataColumnChanged(const AbstractColumn* column) {
0643     DEBUG("XYConvolutionCurveDock::curveY2DataColumnChanged()");
0644     m_initializing = true;
0645     XYCurveDock::setModelIndexFromAspect(cbY2DataColumn, column);
0646     if (column != nullptr) {
0647         DEBUG("Y2 Column available");
0648         uiGeneralTab.lKernel->setEnabled(false);
0649         uiGeneralTab.cbKernel->setEnabled(false);
0650         uiGeneralTab.sbKernelSize->setEnabled(false);
0651     } else {
0652         DEBUG("Y2 Column not available");
0653         uiGeneralTab.lKernel->setEnabled(true);
0654         uiGeneralTab.cbKernel->setEnabled(true);
0655         uiGeneralTab.sbKernelSize->setEnabled(true);
0656     }
0657     m_initializing = false;
0658 }
0659 
0660 void XYConvolutionCurveDock::curveConvolutionDataChanged(const XYConvolutionCurve::ConvolutionData& convolutionData) {
0661     m_initializing = true;
0662     m_convolutionData = convolutionData;
0663     this->directionChanged();
0664 
0665     this->showConvolutionResult();
0666     m_initializing = false;
0667 }
0668 
0669 void XYConvolutionCurveDock::dataChanged() {
0670     this->enableRecalculate();
0671 }
0672 
0673 void XYConvolutionCurveDock::curveVisibilityChanged(bool on) {
0674     m_initializing = true;
0675     uiGeneralTab.chkVisible->setChecked(on);
0676     m_initializing = false;
0677 }