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

0001 /***************************************************************************
0002     File             : XYDifferentiationCurveDock.cpp
0003     Project          : LabPlot
0004     --------------------------------------------------------------------
0005     Copyright        : (C) 2016 Stefan Gerlach (stefan.gerlach@uni.kn)
0006     Copyright        : (C) 2017 Alexander Semke (alexander.semke@web.de)
0007     Description      : widget for editing properties of differentiation curves
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 "XYDifferentiationCurveDock.h"
0031 #include "backend/core/AspectTreeModel.h"
0032 #include "backend/core/Project.h"
0033 #include "backend/worksheet/plots/cartesian/XYDifferentiationCurve.h"
0034 #include "commonfrontend/widgets/TreeViewComboBox.h"
0035 
0036 #include <QStandardItemModel>
0037 
0038 extern "C" {
0039 #include "backend/nsl/nsl_diff.h"
0040 }
0041 
0042 /*!
0043   \class XYDifferentiationCurveDock
0044  \brief  Provides a widget for editing the properties of the XYDifferentiationCurves
0045         (2D-curves defined by a differentiation) currently selected in
0046         the project explorer.
0047 
0048   If more than one curves are set, the properties of the first column are shown.
0049   The changes of the properties are applied to all curves.
0050   The exclusions are the name, the comment and the datasets (columns) of
0051   the curves  - these properties can only be changed if there is only one single curve.
0052 
0053   \ingroup kdefrontend
0054 */
0055 
0056 XYDifferentiationCurveDock::XYDifferentiationCurveDock(QWidget* parent) : XYCurveDock(parent) {
0057 }
0058 
0059 /*!
0060  *  // Tab "General"
0061  */
0062 void XYDifferentiationCurveDock::setupGeneral() {
0063     QWidget* generalTab = new QWidget(ui.tabGeneral);
0064     uiGeneralTab.setupUi(generalTab);
0065     m_leName = uiGeneralTab.leName;
0066     m_leComment = uiGeneralTab.leComment;
0067 
0068     auto* gridLayout = static_cast<QGridLayout*>(generalTab->layout());
0069     gridLayout->setContentsMargins(2, 2, 2, 2);
0070     gridLayout->setHorizontalSpacing(2);
0071     gridLayout->setVerticalSpacing(2);
0072 
0073     uiGeneralTab.cbDataSourceType->addItem(i18n("Spreadsheet"));
0074     uiGeneralTab.cbDataSourceType->addItem(i18n("XY-Curve"));
0075 
0076     cbDataSourceCurve = new TreeViewComboBox(generalTab);
0077     gridLayout->addWidget(cbDataSourceCurve, 5, 2, 1, 3);
0078     cbXDataColumn = new TreeViewComboBox(generalTab);
0079     gridLayout->addWidget(cbXDataColumn, 6, 2, 1, 3);
0080     cbYDataColumn = new TreeViewComboBox(generalTab);
0081     gridLayout->addWidget(cbYDataColumn, 7, 2, 1, 3);
0082 
0083     for (int i = 0; i < NSL_DIFF_DERIV_ORDER_COUNT; ++i)
0084         uiGeneralTab.cbDerivOrder->addItem(i18n(nsl_diff_deriv_order_name[i]));
0085 
0086     uiGeneralTab.sbMin->setRange(-std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
0087     uiGeneralTab.sbMax->setRange(-std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
0088 
0089     uiGeneralTab.pbRecalculate->setIcon( QIcon::fromTheme("run-build") );
0090 
0091     auto* layout = new QHBoxLayout(ui.tabGeneral);
0092     layout->setMargin(0);
0093     layout->addWidget(generalTab);
0094 
0095     //Slots
0096     connect(uiGeneralTab.leName, &QLineEdit::textChanged, this, &XYDifferentiationCurveDock::nameChanged);
0097     connect(uiGeneralTab.leComment, &QLineEdit::textChanged, this, &XYDifferentiationCurveDock::commentChanged);
0098 
0099     connect(uiGeneralTab.chkVisible, &QCheckBox::clicked, this, &XYDifferentiationCurveDock::visibilityChanged);
0100     connect(uiGeneralTab.cbDataSourceType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYDifferentiationCurveDock::dataSourceTypeChanged);
0101     connect(uiGeneralTab.cbAutoRange, &QCheckBox::clicked, this, &XYDifferentiationCurveDock::autoRangeChanged);
0102     connect(uiGeneralTab.sbMin, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &XYDifferentiationCurveDock::xRangeMinChanged);
0103     connect(uiGeneralTab.sbMax, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &XYDifferentiationCurveDock::xRangeMaxChanged);
0104     connect(uiGeneralTab.dateTimeEditMin, &QDateTimeEdit::dateTimeChanged, this, &XYDifferentiationCurveDock::xRangeMinDateTimeChanged);
0105     connect(uiGeneralTab.dateTimeEditMax, &QDateTimeEdit::dateTimeChanged, this, &XYDifferentiationCurveDock::xRangeMaxDateTimeChanged);
0106     connect(uiGeneralTab.cbDerivOrder, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYDifferentiationCurveDock::derivOrderChanged);
0107     connect(uiGeneralTab.sbAccOrder, QOverload<int>::of(&QSpinBox::valueChanged), this, &XYDifferentiationCurveDock::accOrderChanged);
0108     connect(uiGeneralTab.pbRecalculate, &QPushButton::clicked, this, &XYDifferentiationCurveDock::recalculateClicked);
0109 
0110     connect(cbDataSourceCurve, &TreeViewComboBox::currentModelIndexChanged, this, &XYDifferentiationCurveDock::dataSourceCurveChanged);
0111     connect(cbXDataColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYDifferentiationCurveDock::xDataColumnChanged);
0112     connect(cbYDataColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYDifferentiationCurveDock::yDataColumnChanged);
0113 }
0114 
0115 void XYDifferentiationCurveDock::initGeneralTab() {
0116     //if there are more than one curve in the list, disable the tab "general"
0117     if (m_curvesList.size() == 1) {
0118         uiGeneralTab.lName->setEnabled(true);
0119         uiGeneralTab.leName->setEnabled(true);
0120         uiGeneralTab.lComment->setEnabled(true);
0121         uiGeneralTab.leComment->setEnabled(true);
0122 
0123         uiGeneralTab.leName->setText(m_curve->name());
0124         uiGeneralTab.leComment->setText(m_curve->comment());
0125     } else {
0126         uiGeneralTab.lName->setEnabled(false);
0127         uiGeneralTab.leName->setEnabled(false);
0128         uiGeneralTab.lComment->setEnabled(false);
0129         uiGeneralTab.leComment->setEnabled(false);
0130 
0131         uiGeneralTab.leName->setText(QString());
0132         uiGeneralTab.leComment->setText(QString());
0133     }
0134 
0135     //show the properties of the first curve
0136     m_differentiationCurve = static_cast<XYDifferentiationCurve*>(m_curve);
0137     checkColumnAvailability(cbXDataColumn, m_differentiationCurve->xDataColumn(), m_differentiationCurve->xDataColumnPath());
0138     checkColumnAvailability(cbYDataColumn, m_differentiationCurve->yDataColumn(), m_differentiationCurve->yDataColumnPath());
0139 
0140     //data source
0141     uiGeneralTab.cbDataSourceType->setCurrentIndex(static_cast<int>(m_differentiationCurve->dataSourceType()));
0142     this->dataSourceTypeChanged(uiGeneralTab.cbDataSourceType->currentIndex());
0143     XYCurveDock::setModelIndexFromAspect(cbDataSourceCurve, m_differentiationCurve->dataSourceCurve());
0144     XYCurveDock::setModelIndexFromAspect(cbXDataColumn, m_differentiationCurve->xDataColumn());
0145     XYCurveDock::setModelIndexFromAspect(cbYDataColumn, m_differentiationCurve->yDataColumn());
0146 
0147     //range widgets
0148     const auto* plot = static_cast<const CartesianPlot*>(m_differentiationCurve->parentAspect());
0149     m_dateTimeRange = (plot->xRangeFormat() != CartesianPlot::RangeFormat::Numeric);
0150     if (!m_dateTimeRange) {
0151         uiGeneralTab.sbMin->setValue(m_differentiationData.xRange.first());
0152         uiGeneralTab.sbMax->setValue(m_differentiationData.xRange.last());
0153     } else {
0154         uiGeneralTab.dateTimeEditMin->setDateTime( QDateTime::fromMSecsSinceEpoch(m_differentiationData.xRange.first()) );
0155         uiGeneralTab.dateTimeEditMax->setDateTime( QDateTime::fromMSecsSinceEpoch(m_differentiationData.xRange.last()) );
0156     }
0157 
0158     uiGeneralTab.lMin->setVisible(!m_dateTimeRange);
0159     uiGeneralTab.sbMin->setVisible(!m_dateTimeRange);
0160     uiGeneralTab.lMax->setVisible(!m_dateTimeRange);
0161     uiGeneralTab.sbMax->setVisible(!m_dateTimeRange);
0162     uiGeneralTab.lMinDateTime->setVisible(m_dateTimeRange);
0163     uiGeneralTab.dateTimeEditMin->setVisible(m_dateTimeRange);
0164     uiGeneralTab.lMaxDateTime->setVisible(m_dateTimeRange);
0165     uiGeneralTab.dateTimeEditMax->setVisible(m_dateTimeRange);
0166 
0167     //auto range
0168     uiGeneralTab.cbAutoRange->setChecked(m_differentiationData.autoRange);
0169     this->autoRangeChanged();
0170 
0171     // update list of selectable types
0172     xDataColumnChanged(cbXDataColumn->currentModelIndex());
0173 
0174     uiGeneralTab.cbDerivOrder->setCurrentIndex(m_differentiationData.derivOrder);
0175     this->derivOrderChanged(m_differentiationData.derivOrder);
0176 
0177     uiGeneralTab.sbAccOrder->setValue(m_differentiationData.accOrder);
0178     this->accOrderChanged(m_differentiationData.accOrder);
0179 
0180     this->showDifferentiationResult();
0181 
0182     uiGeneralTab.chkVisible->setChecked( m_curve->isVisible() );
0183 
0184     //Slots
0185     connect(m_differentiationCurve, &XYDifferentiationCurve::aspectDescriptionChanged, this, &XYDifferentiationCurveDock::curveDescriptionChanged);
0186     connect(m_differentiationCurve, &XYDifferentiationCurve::dataSourceTypeChanged, this, &XYDifferentiationCurveDock::curveDataSourceTypeChanged);
0187     connect(m_differentiationCurve, &XYDifferentiationCurve::dataSourceCurveChanged, this, &XYDifferentiationCurveDock::curveDataSourceCurveChanged);
0188     connect(m_differentiationCurve, &XYDifferentiationCurve::xDataColumnChanged, this, &XYDifferentiationCurveDock::curveXDataColumnChanged);
0189     connect(m_differentiationCurve, &XYDifferentiationCurve::yDataColumnChanged, this, &XYDifferentiationCurveDock::curveYDataColumnChanged);
0190     connect(m_differentiationCurve, &XYDifferentiationCurve::differentiationDataChanged, this, &XYDifferentiationCurveDock::curveDifferentiationDataChanged);
0191     connect(m_differentiationCurve, &XYDifferentiationCurve::sourceDataChanged, this, &XYDifferentiationCurveDock::enableRecalculate);
0192     connect(m_differentiationCurve, QOverload<bool>::of(&XYCurve::visibilityChanged), this, &XYDifferentiationCurveDock::curveVisibilityChanged);
0193 }
0194 
0195 void XYDifferentiationCurveDock::setModel() {
0196     QList<AspectType> list{AspectType::Folder, AspectType::Datapicker, AspectType::Worksheet,
0197                             AspectType::CartesianPlot, AspectType::XYCurve, AspectType::XYAnalysisCurve};
0198     cbDataSourceCurve->setTopLevelClasses(list);
0199 
0200     QList<const AbstractAspect*> hiddenAspects;
0201     for (auto* curve : m_curvesList)
0202         hiddenAspects << curve;
0203     cbDataSourceCurve->setHiddenAspects(hiddenAspects);
0204 
0205     list = {AspectType::Folder, AspectType::Workbook, AspectType::Datapicker,
0206             AspectType::DatapickerCurve, AspectType::Spreadsheet, AspectType::LiveDataSource,
0207             AspectType::Column, AspectType::Worksheet, AspectType::CartesianPlot, AspectType::XYFitCurve
0208            };
0209     cbXDataColumn->setTopLevelClasses(list);
0210     cbYDataColumn->setTopLevelClasses(list);
0211 
0212     cbDataSourceCurve->setModel(m_aspectTreeModel);
0213     cbXDataColumn->setModel(m_aspectTreeModel);
0214     cbYDataColumn->setModel(m_aspectTreeModel);
0215 
0216     XYCurveDock::setModel();
0217 }
0218 
0219 /*!
0220   sets the curves. The properties of the curves in the list \c list can be edited in this widget.
0221 */
0222 void XYDifferentiationCurveDock::setCurves(QList<XYCurve*> list) {
0223     m_initializing = true;
0224     m_curvesList = list;
0225     m_curve = list.first();
0226     m_aspect = m_curve;
0227     m_differentiationCurve = dynamic_cast<XYDifferentiationCurve*>(m_curve);
0228     m_aspectTreeModel = new AspectTreeModel(m_curve->project());
0229     this->setModel();
0230     m_differentiationData = m_differentiationCurve->differentiationData();
0231 
0232     SET_NUMBER_LOCALE
0233     uiGeneralTab.sbMin->setLocale(numberLocale);
0234     uiGeneralTab.sbMax->setLocale(numberLocale);
0235 
0236     initGeneralTab();
0237     initTabs();
0238     m_initializing = false;
0239 
0240     //hide the "skip gaps" option after the curves were set
0241     ui.lLineSkipGaps->hide();
0242     ui.chkLineSkipGaps->hide();
0243 }
0244 
0245 //*************************************************************
0246 //**** SLOTs for changes triggered in XYFitCurveDock *****
0247 //*************************************************************
0248 void XYDifferentiationCurveDock::dataSourceTypeChanged(int index) {
0249     const auto type = (XYAnalysisCurve::DataSourceType)index;
0250     if (type == XYAnalysisCurve::DataSourceType::Spreadsheet) {
0251         uiGeneralTab.lDataSourceCurve->hide();
0252         cbDataSourceCurve->hide();
0253         uiGeneralTab.lXColumn->show();
0254         cbXDataColumn->show();
0255         uiGeneralTab.lYColumn->show();
0256         cbYDataColumn->show();
0257     } else {
0258         uiGeneralTab.lDataSourceCurve->show();
0259         cbDataSourceCurve->show();
0260         uiGeneralTab.lXColumn->hide();
0261         cbXDataColumn->hide();
0262         uiGeneralTab.lYColumn->hide();
0263         cbYDataColumn->hide();
0264     }
0265 
0266     if (m_initializing)
0267         return;
0268 
0269     for (auto* curve : m_curvesList)
0270         dynamic_cast<XYDifferentiationCurve*>(curve)->setDataSourceType(type);
0271 }
0272 
0273 void XYDifferentiationCurveDock::dataSourceCurveChanged(const QModelIndex& index) {
0274     auto* aspect = static_cast<AbstractAspect*>(index.internalPointer());
0275     auto* dataSourceCurve = dynamic_cast<XYCurve*>(aspect);
0276 
0277     // disable deriv orders and accuracies that need more data points
0278     this->updateSettings(dataSourceCurve->xColumn());
0279 
0280     if (m_initializing)
0281         return;
0282 
0283     for (auto* curve : m_curvesList)
0284         dynamic_cast<XYDifferentiationCurve*>(curve)->setDataSourceCurve(dataSourceCurve);
0285 }
0286 
0287 void XYDifferentiationCurveDock::xDataColumnChanged(const QModelIndex& index) {
0288     if (m_initializing)
0289         return;
0290 
0291     auto* aspect = static_cast<AbstractAspect*>(index.internalPointer());
0292     auto* column = dynamic_cast<AbstractColumn*>(aspect);
0293 
0294     // disable deriv orders and accuracies that need more data points
0295     this->updateSettings(column);
0296 
0297     if (m_initializing)
0298         return;
0299 
0300     for (auto* curve : m_curvesList)
0301         dynamic_cast<XYDifferentiationCurve*>(curve)->setXDataColumn(column);
0302 
0303     cbXDataColumn->useCurrentIndexText(true);
0304     cbXDataColumn->setInvalid(false);
0305 }
0306 
0307 void XYDifferentiationCurveDock::yDataColumnChanged(const QModelIndex& index) {
0308     if (m_initializing)
0309         return;
0310 
0311     auto* aspect = static_cast<AbstractAspect*>(index.internalPointer());
0312     auto* column = dynamic_cast<AbstractColumn*>(aspect);
0313 
0314     for (auto* curve : m_curvesList)
0315         dynamic_cast<XYDifferentiationCurve*>(curve)->setYDataColumn(column);
0316 
0317     cbYDataColumn->useCurrentIndexText(true);
0318     cbYDataColumn->setInvalid(false);
0319 }
0320 
0321 /*!
0322  * disable deriv orders and accuracies that need more data points
0323  */
0324 void XYDifferentiationCurveDock::updateSettings(const AbstractColumn* column) {
0325     if (!column)
0326         return;
0327 
0328     if (uiGeneralTab.cbAutoRange->isChecked()) {
0329         uiGeneralTab.sbMin->setValue(column->minimum());
0330         uiGeneralTab.sbMax->setValue(column->maximum());
0331     }
0332 
0333     size_t n = 0;
0334     for (int row = 0; row < column->rowCount(); ++row)
0335         if (!std::isnan(column->valueAt(row)) && !column->isMasked(row))
0336             n++;
0337 
0338     const auto* model = qobject_cast<const QStandardItemModel*>(uiGeneralTab.cbDerivOrder->model());
0339     QStandardItem* item = model->item(nsl_diff_deriv_order_first);
0340     if (n < 3)
0341         item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
0342     else {
0343         item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
0344         if (n < 5)
0345             uiGeneralTab.sbAccOrder->setMinimum(2);
0346     }
0347 
0348     item = model->item(nsl_diff_deriv_order_second);
0349     if (n < 3) {
0350         item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
0351         if (uiGeneralTab.cbDerivOrder->currentIndex() == nsl_diff_deriv_order_second)
0352                 uiGeneralTab.cbDerivOrder->setCurrentIndex(nsl_diff_deriv_order_first);
0353     }
0354     else {
0355         item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
0356         if (n < 4)
0357             uiGeneralTab.sbAccOrder->setMinimum(1);
0358         else if (n < 5)
0359             uiGeneralTab.sbAccOrder->setMinimum(2);
0360     }
0361 
0362     item = model->item(nsl_diff_deriv_order_third);
0363     if (n < 5) {
0364         item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
0365         if (uiGeneralTab.cbDerivOrder->currentIndex() == nsl_diff_deriv_order_third)
0366                 uiGeneralTab.cbDerivOrder->setCurrentIndex(nsl_diff_deriv_order_first);
0367     }
0368     else
0369         item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
0370 
0371     item = model->item(nsl_diff_deriv_order_fourth);
0372     if (n < 5) {
0373         item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
0374         if (uiGeneralTab.cbDerivOrder->currentIndex() == nsl_diff_deriv_order_fourth)
0375                 uiGeneralTab.cbDerivOrder->setCurrentIndex(nsl_diff_deriv_order_first);
0376     }
0377     else {
0378         item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
0379         if (n < 7)
0380             uiGeneralTab.sbAccOrder->setMinimum(1);
0381     }
0382 
0383     item = model->item(nsl_diff_deriv_order_fifth);
0384     if (n < 7) {
0385         item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
0386         if (uiGeneralTab.cbDerivOrder->currentIndex() == nsl_diff_deriv_order_fifth)
0387                 uiGeneralTab.cbDerivOrder->setCurrentIndex(nsl_diff_deriv_order_first);
0388     }
0389     else
0390         item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
0391 
0392     item = model->item(nsl_diff_deriv_order_sixth);
0393     if (n < 7) {
0394         item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
0395         if (uiGeneralTab.cbDerivOrder->currentIndex() == nsl_diff_deriv_order_sixth)
0396                 uiGeneralTab.cbDerivOrder->setCurrentIndex(nsl_diff_deriv_order_first);
0397     }
0398     else
0399         item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
0400 }
0401 
0402 void XYDifferentiationCurveDock::autoRangeChanged() {
0403     bool autoRange = uiGeneralTab.cbAutoRange->isChecked();
0404     m_differentiationData.autoRange = autoRange;
0405 
0406     uiGeneralTab.lMin->setEnabled(!autoRange);
0407     uiGeneralTab.sbMin->setEnabled(!autoRange);
0408     uiGeneralTab.lMax->setEnabled(!autoRange);
0409     uiGeneralTab.sbMax->setEnabled(!autoRange);
0410     uiGeneralTab.lMinDateTime->setEnabled(!autoRange);
0411     uiGeneralTab.dateTimeEditMin->setEnabled(!autoRange);
0412     uiGeneralTab.lMaxDateTime->setEnabled(!autoRange);
0413     uiGeneralTab.dateTimeEditMax->setEnabled(!autoRange);
0414 
0415     if (autoRange) {
0416         const AbstractColumn* xDataColumn = nullptr;
0417         if (m_differentiationCurve->dataSourceType() == XYAnalysisCurve::DataSourceType::Spreadsheet)
0418             xDataColumn = m_differentiationCurve->xDataColumn();
0419         else {
0420             if (m_differentiationCurve->dataSourceCurve())
0421                 xDataColumn = m_differentiationCurve->dataSourceCurve()->xColumn();
0422         }
0423 
0424         if (xDataColumn) {
0425             if (!m_dateTimeRange) {
0426                 uiGeneralTab.sbMin->setValue(xDataColumn->minimum());
0427                 uiGeneralTab.sbMax->setValue(xDataColumn->maximum());
0428             } else {
0429                 uiGeneralTab.dateTimeEditMin->setDateTime(QDateTime::fromMSecsSinceEpoch(xDataColumn->minimum()));
0430                 uiGeneralTab.dateTimeEditMax->setDateTime(QDateTime::fromMSecsSinceEpoch(xDataColumn->maximum()));
0431             }
0432         }
0433     }
0434 }
0435 
0436 void XYDifferentiationCurveDock::xRangeMinChanged(double value) {
0437     m_differentiationData.xRange.first() = value;
0438     uiGeneralTab.pbRecalculate->setEnabled(true);
0439 }
0440 
0441 void XYDifferentiationCurveDock::xRangeMaxChanged(double value) {
0442     m_differentiationData.xRange.last() = value;
0443     uiGeneralTab.pbRecalculate->setEnabled(true);
0444 }
0445 
0446 void XYDifferentiationCurveDock::xRangeMinDateTimeChanged(const QDateTime& dateTime) {
0447     if (m_initializing)
0448         return;
0449 
0450     m_differentiationData.xRange.first() = dateTime.toMSecsSinceEpoch();
0451     uiGeneralTab.pbRecalculate->setEnabled(true);
0452 }
0453 
0454 void XYDifferentiationCurveDock::xRangeMaxDateTimeChanged(const QDateTime& dateTime) {
0455     if (m_initializing)
0456         return;
0457 
0458     m_differentiationData.xRange.last() = dateTime.toMSecsSinceEpoch();
0459     uiGeneralTab.pbRecalculate->setEnabled(true);
0460 }
0461 
0462 void XYDifferentiationCurveDock::derivOrderChanged(int index) {
0463     const auto derivOrder = (nsl_diff_deriv_order_type)index;
0464     m_differentiationData.derivOrder = derivOrder;
0465 
0466     // update avail. accuracies
0467     switch (derivOrder) {
0468     case nsl_diff_deriv_order_first:
0469         uiGeneralTab.sbAccOrder->setMinimum(2);
0470         uiGeneralTab.sbAccOrder->setMaximum(4);
0471         uiGeneralTab.sbAccOrder->setSingleStep(2);
0472         uiGeneralTab.sbAccOrder->setValue(4);
0473         break;
0474     case nsl_diff_deriv_order_second:
0475         uiGeneralTab.sbAccOrder->setMinimum(1);
0476         uiGeneralTab.sbAccOrder->setMaximum(3);
0477         uiGeneralTab.sbAccOrder->setSingleStep(1);
0478         uiGeneralTab.sbAccOrder->setValue(3);
0479         break;
0480     case nsl_diff_deriv_order_third:
0481         uiGeneralTab.sbAccOrder->setMinimum(2);
0482         uiGeneralTab.sbAccOrder->setMaximum(2);
0483         break;
0484     case nsl_diff_deriv_order_fourth:
0485         uiGeneralTab.sbAccOrder->setMinimum(1);
0486         uiGeneralTab.sbAccOrder->setMaximum(3);
0487         uiGeneralTab.sbAccOrder->setSingleStep(2);
0488         uiGeneralTab.sbAccOrder->setValue(3);
0489         break;
0490     case nsl_diff_deriv_order_fifth:
0491         uiGeneralTab.sbAccOrder->setMinimum(2);
0492         uiGeneralTab.sbAccOrder->setMaximum(2);
0493         break;
0494     case nsl_diff_deriv_order_sixth:
0495         uiGeneralTab.sbAccOrder->setMinimum(1);
0496         uiGeneralTab.sbAccOrder->setMaximum(1);
0497         break;
0498     }
0499 
0500     uiGeneralTab.pbRecalculate->setEnabled(true);
0501 }
0502 
0503 void XYDifferentiationCurveDock::accOrderChanged(int value) {
0504     m_differentiationData.accOrder = value;
0505     uiGeneralTab.pbRecalculate->setEnabled(true);
0506 }
0507 
0508 void XYDifferentiationCurveDock::recalculateClicked() {
0509     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
0510 
0511     for (auto* curve : m_curvesList)
0512         if (curve != nullptr)
0513             dynamic_cast<XYDifferentiationCurve*>(curve)->setDifferentiationData(m_differentiationData);
0514 
0515     uiGeneralTab.pbRecalculate->setEnabled(false);
0516     emit info(i18n("Differentiation status: %1", m_differentiationCurve->differentiationResult().status));
0517     QApplication::restoreOverrideCursor();
0518 }
0519 
0520 void XYDifferentiationCurveDock::enableRecalculate() const {
0521     if (m_initializing)
0522         return;
0523 
0524     //no differentiation possible without the x- and y-data
0525     bool hasSourceData = false;
0526     if (m_differentiationCurve->dataSourceType() == XYAnalysisCurve::DataSourceType::Spreadsheet) {
0527         AbstractAspect* aspectX = static_cast<AbstractAspect*>(cbXDataColumn->currentModelIndex().internalPointer());
0528         AbstractAspect* aspectY = static_cast<AbstractAspect*>(cbYDataColumn->currentModelIndex().internalPointer());
0529         hasSourceData = (aspectX != nullptr && aspectY != nullptr);
0530         if (aspectX) {
0531             cbXDataColumn->useCurrentIndexText(true);
0532             cbXDataColumn->setInvalid(false);
0533         }
0534         if (aspectY) {
0535             cbYDataColumn->useCurrentIndexText(true);
0536             cbYDataColumn->setInvalid(false);
0537         }
0538     } else {
0539          hasSourceData = (m_differentiationCurve->dataSourceCurve() != nullptr);
0540     }
0541 
0542     uiGeneralTab.pbRecalculate->setEnabled(hasSourceData);
0543 }
0544 
0545 /*!
0546  * show the result and details of the differentiation
0547  */
0548 void XYDifferentiationCurveDock::showDifferentiationResult() {
0549     const XYDifferentiationCurve::DifferentiationResult& differentiationResult = m_differentiationCurve->differentiationResult();
0550     if (!differentiationResult.available) {
0551         uiGeneralTab.teResult->clear();
0552         return;
0553     }
0554 
0555     QString str = i18n("status: %1", differentiationResult.status) + "<br>";
0556 
0557     if (!differentiationResult.valid) {
0558         uiGeneralTab.teResult->setText(str);
0559         return; //result is not valid, there was an error which is shown in the status-string, nothing to show more.
0560     }
0561 
0562     SET_NUMBER_LOCALE
0563     if (differentiationResult.elapsedTime > 1000)
0564         str += i18n("calculation time: %1 s", numberLocale.toString(differentiationResult.elapsedTime/1000)) + "<br>";
0565     else
0566         str += i18n("calculation time: %1 ms", numberLocale.toString(differentiationResult.elapsedTime)) + "<br>";
0567 
0568     str += "<br><br>";
0569 
0570     uiGeneralTab.teResult->setText(str);
0571 
0572     //enable the "recalculate"-button if the source data was changed since the last differentiation
0573     uiGeneralTab.pbRecalculate->setEnabled(m_differentiationCurve->isSourceDataChangedSinceLastRecalc());
0574 }
0575 
0576 //*************************************************************
0577 //*** SLOTs for changes triggered in XYDifferentiationCurve ***
0578 //*************************************************************
0579 //General-Tab
0580 void XYDifferentiationCurveDock::curveDescriptionChanged(const AbstractAspect* aspect) {
0581     if (m_curve != aspect)
0582         return;
0583 
0584     m_initializing = true;
0585     if (aspect->name() != uiGeneralTab.leName->text())
0586         uiGeneralTab.leName->setText(aspect->name());
0587     else if (aspect->comment() != uiGeneralTab.leComment->text())
0588         uiGeneralTab.leComment->setText(aspect->comment());
0589     m_initializing = false;
0590 }
0591 
0592 void XYDifferentiationCurveDock::curveDataSourceTypeChanged(XYAnalysisCurve::DataSourceType type) {
0593     m_initializing = true;
0594     uiGeneralTab.cbDataSourceType->setCurrentIndex(static_cast<int>(type));
0595     m_initializing = false;
0596 }
0597 
0598 void XYDifferentiationCurveDock::curveDataSourceCurveChanged(const XYCurve* curve) {
0599     m_initializing = true;
0600     XYCurveDock::setModelIndexFromAspect(cbDataSourceCurve, curve);
0601     m_initializing = false;
0602 }
0603 
0604 void XYDifferentiationCurveDock::curveXDataColumnChanged(const AbstractColumn* column) {
0605     m_initializing = true;
0606     XYCurveDock::setModelIndexFromAspect(cbXDataColumn, column);
0607     m_initializing = false;
0608 }
0609 
0610 void XYDifferentiationCurveDock::curveYDataColumnChanged(const AbstractColumn* column) {
0611     m_initializing = true;
0612     XYCurveDock::setModelIndexFromAspect(cbYDataColumn, column);
0613     m_initializing = false;
0614 }
0615 
0616 void XYDifferentiationCurveDock::curveDifferentiationDataChanged(const XYDifferentiationCurve::DifferentiationData& differentiationData) {
0617     m_initializing = true;
0618     m_differentiationData = differentiationData;
0619     uiGeneralTab.cbDerivOrder->setCurrentIndex(m_differentiationData.derivOrder);
0620     this->derivOrderChanged(m_differentiationData.derivOrder);
0621     uiGeneralTab.sbAccOrder->setValue(m_differentiationData.accOrder);
0622     this->accOrderChanged(m_differentiationData.accOrder);
0623 
0624     this->showDifferentiationResult();
0625     m_initializing = false;
0626 }
0627 
0628 void XYDifferentiationCurveDock::dataChanged() {
0629     this->enableRecalculate();
0630 }
0631 
0632 void XYDifferentiationCurveDock::curveVisibilityChanged(bool on) {
0633     m_initializing = true;
0634     uiGeneralTab.chkVisible->setChecked(on);
0635     m_initializing = false;
0636 }