File indexing completed on 2024-05-19 05:08:23

0001 /*
0002     SPDX-FileCopyrightText: 2021 Thomas Baumgart <tbaumgart@kde.org>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #ifndef LEDGERVIEWPAGE_P_H
0007 #define LEDGERVIEWPAGE_P_H
0008 
0009 // ----------------------------------------------------------------------------
0010 // QT Includes
0011 
0012 #include <QDate>
0013 #include <QPointer>
0014 #include <QTimer>
0015 
0016 // ----------------------------------------------------------------------------
0017 // KDE Includes
0018 
0019 // ----------------------------------------------------------------------------
0020 // Project Includes
0021 
0022 #include "accountsmodel.h"
0023 #include "kmymoneysettings.h"
0024 #include "ktransactionsortoptionsdlg.h"
0025 #include "ledgeraccountfilter.h"
0026 #include "ledgerfilter.h"
0027 #include "ledgerviewsettings.h"
0028 #include "mymoneyexception.h"
0029 #include "mymoneyfile.h"
0030 #include "mymoneymoney.h"
0031 #include "mymoneyprice.h"
0032 #include "mymoneysecurity.h"
0033 #include "mymoneyutils.h"
0034 #include "newtransactionform.h"
0035 #include "selectedobjects.h"
0036 #include "specialledgeritemfilter.h"
0037 
0038 #include <ui_ledgerviewpage.h>
0039 
0040 class LedgerViewPage::Private
0041 {
0042 public:
0043     Private(LedgerViewPage* qq)
0044         : q(qq)
0045         , ui(new Ui_LedgerViewPage)
0046         , accountFilter(nullptr)
0047         , specialItemFilter(nullptr)
0048         , stateFilter(nullptr)
0049         , form(nullptr)
0050         , stackedView(nullptr)
0051         , sortOrderType(LedgerViewSettings::SortOrderStd)
0052         , needModelInit(true)
0053         , showEntryForNewTransaction(false)
0054         , isInvestmentView(false)
0055         , precision(-1)
0056     {
0057     }
0058 
0059     virtual ~Private()
0060     {
0061         delete ui;
0062     }
0063 
0064     void initWidgets(const QString& configGroupName)
0065     {
0066         ui->setupUi(q);
0067 
0068         // make sure, we can disable the detail form but not the ledger view
0069         ui->m_splitter->setCollapsible(0, false);
0070         ui->m_splitter->setCollapsible(1, true);
0071 
0072         // make sure the ledger gets all the stretching
0073         ui->m_splitter->setStretchFactor(0, 3);
0074         ui->m_splitter->setStretchFactor(1, 1);
0075         ui->m_splitter->setSizes(QList<int>() << 10000 << ui->m_formWidget->sizeHint().height());
0076 
0077         delayTimer.setSingleShot(true);
0078 
0079         connect(ui->m_ledgerView, &LedgerView::transactionSelected, q, &LedgerViewPage::transactionSelected);
0080         connect(ui->m_ledgerView, &LedgerView::aboutToStartEdit, q, &LedgerViewPage::aboutToStartEdit);
0081         connect(ui->m_ledgerView, &LedgerView::aboutToFinishEdit, q, &LedgerViewPage::aboutToFinishEdit);
0082         connect(ui->m_ledgerView, &LedgerView::aboutToStartEdit, q, &LedgerViewPage::startEdit);
0083         connect(ui->m_ledgerView, &LedgerView::aboutToFinishEdit, q, &LedgerViewPage::finishEdit);
0084         connect(ui->m_ledgerView, &LedgerView::transactionSelectionChanged, q, &LedgerViewPage::slotRequestSelectionChanged);
0085         connect(ui->m_ledgerView, &LedgerView::requestCustomContextMenu, q, &LedgerViewPage::requestCustomContextMenu);
0086 
0087         connect(ui->m_splitter, &QSplitter::splitterMoved, q, &LedgerViewPage::splitterChanged);
0088 
0089         ui->m_ledgerView->setColumnSelectorGroupName(configGroupName);
0090 
0091         needModelInit = true;
0092     }
0093 
0094     virtual void updateSummaryInformation() const
0095     {
0096         if (reconciliationDate.isValid()) {
0097             ui->m_leftLabel->setText(i18nc("@label:textbox Reconciliation date", "Last reconciliation: %1", MyMoneyUtils::formatDate(reconciliationDate)));
0098         } else {
0099             ui->m_leftLabel->setText(i18nc("@label:textbox Reconciliation date", "Never reconciled"));
0100         }
0101 
0102         if (isInvestmentView) {
0103             const auto file = MyMoneyFile::instance();
0104             const auto account = file->accountsModel()->itemById(accountId);
0105             const auto baseCurrency = file->baseCurrency();
0106 
0107             // collect accounts and their balances
0108             QMap<QString, MyMoneyMoney> actBalance;
0109             actBalance[accountId] = file->balance(accountId);
0110             const auto subAccounts = account.accountList();
0111             for (const auto& accId : qAsConst(subAccounts)) {
0112                 actBalance[accId] = file->balance(accId);
0113             }
0114 
0115             MyMoneyMoney balance;
0116             bool balanceIsApproximated = false;
0117             QMap<QString, MyMoneyMoney>::const_iterator it_b;
0118             for (it_b = actBalance.cbegin(); it_b != actBalance.cend(); ++it_b) {
0119                 MyMoneyAccount stock = file->account(it_b.key());
0120                 QString currencyId = stock.currencyId();
0121                 MyMoneySecurity sec = file->security(currencyId);
0122                 MyMoneyMoney rate(1, 1);
0123 
0124                 if (stock.isInvest()) {
0125                     currencyId = sec.tradingCurrency();
0126                     const MyMoneyPrice& priceInfo = file->price(sec.id(), currencyId);
0127                     balanceIsApproximated |= !priceInfo.isValid();
0128                     rate = priceInfo.rate(sec.tradingCurrency());
0129                 }
0130 
0131                 if (currencyId != baseCurrency.id()) {
0132                     const MyMoneyPrice& priceInfo = file->price(sec.tradingCurrency(), baseCurrency.id());
0133                     balanceIsApproximated |= !priceInfo.isValid();
0134                     rate = (rate * priceInfo.rate(baseCurrency.id())).convertPrecision(sec.pricePrecision());
0135                 }
0136                 balance += ((*it_b) * rate).convert(baseCurrency.smallestAccountFraction());
0137             }
0138 
0139             ui->m_centerLabel->setText(QString());
0140             ui->m_rightLabel->setText(i18nc("@label:textbox Total value of investment",
0141                                             "Investment value: %1%2",
0142                                             balanceIsApproximated ? QLatin1String("~") : QString(),
0143                                             balance.formatMoney(baseCurrency.tradingSymbol(), precision)));
0144         } else {
0145             ui->m_centerLabel->setText(i18nc("@label:textbox Cleared balance", "Cleared: %1", clearedBalance.formatMoney("", precision)));
0146             if (selections.count(SelectedObjects::JournalEntry) > 1) {
0147                 ui->m_rightLabel->setText(i18nc("@label:textbox %1 sum symbol, %2 number of selected tx, %3 sum of tx",
0148                                                 "%1 of %2: %3",
0149                                                 QChar(0x2211),
0150                                                 selections.count(SelectedObjects::JournalEntry),
0151                                                 selectedTotal.formatMoney("", precision)));
0152             } else {
0153                 ui->m_rightLabel->setText(i18nc("@label:textbox Total balance", "Balance: %1", totalBalance.formatMoney("", precision)));
0154             }
0155         }
0156     }
0157 
0158     virtual void clearFilter()
0159     {
0160         stateFilter->clearFilter();
0161         ui->m_ledgerView->setFocus();
0162         QMetaObject::invokeMethod(ui->m_ledgerView, &LedgerView::ensureCurrentItemIsVisible, Qt::QueuedConnection);
0163     }
0164 
0165     virtual void updateAccountData(const MyMoneyAccount& account)
0166     {
0167         reconciliationDate = account.lastReconciliationDate();
0168         precision = MyMoneyMoney::denomToPrec(account.fraction());
0169         accountName = account.name();
0170 
0171         sortOptionKey = QLatin1String("kmm-sort-std");
0172         const auto sortOption = account.value(sortOptionKey);
0173 
0174         if (account.accountType() == eMyMoney::Account::Type::Investment) {
0175             sortOrderType = LedgerViewSettings::SortOrderInvest;
0176         } else {
0177             sortOrderType = LedgerViewSettings::SortOrderStd;
0178         }
0179 
0180         const LedgerSortOrder previousSortOrder = sortOrder;
0181 
0182         // check if we have a specific sort order or rely on the default
0183         if (!sortOption.isEmpty()) {
0184             sortOrder = LedgerSortOrder(sortOption);
0185         } else {
0186             sortOrder = LedgerViewSettings::instance()->sortOrder(sortOrderType);
0187         }
0188 
0189         if (previousSortOrder != sortOrder) {
0190             specialItemFilter->setLedgerSortOrder(sortOrder);
0191             specialItemFilter->forceReload();
0192         }
0193     }
0194 
0195     void selectSortOrder()
0196     {
0197         auto file = MyMoneyFile::instance();
0198         QPointer<KTransactionSortOptionsDlg> dlg = new KTransactionSortOptionsDlg(q);
0199         auto account = file->accountsModel()->itemById(accountId);
0200         const auto defaultSortOption =
0201             (sortOrderType == LedgerViewSettings::SortOrderStd) ? KMyMoneySettings::sortNormalView() : KMyMoneySettings::sortNormalView();
0202         dlg->setSortOption(account.value(sortOptionKey), defaultSortOption);
0203         if ((dlg->exec() == QDialog::Accepted) && dlg) {
0204             const auto newSortOption = dlg->sortOption();
0205             if (newSortOption != account.value(sortOptionKey)) {
0206                 if (newSortOption.isEmpty()) {
0207                     account.deletePair(sortOptionKey);
0208                 } else {
0209                     account.setValue(sortOptionKey, newSortOption);
0210                 }
0211                 MyMoneyFileTransaction ft;
0212                 try {
0213                     file->modifyAccount(account);
0214                     ft.commit();
0215                 } catch (const MyMoneyException& e) {
0216                     qDebug() << "Unable to store sort options with account" << account.name() << e.what();
0217                 }
0218             }
0219         }
0220         delete dlg;
0221     }
0222 
0223     LedgerViewPage* q;
0224     Ui_LedgerViewPage* ui;
0225     LedgerAccountFilter* accountFilter;
0226     SpecialLedgerItemFilter* specialItemFilter;
0227     LedgerFilter* stateFilter;
0228     NewTransactionForm* form;
0229     LedgerViewPage* stackedView;
0230     QSet<QString> hideFormReasons;
0231     QString accountId;
0232     QString accountName;
0233     QString sortOptionKey;
0234     SelectedObjects selections;
0235     QTimer delayTimer;
0236     QDate reconciliationDate;
0237     MyMoneyMoney totalBalance;
0238     MyMoneyMoney clearedBalance;
0239     MyMoneyMoney selectedTotal;
0240     LedgerViewSettings::SortOrderType sortOrderType;
0241     LedgerSortOrder sortOrder;
0242     bool needModelInit;
0243     bool showEntryForNewTransaction;
0244     bool isInvestmentView;
0245     int precision;
0246 };
0247 
0248 #endif // LEDGERVIEWPAGE_P_H