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

0001 /***************************************************************************
0002     File             : XYDataReductionCurveDock.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 data reduction 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 "XYDataReductionCurveDock.h"
0031 #include "backend/core/AspectTreeModel.h"
0032 #include "backend/core/Project.h"
0033 #include "backend/worksheet/plots/cartesian/XYDataReductionCurve.h"
0034 #include "commonfrontend/widgets/TreeViewComboBox.h"
0035 
0036 #include <QMenu>
0037 #include <QWidgetAction>
0038 #include <QStandardItemModel>
0039 #include <QStatusBar>
0040 #include <QProgressBar>
0041 
0042 /*!
0043   \class XYDataReductionCurveDock
0044  \brief  Provides a widget for editing the properties of the XYDataReductionCurves
0045         (2D-curves defined by an data reduction) currently selected in
0046         the project explorer.
0047 
0048   If more then 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 XYDataReductionCurveDock::XYDataReductionCurveDock(QWidget* parent, QStatusBar* sb) : XYCurveDock(parent), statusBar(sb) {
0057 }
0058 
0059 /*!
0060  *  // Tab "General"
0061  */
0062 void XYDataReductionCurveDock::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_GEOM_LINESIM_TYPE_COUNT; ++i)
0084         uiGeneralTab.cbType->addItem(i18n(nsl_geom_linesim_type_name[i]));
0085     uiGeneralTab.cbType->setItemData(nsl_geom_linesim_type_visvalingam_whyatt, i18n("This method is much slower than any other"), Qt::ToolTipRole);
0086 
0087     uiGeneralTab.sbMin->setRange(-std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
0088     uiGeneralTab.sbMax->setRange(-std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
0089     uiGeneralTab.sbTolerance->setRange(0.0, std::numeric_limits<double>::max());
0090     uiGeneralTab.sbTolerance2->setRange(0.0, std::numeric_limits<double>::max());
0091 
0092     uiGeneralTab.pbRecalculate->setIcon(QIcon::fromTheme("run-build"));
0093 
0094     auto* layout = new QHBoxLayout(ui.tabGeneral);
0095     layout->setMargin(0);
0096     layout->addWidget(generalTab);
0097 
0098     //Slots
0099     connect(uiGeneralTab.chkVisible, &QCheckBox::clicked, this, &XYDataReductionCurveDock::visibilityChanged);
0100     connect(uiGeneralTab.cbDataSourceType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &XYDataReductionCurveDock::dataSourceTypeChanged);
0101     connect(uiGeneralTab.cbAutoRange, &QCheckBox::clicked, this, &XYDataReductionCurveDock::autoRangeChanged);
0102     connect(uiGeneralTab.sbMin, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &XYDataReductionCurveDock::xRangeMinChanged);
0103     connect(uiGeneralTab.sbMax, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &XYDataReductionCurveDock::xRangeMaxChanged);
0104     connect(uiGeneralTab.dateTimeEditMin, &QDateTimeEdit::dateTimeChanged, this, &XYDataReductionCurveDock::xRangeMinDateTimeChanged);
0105     connect(uiGeneralTab.dateTimeEditMax, &QDateTimeEdit::dateTimeChanged, this, &XYDataReductionCurveDock::xRangeMaxDateTimeChanged);
0106     connect(uiGeneralTab.chkAuto, &QCheckBox::clicked, this, &XYDataReductionCurveDock::autoToleranceChanged);
0107     connect(uiGeneralTab.sbTolerance, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &XYDataReductionCurveDock::toleranceChanged);
0108     connect(uiGeneralTab.chkAuto2, &QCheckBox::clicked, this, &XYDataReductionCurveDock::autoTolerance2Changed);
0109     connect(uiGeneralTab.sbTolerance2, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &XYDataReductionCurveDock::tolerance2Changed);
0110     connect(uiGeneralTab.pbRecalculate, &QPushButton::clicked, this, &XYDataReductionCurveDock::recalculateClicked);
0111 
0112     connect(cbDataSourceCurve, &TreeViewComboBox::currentModelIndexChanged, this, &XYDataReductionCurveDock::dataSourceCurveChanged);
0113     connect(cbXDataColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYDataReductionCurveDock::xDataColumnChanged);
0114     connect(cbYDataColumn, &TreeViewComboBox::currentModelIndexChanged, this, &XYDataReductionCurveDock::yDataColumnChanged);
0115 }
0116 
0117 void XYDataReductionCurveDock::initGeneralTab() {
0118     //if there are more then one curve in the list, disable the tab "general"
0119     if (m_curvesList.size() == 1) {
0120         uiGeneralTab.lName->setEnabled(true);
0121         uiGeneralTab.leName->setEnabled(true);
0122         uiGeneralTab.lComment->setEnabled(true);
0123         uiGeneralTab.leComment->setEnabled(true);
0124 
0125         uiGeneralTab.leName->setText(m_curve->name());
0126         uiGeneralTab.leComment->setText(m_curve->comment());
0127     } else {
0128         uiGeneralTab.lName->setEnabled(false);
0129         uiGeneralTab.leName->setEnabled(false);
0130         uiGeneralTab.lComment->setEnabled(false);
0131         uiGeneralTab.leComment->setEnabled(false);
0132 
0133         uiGeneralTab.leName->setText(QString());
0134         uiGeneralTab.leComment->setText(QString());
0135     }
0136 
0137     //show the properties of the first curve
0138     m_dataReductionCurve = dynamic_cast<XYDataReductionCurve*>(m_curve);
0139     checkColumnAvailability(cbXDataColumn, m_dataReductionCurve->xDataColumn(), m_dataReductionCurve->xDataColumnPath());
0140     checkColumnAvailability(cbYDataColumn, m_dataReductionCurve->yDataColumn(), m_dataReductionCurve->yDataColumnPath());
0141 
0142     //data source
0143     uiGeneralTab.cbDataSourceType->setCurrentIndex(static_cast<int>(m_dataReductionCurve->dataSourceType()));
0144     this->dataSourceTypeChanged(uiGeneralTab.cbDataSourceType->currentIndex());
0145     XYCurveDock::setModelIndexFromAspect(cbDataSourceCurve, m_dataReductionCurve->dataSourceCurve());
0146     XYCurveDock::setModelIndexFromAspect(cbXDataColumn, m_dataReductionCurve->xDataColumn());
0147     XYCurveDock::setModelIndexFromAspect(cbYDataColumn, m_dataReductionCurve->yDataColumn());
0148 
0149     //range widgets
0150     const auto* plot = static_cast<const CartesianPlot*>(m_dataReductionCurve->parentAspect());
0151     m_dateTimeRange = (plot->xRangeFormat() != CartesianPlot::RangeFormat::Numeric);
0152     if (!m_dateTimeRange) {
0153         uiGeneralTab.sbMin->setValue(m_dataReductionData.xRange.first());
0154         uiGeneralTab.sbMax->setValue(m_dataReductionData.xRange.last());
0155     } else {
0156         uiGeneralTab.dateTimeEditMin->setDateTime( QDateTime::fromMSecsSinceEpoch(m_dataReductionData.xRange.first()) );
0157         uiGeneralTab.dateTimeEditMax->setDateTime( QDateTime::fromMSecsSinceEpoch(m_dataReductionData.xRange.last()) );
0158     }
0159 
0160     uiGeneralTab.lMin->setVisible(!m_dateTimeRange);
0161     uiGeneralTab.sbMin->setVisible(!m_dateTimeRange);
0162     uiGeneralTab.lMax->setVisible(!m_dateTimeRange);
0163     uiGeneralTab.sbMax->setVisible(!m_dateTimeRange);
0164     uiGeneralTab.lMinDateTime->setVisible(m_dateTimeRange);
0165     uiGeneralTab.dateTimeEditMin->setVisible(m_dateTimeRange);
0166     uiGeneralTab.lMaxDateTime->setVisible(m_dateTimeRange);
0167     uiGeneralTab.dateTimeEditMax->setVisible(m_dateTimeRange);
0168 
0169     //auto range
0170     uiGeneralTab.cbAutoRange->setChecked(m_dataReductionData.autoRange);
0171     this->autoRangeChanged();
0172 
0173     // update list of selectable types
0174     xDataColumnChanged(cbXDataColumn->currentModelIndex());
0175 
0176     uiGeneralTab.cbType->setCurrentIndex(m_dataReductionData.type);
0177     this->typeChanged(m_dataReductionData.type);
0178     uiGeneralTab.chkAuto->setChecked(m_dataReductionData.autoTolerance);
0179     this->autoToleranceChanged();
0180     uiGeneralTab.sbTolerance->setValue(m_dataReductionData.tolerance);
0181     this->toleranceChanged(m_dataReductionData.tolerance);
0182     uiGeneralTab.chkAuto2->setChecked(m_dataReductionData.autoTolerance2);
0183     this->autoTolerance2Changed();
0184     uiGeneralTab.sbTolerance2->setValue(m_dataReductionData.tolerance2);
0185     this->tolerance2Changed(m_dataReductionData.tolerance2);
0186 
0187     this->showDataReductionResult();
0188 
0189     //enable the "recalculate"-button if the source data was changed since the last dataReduction
0190     uiGeneralTab.pbRecalculate->setEnabled(m_dataReductionCurve->isSourceDataChangedSinceLastRecalc());
0191 
0192     uiGeneralTab.chkVisible->setChecked( m_curve->isVisible() );
0193 
0194     //Slots
0195     connect(m_dataReductionCurve, &XYDataReductionCurve::aspectDescriptionChanged, this, &XYDataReductionCurveDock::curveDescriptionChanged);
0196     connect(m_dataReductionCurve, &XYDataReductionCurve::dataSourceTypeChanged, this, &XYDataReductionCurveDock::curveDataSourceTypeChanged);
0197     connect(m_dataReductionCurve, &XYDataReductionCurve::dataSourceCurveChanged, this, &XYDataReductionCurveDock::curveDataSourceCurveChanged);
0198     connect(m_dataReductionCurve, &XYDataReductionCurve::xDataColumnChanged, this, &XYDataReductionCurveDock::curveXDataColumnChanged);
0199     connect(m_dataReductionCurve, &XYDataReductionCurve::yDataColumnChanged, this, &XYDataReductionCurveDock::curveYDataColumnChanged);
0200     connect(m_dataReductionCurve, &XYDataReductionCurve::dataReductionDataChanged, this, &XYDataReductionCurveDock::curveDataReductionDataChanged);
0201     connect(m_dataReductionCurve, &XYDataReductionCurve::sourceDataChanged, this, &XYDataReductionCurveDock::enableRecalculate);
0202     connect(m_dataReductionCurve, QOverload<bool>::of(&XYCurve::visibilityChanged), this, &XYDataReductionCurveDock::curveVisibilityChanged);
0203 }
0204 
0205 void XYDataReductionCurveDock::setModel() {
0206     QList<AspectType>  list{AspectType::Folder, AspectType::Datapicker, AspectType::Worksheet,
0207                             AspectType::CartesianPlot, AspectType::XYCurve, AspectType::XYAnalysisCurve};
0208     cbDataSourceCurve->setTopLevelClasses(list);
0209 
0210     QList<const AbstractAspect*> hiddenAspects;
0211     for (auto* curve : m_curvesList)
0212         hiddenAspects << curve;
0213     cbDataSourceCurve->setHiddenAspects(hiddenAspects);
0214 
0215     list = {AspectType::Folder, AspectType::Workbook, AspectType::Datapicker,
0216             AspectType::DatapickerCurve, AspectType::Spreadsheet, AspectType::LiveDataSource,
0217             AspectType::Column, AspectType::Worksheet, AspectType::CartesianPlot,
0218             AspectType::XYFitCurve
0219            };
0220     cbXDataColumn->setTopLevelClasses(list);
0221     cbYDataColumn->setTopLevelClasses(list);
0222 
0223     cbDataSourceCurve->setModel(m_aspectTreeModel);
0224     cbXDataColumn->setModel(m_aspectTreeModel);
0225     cbYDataColumn->setModel(m_aspectTreeModel);
0226 
0227     XYCurveDock::setModel();
0228 }
0229 
0230 /*!
0231   sets the curves. The properties of the curves in the list \c list can be edited in this widget.
0232 */
0233 void XYDataReductionCurveDock::setCurves(QList<XYCurve*> list) {
0234     m_initializing = true;
0235     m_curvesList = list;
0236     m_curve = list.first();
0237     m_aspect = m_curve;
0238     m_dataReductionCurve = dynamic_cast<XYDataReductionCurve*>(m_curve);
0239     m_aspectTreeModel = new AspectTreeModel(m_curve->project());
0240     this->setModel();
0241     m_dataReductionData = m_dataReductionCurve->dataReductionData();
0242 
0243     SET_NUMBER_LOCALE
0244     uiGeneralTab.sbMin->setLocale(numberLocale);
0245     uiGeneralTab.sbMax->setLocale(numberLocale);
0246     uiGeneralTab.sbTolerance->setLocale(numberLocale);
0247     uiGeneralTab.sbTolerance2->setLocale(numberLocale);
0248 
0249     initGeneralTab();
0250     initTabs();
0251     m_initializing = false;
0252 
0253     //hide the "skip gaps" option after the curves were set
0254     ui.lLineSkipGaps->hide();
0255     ui.chkLineSkipGaps->hide();
0256 }
0257 
0258 //*************************************************************
0259 //**** SLOTs for changes triggered in XYFitCurveDock *****
0260 //*************************************************************
0261 void XYDataReductionCurveDock::dataSourceTypeChanged(int index) {
0262     const auto type = (XYAnalysisCurve::DataSourceType)index;
0263     if (type == XYAnalysisCurve::DataSourceType::Spreadsheet) {
0264         uiGeneralTab.lDataSourceCurve->hide();
0265         cbDataSourceCurve->hide();
0266         uiGeneralTab.lXColumn->show();
0267         cbXDataColumn->show();
0268         uiGeneralTab.lYColumn->show();
0269         cbYDataColumn->show();
0270     } else {
0271         uiGeneralTab.lDataSourceCurve->show();
0272         cbDataSourceCurve->show();
0273         uiGeneralTab.lXColumn->hide();
0274         cbXDataColumn->hide();
0275         uiGeneralTab.lYColumn->hide();
0276         cbYDataColumn->hide();
0277     }
0278 
0279     if (m_initializing)
0280         return;
0281 
0282     for (auto* curve : m_curvesList)
0283         dynamic_cast<XYDataReductionCurve*>(curve)->setDataSourceType(type);
0284 }
0285 
0286 void XYDataReductionCurveDock::dataSourceCurveChanged(const QModelIndex& index) {
0287     auto* aspect = static_cast<AbstractAspect*>(index.internalPointer());
0288     auto* dataSourceCurve = dynamic_cast<XYCurve*>(aspect);
0289 
0290 //  // disable deriv orders and accuracies that need more data points
0291 //  this->updateSettings(dataSourceCurve->xColumn());
0292 
0293     if (m_initializing)
0294         return;
0295 
0296     for (auto* curve : m_curvesList)
0297         dynamic_cast<XYDataReductionCurve*>(curve)->setDataSourceCurve(dataSourceCurve);
0298 }
0299 
0300 void XYDataReductionCurveDock::xDataColumnChanged(const QModelIndex& index) {
0301     if (m_initializing)
0302         return;
0303 
0304     auto* aspect = static_cast<AbstractAspect*>(index.internalPointer());
0305     auto* column = dynamic_cast<AbstractColumn*>(aspect);
0306 
0307     for (auto* curve : m_curvesList)
0308         dynamic_cast<XYDataReductionCurve*>(curve)->setXDataColumn(column);
0309 
0310     //TODO: this->updateSettings(column); ?
0311     if (column != nullptr && uiGeneralTab.cbAutoRange->isChecked()) {
0312         uiGeneralTab.sbMin->setValue(column->minimum());
0313         uiGeneralTab.sbMax->setValue(column->maximum());
0314     }
0315 
0316     cbXDataColumn->useCurrentIndexText(true);
0317     cbXDataColumn->setInvalid(false);
0318 
0319     updateTolerance();
0320     updateTolerance2();
0321 }
0322 
0323 void XYDataReductionCurveDock::yDataColumnChanged(const QModelIndex& index) {
0324     if (m_initializing)
0325         return;
0326 
0327     auto* aspect = static_cast<AbstractAspect*>(index.internalPointer());
0328     auto* column = dynamic_cast<AbstractColumn*>(aspect);
0329 
0330     for (auto* curve : m_curvesList)
0331         dynamic_cast<XYDataReductionCurve*>(curve)->setYDataColumn(column);
0332 
0333     cbYDataColumn->useCurrentIndexText(true);
0334     cbYDataColumn->setInvalid(false);
0335 
0336     updateTolerance();
0337     updateTolerance2();
0338 }
0339 
0340 void XYDataReductionCurveDock::updateTolerance() {
0341     const AbstractColumn* xDataColumn = nullptr;
0342     const AbstractColumn* yDataColumn = nullptr;
0343     if (m_dataReductionCurve->dataSourceType() == XYAnalysisCurve::DataSourceType::Spreadsheet) {
0344         xDataColumn = m_dataReductionCurve->xDataColumn();
0345         yDataColumn = m_dataReductionCurve->yDataColumn();
0346     } else {
0347         if (m_dataReductionCurve->dataSourceCurve()) {
0348             xDataColumn = m_dataReductionCurve->dataSourceCurve()->xColumn();
0349             yDataColumn = m_dataReductionCurve->dataSourceCurve()->yColumn();
0350         }
0351     }
0352 
0353     if (xDataColumn == nullptr || yDataColumn == nullptr)
0354         return;
0355 
0356     //copy all valid data points for calculating tolerance to temporary vectors
0357     QVector<double> xdataVector;
0358     QVector<double> ydataVector;
0359     const double xmin = m_dataReductionData.xRange.first();
0360     const double xmax = m_dataReductionData.xRange.last();
0361     XYAnalysisCurve::copyData(xdataVector, ydataVector, xDataColumn, yDataColumn, xmin, xmax);
0362 
0363     if (xdataVector.size() > 1)
0364         uiGeneralTab.cbType->setEnabled(true);
0365     else {
0366         uiGeneralTab.cbType->setEnabled(false);
0367         return;
0368     }
0369     DEBUG("automatic tolerance:");
0370     DEBUG("clip_diag_perpoint =" << nsl_geom_linesim_clip_diag_perpoint(xdataVector.data(), ydataVector.data(), (size_t)xdataVector.size()));
0371     DEBUG("clip_area_perpoint =" << nsl_geom_linesim_clip_area_perpoint(xdataVector.data(), ydataVector.data(), (size_t)xdataVector.size()));
0372     DEBUG("avg_dist_perpoint =" << nsl_geom_linesim_avg_dist_perpoint(xdataVector.data(), ydataVector.data(), (size_t)xdataVector.size()));
0373 
0374     const auto type = (nsl_geom_linesim_type)uiGeneralTab.cbType->currentIndex();
0375     if (type == nsl_geom_linesim_type_raddist || type == nsl_geom_linesim_type_opheim)
0376         m_dataReductionData.tolerance = 10. * nsl_geom_linesim_clip_diag_perpoint(xdataVector.data(), ydataVector.data(), (size_t)xdataVector.size());
0377     else if (type == nsl_geom_linesim_type_visvalingam_whyatt)
0378         m_dataReductionData.tolerance = 0.1 * nsl_geom_linesim_clip_area_perpoint(xdataVector.data(), ydataVector.data(), (size_t)xdataVector.size());
0379     else if (type == nsl_geom_linesim_type_douglas_peucker_variant)
0380         m_dataReductionData.tolerance = xdataVector.size()/10.; // reduction to 10%
0381     else
0382         m_dataReductionData.tolerance = 2.*nsl_geom_linesim_avg_dist_perpoint(xdataVector.data(), ydataVector.data(), xdataVector.size());
0383     //m_dataReductionData.tolerance = nsl_geom_linesim_clip_diag_perpoint(xdataVector.data(), ydataVector.data(), xdataVector.size());
0384     uiGeneralTab.sbTolerance->setValue(m_dataReductionData.tolerance);
0385 }
0386 
0387 void XYDataReductionCurveDock::updateTolerance2() {
0388     const auto type = (nsl_geom_linesim_type)uiGeneralTab.cbType->currentIndex();
0389 
0390     if (type == nsl_geom_linesim_type_perpdist)
0391         uiGeneralTab.sbTolerance2->setValue(10);
0392     else if (type == nsl_geom_linesim_type_opheim)
0393         uiGeneralTab.sbTolerance2->setValue(5*uiGeneralTab.sbTolerance->value());
0394     else if (type == nsl_geom_linesim_type_lang)
0395         uiGeneralTab.sbTolerance2->setValue(10);
0396 }
0397 
0398 void XYDataReductionCurveDock::autoRangeChanged() {
0399     bool autoRange = uiGeneralTab.cbAutoRange->isChecked();
0400     m_dataReductionData.autoRange = autoRange;
0401 
0402     uiGeneralTab.lMin->setEnabled(!autoRange);
0403     uiGeneralTab.sbMin->setEnabled(!autoRange);
0404     uiGeneralTab.lMax->setEnabled(!autoRange);
0405     uiGeneralTab.sbMax->setEnabled(!autoRange);
0406     uiGeneralTab.lMinDateTime->setEnabled(!autoRange);
0407     uiGeneralTab.dateTimeEditMin->setEnabled(!autoRange);
0408     uiGeneralTab.lMaxDateTime->setEnabled(!autoRange);
0409     uiGeneralTab.dateTimeEditMax->setEnabled(!autoRange);
0410 
0411     if (autoRange) {
0412         const AbstractColumn* xDataColumn = nullptr;
0413         if (m_dataReductionCurve->dataSourceType() == XYAnalysisCurve::DataSourceType::Spreadsheet)
0414             xDataColumn = m_dataReductionCurve->xDataColumn();
0415         else {
0416             if (m_dataReductionCurve->dataSourceCurve())
0417                 xDataColumn = m_dataReductionCurve->dataSourceCurve()->xColumn();
0418         }
0419 
0420         if (xDataColumn) {
0421             if (!m_dateTimeRange) {
0422                 uiGeneralTab.sbMin->setValue(xDataColumn->minimum());
0423                 uiGeneralTab.sbMax->setValue(xDataColumn->maximum());
0424             } else {
0425                 uiGeneralTab.dateTimeEditMin->setDateTime(QDateTime::fromMSecsSinceEpoch(xDataColumn->minimum()));
0426                 uiGeneralTab.dateTimeEditMax->setDateTime(QDateTime::fromMSecsSinceEpoch(xDataColumn->maximum()));
0427             }
0428         }
0429     }
0430 }
0431 
0432 void XYDataReductionCurveDock::xRangeMinChanged(double value) {
0433     m_dataReductionData.xRange.first() = value;
0434     uiGeneralTab.pbRecalculate->setEnabled(true);
0435 }
0436 
0437 void XYDataReductionCurveDock::xRangeMaxChanged(double value) {
0438     m_dataReductionData.xRange.last() = value;
0439     uiGeneralTab.pbRecalculate->setEnabled(true);
0440 }
0441 
0442 void XYDataReductionCurveDock::xRangeMinDateTimeChanged(const QDateTime& dateTime) {
0443     if (m_initializing)
0444         return;
0445 
0446     m_dataReductionData.xRange.first() = dateTime.toMSecsSinceEpoch();
0447     uiGeneralTab.pbRecalculate->setEnabled(true);
0448 }
0449 
0450 void XYDataReductionCurveDock::xRangeMaxDateTimeChanged(const QDateTime& dateTime) {
0451     if (m_initializing)
0452         return;
0453 
0454     m_dataReductionData.xRange.last() = dateTime.toMSecsSinceEpoch();
0455     uiGeneralTab.pbRecalculate->setEnabled(true);
0456 }
0457 
0458 void XYDataReductionCurveDock::typeChanged(int index) {
0459     const auto type = (nsl_geom_linesim_type)index;
0460     m_dataReductionData.type = type;
0461 
0462     switch (type) {
0463     case nsl_geom_linesim_type_douglas_peucker:
0464     case nsl_geom_linesim_type_raddist:
0465     case nsl_geom_linesim_type_interp:
0466     case nsl_geom_linesim_type_reumann_witkam:
0467         uiGeneralTab.lOption->setText(i18n("Tolerance (distance):"));
0468         uiGeneralTab.sbTolerance->setDecimals(6);
0469         uiGeneralTab.sbTolerance->setMinimum(0);
0470         uiGeneralTab.sbTolerance->setSingleStep(0.01);
0471         uiGeneralTab.lOption2->hide();
0472         uiGeneralTab.chkAuto2->hide();
0473         uiGeneralTab.sbTolerance2->hide();
0474         if (uiGeneralTab.chkAuto->isChecked())
0475             updateTolerance();
0476         break;
0477     case nsl_geom_linesim_type_douglas_peucker_variant:
0478         uiGeneralTab.lOption->setText(i18n("Number of points:"));
0479         uiGeneralTab.sbTolerance->setDecimals(0);
0480         uiGeneralTab.sbTolerance->setMinimum(2);
0481         uiGeneralTab.sbTolerance->setSingleStep(1);
0482         uiGeneralTab.lOption2->hide();
0483         uiGeneralTab.chkAuto2->hide();
0484         uiGeneralTab.sbTolerance2->hide();
0485         if (uiGeneralTab.chkAuto->isChecked())
0486             updateTolerance();
0487         break;
0488     case nsl_geom_linesim_type_nthpoint:
0489         uiGeneralTab.lOption->setText(i18n("Step size:"));
0490         uiGeneralTab.sbTolerance->setValue(10);
0491         uiGeneralTab.sbTolerance->setDecimals(0);
0492         uiGeneralTab.sbTolerance->setMinimum(1);
0493         uiGeneralTab.sbTolerance->setSingleStep(1);
0494         uiGeneralTab.lOption2->hide();
0495         uiGeneralTab.chkAuto2->hide();
0496         uiGeneralTab.sbTolerance2->hide();
0497         break;
0498     case nsl_geom_linesim_type_perpdist:    // repeat option
0499         uiGeneralTab.lOption->setText(i18n("Tolerance (distance):"));
0500         uiGeneralTab.sbTolerance->setDecimals(6);
0501         uiGeneralTab.sbTolerance->setMinimum(0);
0502         uiGeneralTab.sbTolerance->setSingleStep(0.01);
0503         uiGeneralTab.sbTolerance2->show();
0504         uiGeneralTab.lOption2->show();
0505         uiGeneralTab.chkAuto2->show();
0506         uiGeneralTab.lOption2->setText(i18n("Repeats:"));
0507         uiGeneralTab.sbTolerance2->setDecimals(0);
0508         uiGeneralTab.sbTolerance2->setMinimum(1);
0509         uiGeneralTab.sbTolerance2->setSingleStep(1);
0510         if (uiGeneralTab.chkAuto->isChecked())
0511             updateTolerance();
0512         if (uiGeneralTab.chkAuto2->isChecked())
0513             updateTolerance2();
0514         break;
0515     case nsl_geom_linesim_type_visvalingam_whyatt:
0516         uiGeneralTab.lOption->setText(i18n("Tolerance (area):"));
0517         uiGeneralTab.sbTolerance->setDecimals(6);
0518         uiGeneralTab.sbTolerance->setMinimum(0);
0519         uiGeneralTab.sbTolerance->setSingleStep(0.01);
0520         uiGeneralTab.lOption2->hide();
0521         uiGeneralTab.chkAuto2->hide();
0522         uiGeneralTab.sbTolerance2->hide();
0523         if (uiGeneralTab.chkAuto->isChecked())
0524             updateTolerance();
0525         break;
0526     case nsl_geom_linesim_type_opheim:  // min/max tol options
0527         uiGeneralTab.lOption->setText(i18n("Minimum tolerance:"));
0528         uiGeneralTab.sbTolerance->setDecimals(6);
0529         uiGeneralTab.sbTolerance->setMinimum(0);
0530         uiGeneralTab.sbTolerance->setSingleStep(0.01);
0531         uiGeneralTab.lOption2->setText(i18n("Maximum tolerance:"));
0532         uiGeneralTab.lOption2->show();
0533         uiGeneralTab.chkAuto2->show();
0534         uiGeneralTab.sbTolerance2->show();
0535         uiGeneralTab.sbTolerance2->setDecimals(6);
0536         uiGeneralTab.sbTolerance2->setMinimum(0);
0537         uiGeneralTab.sbTolerance2->setSingleStep(0.01);
0538         if (uiGeneralTab.chkAuto->isChecked())
0539             updateTolerance();
0540         if (uiGeneralTab.chkAuto2->isChecked())
0541             updateTolerance2();
0542         break;
0543     case nsl_geom_linesim_type_lang:    // distance/region
0544         uiGeneralTab.lOption->setText(i18n("Tolerance (distance):"));
0545         uiGeneralTab.sbTolerance->setDecimals(6);
0546         uiGeneralTab.sbTolerance->setMinimum(0);
0547         uiGeneralTab.sbTolerance->setSingleStep(0.01);
0548         uiGeneralTab.lOption2->setText(i18n("Search region:"));
0549         uiGeneralTab.lOption2->show();
0550         uiGeneralTab.chkAuto2->show();
0551         uiGeneralTab.sbTolerance2->show();
0552         uiGeneralTab.sbTolerance2->setDecimals(0);
0553         uiGeneralTab.sbTolerance2->setMinimum(1);
0554         uiGeneralTab.sbTolerance2->setSingleStep(1);
0555         if (uiGeneralTab.chkAuto->isChecked())
0556             updateTolerance();
0557         if (uiGeneralTab.chkAuto2->isChecked())
0558             updateTolerance2();
0559         break;
0560     }
0561 
0562     uiGeneralTab.pbRecalculate->setEnabled(true);
0563 }
0564 
0565 void XYDataReductionCurveDock::autoToleranceChanged() {
0566     const auto autoTolerance = (bool)uiGeneralTab.chkAuto->isChecked();
0567     m_dataReductionData.autoTolerance = autoTolerance;
0568 
0569     if (autoTolerance) {
0570         uiGeneralTab.sbTolerance->setEnabled(false);
0571         updateTolerance();
0572     } else
0573         uiGeneralTab.sbTolerance->setEnabled(true);
0574 }
0575 
0576 void XYDataReductionCurveDock::toleranceChanged(double value) {
0577     m_dataReductionData.tolerance = value;
0578     uiGeneralTab.pbRecalculate->setEnabled(true);
0579 }
0580 
0581 void XYDataReductionCurveDock::autoTolerance2Changed() {
0582     const auto autoTolerance2 = (bool)uiGeneralTab.chkAuto2->isChecked();
0583     m_dataReductionData.autoTolerance2 = autoTolerance2;
0584 
0585     if (autoTolerance2) {
0586         uiGeneralTab.sbTolerance2->setEnabled(false);
0587         updateTolerance2();
0588     } else
0589         uiGeneralTab.sbTolerance2->setEnabled(true);
0590 }
0591 
0592 void XYDataReductionCurveDock::tolerance2Changed(double value) {
0593     m_dataReductionData.tolerance2 = value;
0594     uiGeneralTab.pbRecalculate->setEnabled(true);
0595 }
0596 
0597 void XYDataReductionCurveDock::recalculateClicked() {
0598     //show a progress bar in the status bar
0599     auto* progressBar = new QProgressBar();
0600     progressBar->setMinimum(0);
0601     progressBar->setMaximum(100);
0602     connect(m_curve, SIGNAL(completed(int)), progressBar, SLOT(setValue(int)));
0603     statusBar->clearMessage();
0604     statusBar->addWidget(progressBar, 1);
0605     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
0606 
0607     for (auto* curve : m_curvesList)
0608         dynamic_cast<XYDataReductionCurve*>(curve)->setDataReductionData(m_dataReductionData);
0609 
0610     QApplication::restoreOverrideCursor();
0611     statusBar->removeWidget(progressBar);
0612 
0613     uiGeneralTab.pbRecalculate->setEnabled(false);
0614     emit info(i18n("Data reduction status: %1", m_dataReductionCurve->dataReductionResult().status));
0615 }
0616 
0617 void XYDataReductionCurveDock::enableRecalculate() const {
0618     if (m_initializing)
0619         return;
0620 
0621     //no dataReductioning possible without the x- and y-data
0622     bool hasSourceData = false;
0623     if (m_dataReductionCurve->dataSourceType() == XYAnalysisCurve::DataSourceType::Spreadsheet) {
0624         AbstractAspect* aspectX = static_cast<AbstractAspect*>(cbXDataColumn->currentModelIndex().internalPointer());
0625         AbstractAspect* aspectY = static_cast<AbstractAspect*>(cbYDataColumn->currentModelIndex().internalPointer());
0626         hasSourceData = (aspectX != nullptr && aspectY != nullptr);
0627         if (aspectX) {
0628             cbXDataColumn->useCurrentIndexText(true);
0629             cbXDataColumn->setInvalid(false);
0630         }
0631         if (aspectY) {
0632             cbYDataColumn->useCurrentIndexText(true);
0633             cbYDataColumn->setInvalid(false);
0634         }
0635     } else {
0636          hasSourceData = (m_dataReductionCurve->dataSourceCurve() != nullptr);
0637     }
0638 
0639     uiGeneralTab.pbRecalculate->setEnabled(hasSourceData);
0640 }
0641 
0642 /*!
0643  * show the result and details of the dataReduction
0644  */
0645 void XYDataReductionCurveDock::showDataReductionResult() {
0646     const XYDataReductionCurve::DataReductionResult& dataReductionResult = m_dataReductionCurve->dataReductionResult();
0647     if (!dataReductionResult.available) {
0648         uiGeneralTab.teResult->clear();
0649         return;
0650     }
0651 
0652     QString str = i18n("status: %1", dataReductionResult.status) + "<br>";
0653 
0654     if (!dataReductionResult.valid) {
0655         uiGeneralTab.teResult->setText(str);
0656         return; //result is not valid, there was an error which is shown in the status-string, nothing to show more.
0657     }
0658 
0659     SET_NUMBER_LOCALE
0660     if (dataReductionResult.elapsedTime > 1000)
0661         str += i18n("calculation time: %1 s", numberLocale.toString(dataReductionResult.elapsedTime/1000)) + "<br>";
0662     else
0663         str += i18n("calculation time: %1 ms", numberLocale.toString(dataReductionResult.elapsedTime)) + "<br>";
0664 
0665     str += "<br>";
0666 
0667     str += i18n("number of points: %1", numberLocale.toString(static_cast<qulonglong>(dataReductionResult.npoints))) + "<br>";
0668     str += i18n("positional squared error: %1", numberLocale.toString(dataReductionResult.posError)) + "<br>";
0669     str += i18n("area error: %1", numberLocale.toString(dataReductionResult.areaError)) + "<br>";
0670 
0671     uiGeneralTab.teResult->setText(str);
0672 }
0673 
0674 //*************************************************************
0675 //*********** SLOTs for changes triggered in XYCurve **********
0676 //*************************************************************
0677 //General-Tab
0678 void XYDataReductionCurveDock::curveDescriptionChanged(const AbstractAspect* aspect) {
0679     if (m_curve != aspect)
0680         return;
0681 
0682     m_initializing = true;
0683     if (aspect->name() != uiGeneralTab.leName->text())
0684         uiGeneralTab.leName->setText(aspect->name());
0685     else if (aspect->comment() != uiGeneralTab.leComment->text())
0686         uiGeneralTab.leComment->setText(aspect->comment());
0687     m_initializing = false;
0688 }
0689 
0690 void XYDataReductionCurveDock::curveDataSourceTypeChanged(XYAnalysisCurve::DataSourceType type) {
0691     m_initializing = true;
0692     uiGeneralTab.cbDataSourceType->setCurrentIndex(static_cast<int>(type));
0693     m_initializing = false;
0694 }
0695 
0696 void XYDataReductionCurveDock::curveDataSourceCurveChanged(const XYCurve* curve) {
0697     m_initializing = true;
0698     XYCurveDock::setModelIndexFromAspect(cbDataSourceCurve, curve);
0699     m_initializing = false;
0700 }
0701 
0702 void XYDataReductionCurveDock::curveXDataColumnChanged(const AbstractColumn* column) {
0703     m_initializing = true;
0704     XYCurveDock::setModelIndexFromAspect(cbXDataColumn, column);
0705     m_initializing = false;
0706 }
0707 
0708 void XYDataReductionCurveDock::curveYDataColumnChanged(const AbstractColumn* column) {
0709     m_initializing = true;
0710     XYCurveDock::setModelIndexFromAspect(cbYDataColumn, column);
0711     m_initializing = false;
0712 }
0713 
0714 void XYDataReductionCurveDock::curveDataReductionDataChanged(const XYDataReductionCurve::DataReductionData& dataReductionData) {
0715     m_initializing = true;
0716     m_dataReductionData = dataReductionData;
0717     //uiGeneralTab.cbType->setCurrentIndex(m_dataReductionData.type);
0718     //this->typeChanged();
0719 
0720     this->showDataReductionResult();
0721     m_initializing = false;
0722 }
0723 
0724 void XYDataReductionCurveDock::dataChanged() {
0725     this->enableRecalculate();
0726 }
0727 
0728 void XYDataReductionCurveDock::curveVisibilityChanged(bool on) {
0729     m_initializing = true;
0730     uiGeneralTab.chkVisible->setChecked(on);
0731     m_initializing = false;
0732 }