File indexing completed on 2024-05-19 16:16:55
0001 /* 0002 SPDX-FileCopyrightText: 2002-2019 Thomas Baumgart <tbaumgart@kde.org> 0003 SPDX-FileCopyrightText: 2017-2018 Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com> 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "ktransactionfilter.h" 0008 #include "ktransactionfilter_p.h" 0009 0010 // ---------------------------------------------------------------------------- 0011 // QT Includes 0012 0013 // ---------------------------------------------------------------------------- 0014 // KDE Includes 0015 0016 #include <KHelpClient> 0017 #include <KLocalizedString> 0018 0019 // ---------------------------------------------------------------------------- 0020 // Project Includes 0021 0022 #include "ui_ktransactionfilter.h" 0023 #include "mymoneyreport.h" 0024 #include "mymoneysplit.h" 0025 #include "mymoneyexception.h" 0026 #include "mymoneyfile.h" 0027 #include "mymoneytransaction.h" 0028 #include "mymoneytransactionfilter.h" 0029 #include "kmymoneysettings.h" 0030 #include "daterangedlg.h" 0031 0032 KTransactionFilter::KTransactionFilter(QWidget *parent, bool withEquityAccounts, bool withInvestments, bool withDataTab) : 0033 QWidget(parent), 0034 d_ptr(new KTransactionFilterPrivate(this)) 0035 { 0036 Q_D(KTransactionFilter); 0037 d->init(withEquityAccounts, withInvestments, withDataTab); 0038 } 0039 0040 KTransactionFilter::~KTransactionFilter() 0041 { 0042 Q_D(KTransactionFilter); 0043 delete d; 0044 } 0045 0046 void KTransactionFilter::slotReset() 0047 { 0048 Q_D(KTransactionFilter); 0049 d->ui->m_textEdit->setText(QString()); 0050 d->ui->m_regExp->setChecked(false); 0051 d->ui->m_caseSensitive->setChecked(false); 0052 d->ui->m_textNegate->setCurrentIndex(0); 0053 0054 d->ui->m_amountEdit->setEnabled(true); 0055 d->ui->m_amountFromEdit->setEnabled(false); 0056 d->ui->m_amountToEdit->setEnabled(false); 0057 d->ui->m_amountEdit->setText(QString()); 0058 d->ui->m_amountFromEdit->setText(QString()); 0059 d->ui->m_amountToEdit->setText(QString()); 0060 d->ui->m_amountButton->setChecked(true); 0061 d->ui->m_amountRangeButton->setChecked(false); 0062 0063 d->ui->m_emptyPayeesButton->setChecked(false); 0064 d->selectAllItems(d->ui->m_payeesView, true); 0065 0066 d->ui->m_emptyTagsButton->setChecked(false); 0067 d->selectAllItems(d->ui->m_tagsView, true); 0068 0069 d->ui->m_typeBox->setCurrentIndex((int)eMyMoney::TransactionFilter::Type::All); 0070 d->ui->m_stateBox->setCurrentIndex((int)eMyMoney::TransactionFilter::State::All); 0071 d->ui->m_validityBox->setCurrentIndex((int)eMyMoney::TransactionFilter::Validity::Any); 0072 0073 d->ui->m_nrEdit->setEnabled(true); 0074 d->ui->m_nrFromEdit->setEnabled(false); 0075 d->ui->m_nrToEdit->setEnabled(false); 0076 d->ui->m_nrEdit->setText(QString()); 0077 d->ui->m_nrFromEdit->setText(QString()); 0078 d->ui->m_nrToEdit->setText(QString()); 0079 d->ui->m_nrButton->setChecked(true); 0080 d->ui->m_nrRangeButton->setChecked(false); 0081 0082 // the following call implies a call to slotUpdateSelections, 0083 // that's why we call it last 0084 if (d->m_dateRange) 0085 d->m_dateRange->slotReset(); 0086 slotUpdateSelections(); 0087 0088 d->ui->m_accountsView->slotSelectAllAccounts(); 0089 d->ui->m_categoriesView->slotSelectAllAccounts(); 0090 } 0091 0092 void KTransactionFilter::slotUpdateSelections() 0093 { 0094 Q_D(KTransactionFilter); 0095 QString txt; 0096 const QString separator(", "); 0097 // Text tab 0098 if (!d->ui->m_textEdit->text().isEmpty()) { 0099 if (!txt.isEmpty()) 0100 txt += separator; 0101 txt += i18n("Text"); 0102 d->ui->m_regExp->setEnabled(QRegExp(d->ui->m_textEdit->text()).isValid()); 0103 } else 0104 d->ui->m_regExp->setEnabled(false); 0105 0106 d->ui->m_caseSensitive->setEnabled(!d->ui->m_textEdit->text().isEmpty()); 0107 d->ui->m_textNegate->setEnabled(!d->ui->m_textEdit->text().isEmpty()); 0108 0109 // Account tab 0110 if (!d->ui->m_accountsView->allItemsSelected()) { 0111 if (!txt.isEmpty()) 0112 txt += separator; 0113 txt += i18n("Account"); 0114 } 0115 0116 if (d->m_dateRange && d->m_dateRange->dateRange() != eMyMoney::TransactionFilter::Date::All) { 0117 if (!txt.isEmpty()) 0118 txt += separator; 0119 txt += i18n("Date"); 0120 } 0121 0122 // Amount tab 0123 if ((d->ui->m_amountButton->isChecked() && d->ui->m_amountEdit->isValid()) 0124 || (d->ui->m_amountRangeButton->isChecked() 0125 && (d->ui->m_amountFromEdit->isValid() || d->ui->m_amountToEdit->isValid()))) { 0126 if (!txt.isEmpty()) 0127 txt += separator; 0128 txt += i18n("Amount"); 0129 } 0130 0131 // Categories tab 0132 if (!d->ui->m_categoriesView->allItemsSelected()) { 0133 if (!txt.isEmpty()) 0134 txt += separator; 0135 txt += i18n("Category"); 0136 } 0137 0138 // Tags tab 0139 if (!d->allItemsSelected(d->ui->m_tagsView) 0140 || d->ui->m_emptyTagsButton->isChecked()) { 0141 if (!txt.isEmpty()) 0142 txt += separator; 0143 txt += i18n("Tags"); 0144 } 0145 d->ui->m_tagsView->setEnabled(!d->ui->m_emptyTagsButton->isChecked()); 0146 0147 // Payees tab 0148 if (!d->allItemsSelected(d->ui->m_payeesView) 0149 || d->ui->m_emptyPayeesButton->isChecked()) { 0150 if (!txt.isEmpty()) 0151 txt += separator; 0152 txt += i18n("Payees"); 0153 } 0154 d->ui->m_payeesView->setEnabled(!d->ui->m_emptyPayeesButton->isChecked()); 0155 0156 // Details tab 0157 if (d->ui->m_typeBox->currentIndex() != 0 // 0158 || d->ui->m_stateBox->currentIndex() != 0 // 0159 || d->ui->m_validityBox->currentIndex() != 0 // 0160 || (d->ui->m_nrButton->isChecked() && d->ui->m_nrEdit->text().length() != 0) // 0161 || (d->ui->m_nrRangeButton->isChecked() // 0162 && (d->ui->m_nrFromEdit->text().length() != 0 || d->ui->m_nrToEdit->text().length() != 0))) { 0163 if (!txt.isEmpty()) 0164 txt += separator; 0165 txt += i18n("Details"); 0166 } 0167 0168 //Show a warning about transfers if Categories are filtered - bug #1523508 0169 if (!d->ui->m_categoriesView->allItemsSelected()) { 0170 d->ui->m_transferWarning->setText(i18n("Warning: Filtering by Category will exclude all transfers from the results.")); 0171 } else { 0172 d->ui->m_transferWarning->setText(QString()); 0173 } 0174 0175 // disable the search button if no selection is made 0176 emit selectionNotEmpty(!txt.isEmpty()); 0177 0178 if (txt.isEmpty()) { 0179 txt = i18nc("No selection", "(None)"); 0180 } 0181 d->ui->m_selectedCriteria->setText(i18n("Current selections: %1", txt)); 0182 } 0183 0184 void KTransactionFilter::slotAmountSelected() 0185 { 0186 Q_D(KTransactionFilter); 0187 d->ui->m_amountEdit->setEnabled(true); 0188 d->ui->m_amountFromEdit->setEnabled(false); 0189 d->ui->m_amountToEdit->setEnabled(false); 0190 slotUpdateSelections(); 0191 } 0192 0193 void KTransactionFilter::slotAmountRangeSelected() 0194 { 0195 Q_D(KTransactionFilter); 0196 d->ui->m_amountEdit->setEnabled(false); 0197 d->ui->m_amountFromEdit->setEnabled(true); 0198 d->ui->m_amountToEdit->setEnabled(true); 0199 slotUpdateSelections(); 0200 } 0201 0202 void KTransactionFilter::slotSelectAllPayees() 0203 { 0204 Q_D(KTransactionFilter); 0205 d->selectAllItems(d->ui->m_payeesView, true); 0206 } 0207 0208 void KTransactionFilter::slotDeselectAllPayees() 0209 { 0210 Q_D(KTransactionFilter); 0211 d->selectAllItems(d->ui->m_payeesView, false); 0212 } 0213 0214 void KTransactionFilter::slotSelectAllTags() 0215 { 0216 Q_D(KTransactionFilter); 0217 d->selectAllItems(d->ui->m_tagsView, true); 0218 } 0219 0220 void KTransactionFilter::slotDeselectAllTags() 0221 { 0222 Q_D(KTransactionFilter); 0223 d->selectAllItems(d->ui->m_tagsView, false); 0224 } 0225 0226 void KTransactionFilter::slotNrSelected() 0227 { 0228 Q_D(KTransactionFilter); 0229 d->ui->m_nrEdit->setEnabled(true); 0230 d->ui->m_nrFromEdit->setEnabled(false); 0231 d->ui->m_nrToEdit->setEnabled(false); 0232 slotUpdateSelections(); 0233 } 0234 0235 void KTransactionFilter::slotNrRangeSelected() 0236 { 0237 Q_D(KTransactionFilter); 0238 d->ui->m_nrEdit->setEnabled(false); 0239 d->ui->m_nrFromEdit->setEnabled(true); 0240 d->ui->m_nrToEdit->setEnabled(true); 0241 slotUpdateSelections(); 0242 } 0243 0244 void KTransactionFilter::slotShowHelp() 0245 { 0246 Q_D(KTransactionFilter); 0247 auto anchor = d->m_helpAnchor[d->ui->m_criteriaTab->currentWidget()]; 0248 if (anchor.isEmpty()) 0249 anchor = QString("details.search"); 0250 0251 KHelpClient::invokeHelp(anchor); 0252 } 0253 0254 MyMoneyTransactionFilter KTransactionFilter::setupFilter() 0255 { 0256 Q_D(KTransactionFilter); 0257 d->m_filter.clear(); 0258 0259 // Text tab 0260 if (!d->ui->m_textEdit->text().isEmpty()) { 0261 QRegExp exp(d->ui->m_textEdit->text(), d->ui->m_caseSensitive->isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive, !d->ui->m_regExp->isChecked() ? QRegExp::Wildcard : QRegExp::RegExp); 0262 d->m_filter.setTextFilter(exp, d->ui->m_textNegate->currentIndex() != 0); 0263 } 0264 0265 // Account tab 0266 if (!d->ui->m_accountsView->allItemsSelected()) { 0267 // retrieve a list of selected accounts 0268 QStringList list; 0269 d->ui->m_accountsView->selectedItems(list); 0270 0271 // if we're not in expert mode, we need to make sure 0272 // that all stock accounts for the selected investment 0273 // account are also selected 0274 if (!KMyMoneySettings::expertMode()) { 0275 QStringList missing; 0276 foreach (const auto selection, list) { 0277 auto acc = MyMoneyFile::instance()->account(selection); 0278 if (acc.accountType() == eMyMoney::Account::Type::Investment) { 0279 foreach (const auto sAccount, acc.accountList()) { 0280 if (!list.contains(sAccount)) { 0281 missing.append(sAccount); 0282 } 0283 } 0284 } 0285 } 0286 list += missing; 0287 } 0288 0289 d->m_filter.addAccount(list); 0290 } 0291 0292 // Date tab 0293 if (d->m_dateRange && (int)d->m_dateRange->dateRange() != 0) { 0294 d->m_filter.setDateFilter(d->m_dateRange->fromDate(), d->m_dateRange->toDate()); 0295 } 0296 0297 // Amount tab 0298 if ((d->ui->m_amountButton->isChecked() && d->ui->m_amountEdit->isValid())) { 0299 d->m_filter.setAmountFilter(d->ui->m_amountEdit->value(), d->ui->m_amountEdit->value()); 0300 0301 } else if ((d->ui->m_amountRangeButton->isChecked() // 0302 && (d->ui->m_amountFromEdit->isValid() || d->ui->m_amountToEdit->isValid()))) { 0303 0304 MyMoneyMoney from(MyMoneyMoney::minValue), to(MyMoneyMoney::maxValue); 0305 if (d->ui->m_amountFromEdit->isValid()) 0306 from = d->ui->m_amountFromEdit->value(); 0307 if (d->ui->m_amountToEdit->isValid()) 0308 to = d->ui->m_amountToEdit->value(); 0309 0310 d->m_filter.setAmountFilter(from, to); 0311 } 0312 0313 // Categories tab 0314 if (!d->ui->m_categoriesView->allItemsSelected()) { 0315 d->m_filter.addCategory(d->ui->m_categoriesView->selectedItems()); 0316 } 0317 0318 // Tags tab 0319 if (d->ui->m_emptyTagsButton->isChecked()) { 0320 d->m_filter.addTag(QString()); 0321 0322 } else if (!d->allItemsSelected(d->ui->m_tagsView)) { 0323 d->scanCheckListItems(d->ui->m_tagsView, KTransactionFilterPrivate::addTagToFilter); 0324 } 0325 0326 // Payees tab 0327 if (d->ui->m_emptyPayeesButton->isChecked()) { 0328 d->m_filter.addPayee(QString()); 0329 0330 } else if (!d->allItemsSelected(d->ui->m_payeesView)) { 0331 d->scanCheckListItems(d->ui->m_payeesView, KTransactionFilterPrivate::addPayeeToFilter); 0332 } 0333 0334 // Details tab 0335 if (d->ui->m_typeBox->currentIndex() != 0) 0336 d->m_filter.addType(d->ui->m_typeBox->currentIndex()); 0337 0338 if (d->ui->m_stateBox->currentIndex() != 0) 0339 d->m_filter.addState(d->ui->m_stateBox->currentIndex()); 0340 0341 if (d->ui->m_validityBox->currentIndex() != 0) 0342 d->m_filter.addValidity(d->ui->m_validityBox->currentIndex()); 0343 0344 if (d->ui->m_nrButton->isChecked() && !d->ui->m_nrEdit->text().isEmpty()) 0345 d->m_filter.setNumberFilter(d->ui->m_nrEdit->text(), d->ui->m_nrEdit->text()); 0346 0347 if (d->ui->m_nrRangeButton->isChecked() // 0348 && (!d->ui->m_nrFromEdit->text().isEmpty() || !d->ui->m_nrToEdit->text().isEmpty())) { 0349 d->m_filter.setNumberFilter(d->ui->m_nrFromEdit->text(), d->ui->m_nrToEdit->text()); 0350 } 0351 return d->m_filter; 0352 } 0353 0354 void KTransactionFilter::resetFilter(MyMoneyReport& rep) 0355 { 0356 Q_D(KTransactionFilter); 0357 // 0358 // Text Filter 0359 // 0360 0361 QRegExp textfilter; 0362 if (rep.textFilter(textfilter)) { 0363 d->ui->m_textEdit->setText(textfilter.pattern()); 0364 d->ui->m_caseSensitive->setChecked(Qt::CaseSensitive == textfilter.caseSensitivity()); 0365 d->ui->m_regExp->setChecked(QRegExp::RegExp == textfilter.patternSyntax()); 0366 d->ui->m_textNegate->setCurrentIndex(rep.isInvertingText()); 0367 } 0368 0369 // 0370 // Type & State Filters 0371 // 0372 0373 int type; 0374 if (rep.firstType(type)) 0375 d->ui->m_typeBox->setCurrentIndex(type); 0376 0377 int state; 0378 if (rep.firstState(state)) 0379 d->ui->m_stateBox->setCurrentIndex(state); 0380 0381 int validity; 0382 if (rep.firstValidity(validity)) 0383 d->ui->m_validityBox->setCurrentIndex(validity); 0384 0385 // 0386 // Number Filter 0387 // 0388 0389 QString nrFrom, nrTo; 0390 if (rep.numberFilter(nrFrom, nrTo)) { 0391 if (nrFrom == nrTo) { 0392 d->ui->m_nrEdit->setEnabled(true); 0393 d->ui->m_nrFromEdit->setEnabled(false); 0394 d->ui->m_nrToEdit->setEnabled(false); 0395 d->ui->m_nrEdit->setText(nrFrom); 0396 d->ui->m_nrFromEdit->setText(QString()); 0397 d->ui->m_nrToEdit->setText(QString()); 0398 d->ui->m_nrButton->setChecked(true); 0399 d->ui->m_nrRangeButton->setChecked(false); 0400 } else { 0401 d->ui->m_nrEdit->setEnabled(false); 0402 d->ui->m_nrFromEdit->setEnabled(true); 0403 d->ui->m_nrToEdit->setEnabled(false); 0404 d->ui->m_nrEdit->setText(QString()); 0405 d->ui->m_nrFromEdit->setText(nrFrom); 0406 d->ui->m_nrToEdit->setText(nrTo); 0407 d->ui->m_nrButton->setChecked(false); 0408 d->ui->m_nrRangeButton->setChecked(true); 0409 } 0410 } else { 0411 d->ui->m_nrEdit->setEnabled(true); 0412 d->ui->m_nrFromEdit->setEnabled(false); 0413 d->ui->m_nrToEdit->setEnabled(false); 0414 d->ui->m_nrEdit->setText(QString()); 0415 d->ui->m_nrFromEdit->setText(QString()); 0416 d->ui->m_nrToEdit->setText(QString()); 0417 d->ui->m_nrButton->setChecked(true); 0418 d->ui->m_nrRangeButton->setChecked(false); 0419 } 0420 0421 // 0422 // Amount Filter 0423 // 0424 0425 MyMoneyMoney from, to; 0426 if (rep.amountFilter(from, to)) { // bool getAmountFilter(MyMoneyMoney&,MyMoneyMoney&); 0427 if (from == to) { 0428 d->ui->m_amountEdit->setEnabled(true); 0429 d->ui->m_amountFromEdit->setEnabled(false); 0430 d->ui->m_amountToEdit->setEnabled(false); 0431 d->ui->m_amountEdit->setText(QString::number(from.toDouble())); 0432 d->ui->m_amountFromEdit->setText(QString()); 0433 d->ui->m_amountToEdit->setText(QString()); 0434 d->ui->m_amountButton->setChecked(true); 0435 d->ui->m_amountRangeButton->setChecked(false); 0436 } else { 0437 d->ui->m_amountEdit->setEnabled(false); 0438 d->ui->m_amountFromEdit->setEnabled(true); 0439 d->ui->m_amountToEdit->setEnabled(true); 0440 d->ui->m_amountEdit->setText(QString()); 0441 d->ui->m_amountFromEdit->setText(QString::number(from.toDouble())); 0442 d->ui->m_amountToEdit->setText(QString::number(to.toDouble())); 0443 d->ui->m_amountButton->setChecked(false); 0444 d->ui->m_amountRangeButton->setChecked(true); 0445 } 0446 } else { 0447 d->ui->m_amountEdit->setEnabled(true); 0448 d->ui->m_amountFromEdit->setEnabled(false); 0449 d->ui->m_amountToEdit->setEnabled(false); 0450 d->ui->m_amountEdit->setText(QString()); 0451 d->ui->m_amountFromEdit->setText(QString()); 0452 d->ui->m_amountToEdit->setText(QString()); 0453 d->ui->m_amountButton->setChecked(true); 0454 d->ui->m_amountRangeButton->setChecked(false); 0455 } 0456 0457 // 0458 // Payees Filter 0459 // 0460 0461 QStringList payees; 0462 if (rep.payees(payees)) { 0463 if (payees.empty()) { 0464 d->ui->m_emptyPayeesButton->setChecked(true); 0465 } else { 0466 d->selectAllItems(d->ui->m_payeesView, false); 0467 d->selectItems(d->ui->m_payeesView, payees, true); 0468 } 0469 } else { 0470 d->selectAllItems(d->ui->m_payeesView, true); 0471 } 0472 0473 // 0474 // Tags Filter 0475 // 0476 0477 QStringList tags; 0478 if (rep.tags(tags)) { 0479 if (tags.empty()) { 0480 d->ui->m_emptyTagsButton->setChecked(true); 0481 } else { 0482 d->selectAllItems(d->ui->m_tagsView, false); 0483 d->selectItems(d->ui->m_tagsView, tags, true); 0484 } 0485 } else { 0486 d->selectAllItems(d->ui->m_tagsView, true); 0487 } 0488 0489 // 0490 // Accounts Filter 0491 // 0492 0493 QStringList accounts; 0494 if (rep.accounts(accounts)) { 0495 // in case the presentation of closed accounts is turned off ... 0496 if (d->accountSet.isHidingClosedAccounts()) { 0497 // ... we need to turn them on again in case our own 0498 // configuration references a closed account 0499 const MyMoneyFile* file = MyMoneyFile::instance(); 0500 foreach(const auto accId, accounts) { 0501 try { 0502 if (file->account(accId).isClosed()) { 0503 d->accountSet.setHideClosedAccounts(false); 0504 d->accountSet.load(d->ui->m_accountsView); 0505 break; 0506 } 0507 } catch (const MyMoneyException&) { 0508 } 0509 } 0510 } 0511 d->ui->m_accountsView->selectAllItems(false); 0512 d->ui->m_accountsView->selectItems(accounts, true); 0513 } else 0514 d->ui->m_accountsView->selectAllItems(true); 0515 0516 // 0517 // Categories Filter 0518 // 0519 0520 if (rep.categories(accounts)) { 0521 d->ui->m_categoriesView->selectAllItems(false); 0522 d->ui->m_categoriesView->selectItems(accounts, true); 0523 } else 0524 d->ui->m_categoriesView->selectAllItems(true); 0525 0526 // 0527 // Date Filter 0528 // 0529 0530 // the following call implies a call to slotUpdateSelections, 0531 // that's why we call it last 0532 0533 if (d->m_dateRange) { 0534 rep.updateDateFilter(); 0535 QDate dateFrom, dateTo; 0536 if (rep.dateFilter(dateFrom, dateTo)) { 0537 if (rep.isDateUserDefined()) { 0538 d->m_dateRange->setDateRange(dateFrom, dateTo); 0539 } else { 0540 d->m_dateRange->setDateRange(rep.dateRange()); 0541 } 0542 } else { 0543 d->m_dateRange->setDateRange(eMyMoney::TransactionFilter::Date::All); 0544 } 0545 } 0546 0547 } 0548 0549 KMyMoneyAccountSelector* KTransactionFilter::categoriesView() 0550 { 0551 Q_D(KTransactionFilter); 0552 return d->ui->m_categoriesView; 0553 } 0554 0555 DateRangeDlg* KTransactionFilter::dateRange() 0556 { 0557 Q_D(KTransactionFilter); 0558 return d->m_dateRange; 0559 }