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 }