File indexing completed on 2024-06-16 04:46:41

0001 /*  This file is part of the KDE project
0002     SPDX-FileCopyrightText: 2009 Laurent Montel <montel@kde.org>
0003     SPDX-FileCopyrightText: 2017 Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com>
0004     SPDX-FileCopyrightText: 2018 Michael Kiefer <Michael-Kiefer@web.de>
0005     SPDX-FileCopyrightText: 2020 Robert Szczesiak <dev.rszczesiak@gmail.com>
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include "reporttabimpl.h"
0010 
0011 #include <KLocalizedString>
0012 #include <QtMath>
0013 
0014 #include "kmymoneyutils.h"
0015 #include "daterangedlg.h"
0016 
0017 #include "ui_reporttabgeneral.h"
0018 #include "ui_reporttabrowcolpivot.h"
0019 #include "ui_reporttabrowcolquery.h"
0020 #include "ui_reporttabchart.h"
0021 #include "ui_reporttabrange.h"
0022 #include "ui_reporttabcapitalgain.h"
0023 #include "ui_reporttabperformance.h"
0024 
0025 #include "mymoney/mymoneyreport.h"
0026 #include "mymoneyenums.h"
0027 
0028 ReportTabGeneral::ReportTabGeneral(QWidget *parent)
0029     : QWidget(parent)
0030 {
0031     ui = new Ui::ReportTabGeneral;
0032     ui->setupUi(this);
0033 }
0034 
0035 ReportTabGeneral::~ReportTabGeneral()
0036 {
0037     delete ui;
0038 }
0039 
0040 ReportTabRowColPivot::ReportTabRowColPivot(QWidget *parent)
0041     : QWidget(parent)
0042 {
0043     ui = new Ui::ReportTabRowColPivot;
0044     ui->setupUi(this);
0045 }
0046 
0047 ReportTabRowColPivot::~ReportTabRowColPivot()
0048 {
0049     delete ui;
0050 }
0051 
0052 ReportTabRowColQuery::ReportTabRowColQuery(QWidget *parent)
0053     : QWidget(parent)
0054 {
0055     ui = new Ui::ReportTabRowColQuery;
0056     ui->setupUi(this);
0057     ui->buttonGroup1->setExclusive(false);
0058     ui->buttonGroup1->setId(ui->m_checkMemo, 0);
0059     ui->buttonGroup1->setId(ui->m_checkShares, 1);
0060     ui->buttonGroup1->setId(ui->m_checkPrice, 2);
0061     ui->buttonGroup1->setId(ui->m_checkReconciled, 3);
0062     ui->buttonGroup1->setId(ui->m_checkAccount, 4);
0063     ui->buttonGroup1->setId(ui->m_checkNumber, 5);
0064     ui->buttonGroup1->setId(ui->m_checkPayee, 6);
0065     ui->buttonGroup1->setId(ui->m_checkCategory, 7);
0066     ui->buttonGroup1->setId(ui->m_checkAction, 8);
0067     ui->buttonGroup1->setId(ui->m_checkBalance, 9);
0068     connect(ui->m_checkHideTransactions, &QAbstractButton::toggled, this, &ReportTabRowColQuery::slotHideTransactionsChanged);
0069 }
0070 
0071 void ReportTabRowColQuery::slotHideTransactionsChanged(bool checked)
0072 {
0073     if (checked)                                          // toggle m_checkHideSplitDetails only if it's mandatory
0074         ui->m_checkHideSplitDetails->setChecked(checked);
0075     ui->m_checkHideSplitDetails->setEnabled(!checked);    // hiding transactions without hiding splits isn't allowed
0076 }
0077 
0078 ReportTabRowColQuery::~ReportTabRowColQuery()
0079 {
0080     delete ui;
0081 }
0082 
0083 ReportTabChart::ReportTabChart(QWidget *parent)
0084     : QWidget(parent)
0085 {
0086     ui = new Ui::ReportTabChart;
0087     ui->setupUi(this);
0088 
0089     ui->m_comboType->addItem(i18nc("type of graphic chart", "Line"), static_cast<int>(eMyMoney::Report::ChartType::Line));
0090     ui->m_comboType->addItem(i18nc("type of graphic chart", "Bar"), static_cast<int>(eMyMoney::Report::ChartType::Bar));
0091     ui->m_comboType->addItem(i18nc("type of graphic chart", "Stacked Bar"), static_cast<int>(eMyMoney::Report::ChartType::StackedBar));
0092     ui->m_comboType->addItem(i18nc("type of graphic chart", "Pie"), static_cast<int>(eMyMoney::Report::ChartType::Pie));
0093     ui->m_comboType->addItem(i18nc("type of graphic chart", "Ring"), static_cast<int>(eMyMoney::Report::ChartType::Ring));
0094     connect(ui->m_comboType, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ReportTabChart::slotChartTypeChanged);
0095     Q_EMIT ui->m_comboType->currentIndexChanged(ui->m_comboType->currentIndex());
0096 
0097     ui->m_comboPalette->addItem(i18nc("type of graphic palette", "Use application setting"), static_cast<int>(eMyMoney::Report::ChartPalette::Application));
0098     ui->m_comboPalette->addItem(i18nc("type of graphic palette", "Default"), static_cast<int>(eMyMoney::Report::ChartPalette::Default));
0099     ui->m_comboPalette->addItem(i18nc("type of graphic palette", "Rainbow"), static_cast<int>(eMyMoney::Report::ChartPalette::Rainbow));
0100     ui->m_comboPalette->addItem(i18nc("type of graphic palette", "Subdued"), static_cast<int>(eMyMoney::Report::ChartPalette::Subdued));
0101 }
0102 
0103 ReportTabChart::~ReportTabChart()
0104 {
0105     delete ui;
0106 }
0107 
0108 void ReportTabChart::slotChartTypeChanged(int index)
0109 {
0110     if (index == static_cast<int>(eMyMoney::Report::ChartType::Pie) ||
0111             index == static_cast<int>(eMyMoney::Report::ChartType::Ring)) {
0112         ui->m_checkCHGridLines->setText(i18n("Show circular grid lines"));
0113         ui->m_checkSVGridLines->setText(i18n("Show sagittal grid lines"));
0114         ui->m_logYaxis->setChecked(false);
0115         ui->m_logYaxis->setEnabled(false);
0116         ui->m_negExpenses->setChecked(false);
0117         ui->m_negExpenses->setEnabled(false);
0118     } else {
0119         ui->m_checkCHGridLines->setText(i18n("Show horizontal grid lines"));
0120         ui->m_checkSVGridLines->setText(i18n("Show vertical grid lines"));
0121         ui->m_logYaxis->setEnabled(true);
0122         ui->m_negExpenses->setEnabled(true);
0123     }
0124 }
0125 
0126 void ReportTabChart::setNegExpenses(bool set)
0127 {
0128     // logarithm on negative numbers does not make sense, so disable it
0129     if (set) {
0130         ui->m_logYaxis->setChecked(false);
0131         ui->m_logYaxis->setEnabled(false);
0132     } else {
0133         ui->m_logYaxis->setEnabled(true);
0134     }
0135 }
0136 
0137 ReportTabRange::ReportTabRange(QWidget *parent)
0138     : QWidget(parent),
0139       ui(new Ui::ReportTabRange),
0140       m_logYaxis(false)
0141 {
0142     ui->setupUi(this);
0143     m_dateRange = new DateRangeDlg;
0144     ui->dateRangeGrid->addWidget(m_dateRange, 0, 0, 1, 2);
0145     connect(ui->m_yLabelsPrecision, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &ReportTabRange::slotYLabelsPrecisionChanged);
0146     Q_EMIT ui->m_yLabelsPrecision->valueChanged(ui->m_yLabelsPrecision->value());
0147     connect(ui->m_dataRangeStart, &QLineEdit::editingFinished, this, &ReportTabRange::slotEditingFinishedStart);
0148     connect(ui->m_dataRangeEnd, &QLineEdit::editingFinished, this, &ReportTabRange::slotEditingFinishedEnd);
0149     connect(ui->m_dataMajorTick, &QLineEdit::editingFinished, this, &ReportTabRange::slotEditingFinishedMajor);
0150     connect(ui->m_dataMinorTick, &QLineEdit::editingFinished, this, &ReportTabRange::slotEditingFinishedMinor);
0151     connect(ui->m_dataLock, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ReportTabRange::slotDataLockChanged);
0152     Q_EMIT ui->m_dataLock->currentIndexChanged(ui->m_dataLock->currentIndex());
0153 }
0154 
0155 ReportTabRange::~ReportTabRange()
0156 {
0157     delete ui;
0158 }
0159 
0160 void ReportTabRange::setRangeLogarythmic(bool set)
0161 {
0162     // major and minor tick have no influence if axis is logarithmic so hide them
0163     if (set) {
0164         ui->lblDataMajorTick->hide();
0165         ui->lblDataMinorTick->hide();
0166         ui->m_dataMajorTick->hide();
0167         ui->m_dataMinorTick->hide();
0168 
0169         m_logYaxis = true;
0170     } else {
0171         ui->lblDataMajorTick->show();
0172         ui->lblDataMinorTick->show();
0173         ui->m_dataMajorTick->show();
0174         ui->m_dataMinorTick->show();
0175 
0176         m_logYaxis = false;
0177     }
0178 
0179     updateDataRangeValidators(ui->m_yLabelsPrecision->value()); // update data range validators and re-validate
0180 }
0181 
0182 void ReportTabRange::updateDataRangeValidators(const int& precision)
0183 {
0184 
0185     const QValidator *dbValStart = ui->m_dataRangeStart->validator();
0186     const QValidator *dbValEnd = ui->m_dataRangeEnd->validator();
0187 
0188     delete dbValStart;
0189     if (dbValStart != dbValEnd) {
0190         delete dbValEnd;
0191     }
0192 
0193     if (m_logYaxis) {
0194         dbValStart = new MyLogarithmicDoubleValidator(precision, qPow(10, -precision), ui->m_dataRangeStart);
0195         dbValEnd = new MyLogarithmicDoubleValidator(precision, qPow(10, -precision + 4), ui->m_dataRangeEnd);
0196     } else { // the validator will be used by two QLineEdit objects so let this tab be their parent
0197         dbValStart = new MyDoubleValidator(precision, this);
0198         dbValEnd = dbValStart;
0199     }
0200 
0201     ui->m_dataRangeStart->setValidator(dbValStart);
0202     ui->m_dataRangeEnd->setValidator(dbValEnd);
0203 
0204     QString dataRangeStart = ui->m_dataRangeStart->text();
0205     QString dataRangeEnd = ui->m_dataRangeEnd->text();
0206     if (!ui->m_dataRangeStart->hasAcceptableInput()) {
0207         dbValStart->fixup(dataRangeStart);
0208         ui->m_dataRangeStart->setText(dataRangeStart);
0209     }
0210     if (ui->m_dataRangeEnd->hasAcceptableInput()) {
0211         dbValEnd->fixup(dataRangeEnd);
0212         ui->m_dataRangeEnd->setText(dataRangeEnd);
0213     }
0214 }
0215 
0216 void ReportTabRange::slotEditingFinished(EDimension dim)
0217 {
0218     qreal dataRangeStart = locale().toDouble(ui->m_dataRangeStart->text());
0219     qreal dataRangeEnd = locale().toDouble(ui->m_dataRangeEnd->text());
0220 
0221     if (dataRangeEnd < dataRangeStart) { // end must be higher than start
0222         if (dim == eRangeEnd) {
0223             ui->m_dataRangeStart->setText(ui->m_dataRangeEnd->text());
0224             dataRangeStart = dataRangeEnd;
0225         } else {
0226             ui->m_dataRangeEnd->setText(ui->m_dataRangeStart->text());
0227             dataRangeEnd = dataRangeStart;
0228         }
0229     }
0230     if (!m_logYaxis) { // major and minor ticks only have influence when axis is linear
0231         qreal dataMajorTick = locale().toDouble(ui->m_dataMajorTick->text());
0232         qreal dataMinorTick = locale().toDouble(ui->m_dataMinorTick->text());
0233         if ((dataRangeStart != 0 || dataRangeEnd != 0)) { // if data range isn't going to be reset
0234             if ((dataRangeEnd - dataRangeStart) < dataMajorTick) // major tick cannot be greater than data range
0235                 dataMajorTick = dataRangeEnd - dataRangeStart;
0236 
0237             if (dataMajorTick != 0 && // if major tick isn't going to be reset
0238                     dataMajorTick < (dataRangeEnd - dataRangeStart) * 0.01) // constraint major tick to be greater or equal to 1% of data range
0239                 dataMajorTick = (dataRangeEnd - dataRangeStart) * 0.01;
0240 
0241             //set precision of major tick to be greater by 1
0242             ui->m_dataMajorTick->setText(locale().toString(dataMajorTick, 'f', ui->m_yLabelsPrecision->value() + 1).remove(locale().groupSeparator()).remove(QRegularExpression("0+$")).remove(QRegularExpression("\\" + locale().decimalPoint() + "$")));
0243         }
0244 
0245         if (dataMajorTick < dataMinorTick) { // major tick must be higher than minor
0246             if (dim == eMinorTick) {
0247                 ui->m_dataMajorTick->setText(ui->m_dataMinorTick->text());
0248                 dataMajorTick = dataMinorTick;
0249             } else {
0250                 ui->m_dataMinorTick->setText(ui->m_dataMajorTick->text());
0251                 dataMinorTick = dataMajorTick;
0252             }
0253         }
0254 
0255         if (dataMinorTick < dataMajorTick * 0.1) { // constraint minor tick to be greater or equal to 10% of major tick, and set precision to be greater by 1
0256             dataMinorTick = dataMajorTick * 0.1;
0257             ui->m_dataMinorTick->setText(locale().toString(dataMinorTick, 'f', ui->m_yLabelsPrecision->value() + 1).remove(locale().groupSeparator()).remove(QRegularExpression("0+$")).remove(QRegularExpression("\\" + locale().decimalPoint() + "$")));
0258         }
0259     }
0260 }
0261 
0262 void ReportTabRange::slotEditingFinishedStart()
0263 {
0264     slotEditingFinished(eRangeStart);
0265 }
0266 
0267 void ReportTabRange::slotEditingFinishedEnd()
0268 {
0269     slotEditingFinished(eRangeEnd);
0270 }
0271 
0272 void ReportTabRange::slotEditingFinishedMajor()
0273 {
0274     slotEditingFinished(eMajorTick);
0275 }
0276 
0277 void ReportTabRange::slotEditingFinishedMinor()
0278 {
0279     slotEditingFinished(eMinorTick);
0280 }
0281 
0282 void ReportTabRange::slotYLabelsPrecisionChanged(const int& value)
0283 {
0284     ui->m_dataMajorTick->setValidator(0);
0285     ui->m_dataMinorTick->setValidator(0);
0286 
0287     MyDoubleValidator *dblVal2 = new MyDoubleValidator(value + 1);
0288     ui->m_dataMajorTick->setValidator(dblVal2);
0289     ui->m_dataMinorTick->setValidator(dblVal2);
0290 
0291     updateDataRangeValidators(value);
0292 }
0293 
0294 void ReportTabRange::slotDataLockChanged(int index) {
0295     if (index == static_cast<int>(eMyMoney::Report::DataLock::Automatic)) {
0296         ui->m_dataRangeStart->setText(QStringLiteral("0"));
0297         ui->m_dataRangeEnd->setText(QStringLiteral("0"));
0298         ui->m_dataMajorTick->setText(QStringLiteral("0"));
0299         ui->m_dataMinorTick->setText(QStringLiteral("0"));
0300         ui->m_dataRangeStart->setEnabled(false);
0301         ui->m_dataRangeEnd->setEnabled(false);
0302         ui->m_dataMajorTick->setEnabled(false);
0303         ui->m_dataMinorTick->setEnabled(false);
0304     } else {
0305         ui->m_dataRangeStart->setEnabled(true);
0306         ui->m_dataRangeEnd->setEnabled(true);
0307         ui->m_dataMajorTick->setEnabled(true);
0308         ui->m_dataMinorTick->setEnabled(true);
0309     }
0310 }
0311 
0312 ReportTabCapitalGain::ReportTabCapitalGain(QWidget *parent)
0313     : QWidget(parent)
0314 {
0315     ui = new Ui::ReportTabCapitalGain;
0316     ui->setupUi(this);
0317     connect(ui->m_investmentSum, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ReportTabCapitalGain::slotInvestmentSumChanged);
0318 }
0319 
0320 ReportTabCapitalGain::~ReportTabCapitalGain()
0321 {
0322     delete ui;
0323 }
0324 
0325 void ReportTabCapitalGain::slotInvestmentSumChanged(int index) {
0326     Q_UNUSED(index);
0327     if (ui->m_investmentSum->currentData() == static_cast<int>(eMyMoney::Report::InvestmentSum::Owned)) {
0328         ui->m_settlementPeriod->setValue(0);
0329         ui->m_settlementPeriod->setEnabled(false);
0330         ui->m_showSTLTCapitalGains->setChecked(false);
0331         ui->m_showSTLTCapitalGains->setEnabled(false);
0332         ui->m_termSeparator->setEnabled(false);
0333     } else {
0334         ui->m_settlementPeriod->setEnabled(true);
0335         ui->m_showSTLTCapitalGains->setEnabled(true);
0336         ui->m_termSeparator->setEnabled(true);
0337     }
0338 }
0339 
0340 ReportTabPerformance::ReportTabPerformance(QWidget *parent)
0341     : QWidget(parent)
0342 {
0343     ui = new Ui::ReportTabPerformance;
0344     ui->setupUi(this);
0345 }
0346 
0347 ReportTabPerformance::~ReportTabPerformance()
0348 {
0349     delete ui;
0350 }
0351 
0352 MyDoubleValidator::MyDoubleValidator(int decimals, QObject * parent) :
0353     QDoubleValidator(0, 0, decimals, parent)
0354 {
0355 }
0356 
0357 QValidator::State MyDoubleValidator::validate(QString &s, int &i) const
0358 {
0359     Q_UNUSED(i);
0360     if (s.isEmpty() || s == "-") {
0361         return QValidator::Intermediate;
0362     }
0363 
0364     QString decimalPoint = locale().decimalPoint();
0365 
0366     if(s.indexOf(decimalPoint) != -1) {
0367         int charsAfterPoint = s.length() - s.indexOf(decimalPoint) - 1;
0368 
0369         if (charsAfterPoint > decimals()) {
0370             return QValidator::Invalid;
0371         }
0372     }
0373 
0374     bool ok;
0375     locale().toDouble(s, &ok);
0376 
0377     if (ok) {
0378         return QValidator::Acceptable;
0379     } else {
0380         return QValidator::Invalid;
0381     }
0382 }
0383 
0384 MyLogarithmicDoubleValidator::MyLogarithmicDoubleValidator(const int decimals, const qreal defaultValue, QObject *parent)
0385     : QDoubleValidator(qPow(10, -decimals), 0, decimals, parent)
0386 {
0387     m_defaultText = KMyMoneyUtils::normalizeNumericString(defaultValue, locale(), 'f', decimals);
0388 }
0389 
0390 QValidator::State MyLogarithmicDoubleValidator::validate(QString &s, int &i) const
0391 {
0392     Q_UNUSED(i);
0393     if (s.isEmpty() || s == QStringLiteral("0")) {
0394         return QValidator::Intermediate;
0395     }
0396 
0397     QString decimalPoint = locale().decimalPoint();
0398 
0399     // start numbering placeholders with a two-digit number to avoid
0400     // interpreting the following zero as part of the placeholder index
0401     const QRegularExpression re((QStringLiteral("^0\\%110{0,%12}$")
0402                                  .arg(decimalPoint)
0403                                  .arg(decimals() - 1)));
0404     if (re.match(s).hasMatch())
0405         return QValidator::Intermediate;
0406 
0407     if (s.indexOf(decimalPoint) != -1) {
0408         int charsAfterPoint = s.length() - s.indexOf(decimalPoint) - 1;
0409 
0410         if (charsAfterPoint > decimals()) {
0411             return QValidator::Invalid;
0412         }
0413     }
0414 
0415     bool ok;
0416     const qreal result = locale().toDouble(s, &ok);
0417 
0418     if (ok && result >= bottom()) {
0419         return QValidator::Acceptable;
0420     } else {
0421         return QValidator::Invalid;
0422     }
0423 }
0424 
0425 void MyLogarithmicDoubleValidator::fixup(QString &input) const
0426 {
0427     input = m_defaultText;
0428 }