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

0001 /*
0002     SPDX-FileCopyrightText: 2007-2019 Thomas Baumgart <tbaumgart@kde.org>
0003     SPDX-FileCopyrightText: 2017 Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com>
0004     SPDX-FileCopyrightText: 2020 Robert Szczesiak <dev.rszczesiak@gmail.com>
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "kinstitutionsview.h"
0009 
0010 // ----------------------------------------------------------------------------
0011 // QT Includes
0012 
0013 #include <QAction>
0014 #include <QPointer>
0015 #include <QKeyEvent>
0016 
0017 // ----------------------------------------------------------------------------
0018 // KDE Includes
0019 
0020 #include <KMessageBox>
0021 
0022 // ----------------------------------------------------------------------------
0023 // Project Includes
0024 
0025 #include "ui_kinstitutionsview.h"
0026 #include "kmymoneyviewbase_p.h"
0027 #include "mymoneyfile.h"
0028 #include "mymoneymoney.h"
0029 #include "kmymoneysettings.h"
0030 #include "mymoneyexception.h"
0031 #include "mymoneyinstitution.h"
0032 #include "knewinstitutiondlg.h"
0033 #include "menuenums.h"
0034 #include "accountdelegate.h"
0035 #include "institutionsmodel.h"
0036 #include "accountsproxymodel.h"
0037 #include "institutionsproxymodel.h"
0038 #include "icons.h"
0039 #include "columnselector.h"
0040 #include "kmymoneyaccounttreeview.h"
0041 
0042 using namespace Icons;
0043 
0044 
0045 class KInstitutionsViewPrivate : public KMyMoneyViewBasePrivate
0046 {
0047     Q_DECLARE_PUBLIC(KInstitutionsView)
0048 
0049 public:
0050     explicit KInstitutionsViewPrivate(KInstitutionsView *qq)
0051         : KMyMoneyViewBasePrivate(qq)
0052         , ui(new Ui::KInstitutionsView)
0053         , m_proxyModel(nullptr)
0054     {
0055     }
0056 
0057     ~KInstitutionsViewPrivate()
0058     {
0059         delete ui;
0060     }
0061 
0062     void init()
0063     {
0064         Q_Q(KInstitutionsView);
0065         ui->setupUi(q);
0066 
0067         // setup icons for buttons
0068         ui->m_collapseButton->setIcon(Icons::get(Icon::ListCollapse));
0069         ui->m_expandButton->setIcon(Icons::get(Icon::ListExpand));
0070         // prepare the filter container
0071         ui->m_closeButton->setIcon(Icons::get(Icon::DialogClose));
0072         ui->m_filterContainer->hide();
0073         ui->m_searchWidget->installEventFilter(q);
0074 
0075         ui->m_accountTree->setProxyModel(new InstitutionsProxyModel);
0076         m_proxyModel = ui->m_accountTree->proxyModel();
0077         q->connect(ui->m_searchWidget, &QLineEdit::textChanged, m_proxyModel, &QSortFilterProxyModel::setFilterFixedString);
0078 
0079         auto columnSelector = new ColumnSelector(ui->m_accountTree, q->metaObject()->className());
0080         columnSelector->setAlwaysVisible(QVector<int>({ AccountsModel::Column::AccountName }));
0081         columnSelector->setAlwaysHidden(QVector<int>({
0082             AccountsModel::Column::PostedValue,
0083             AccountsModel::Column::Type,
0084             AccountsModel::Column::CostCenter,
0085             AccountsModel::Column::Tax,
0086             AccountsModel::Column::Vat,
0087             AccountsModel::Column::Number,
0088             AccountsModel::Column::HasOnlineMapping,
0089         }));
0090 
0091         ui->m_accountTree->setModel(MyMoneyFile::instance()->institutionsModel());
0092         m_proxyModel->addAccountGroup(AccountsProxyModel::assetLiabilityEquity());
0093 
0094         columnSelector->setModel(m_proxyModel);
0095         q->slotSettingsChanged();
0096 
0097         // forward the widget requests
0098         q->connect(ui->m_accountTree, &KMyMoneyAccountTreeView::requestCustomContextMenu, q, &KInstitutionsView::requestCustomContextMenu);
0099         q->connect(ui->m_accountTree, &KMyMoneyAccountTreeView::requestSelectionChange, q, &KInstitutionsView::requestSelectionChange);
0100         q->connect(ui->m_accountTree, &KMyMoneyAccountTreeView::requestActionTrigger, q, &KInstitutionsView::requestActionTrigger);
0101 
0102         m_focusWidget = ui->m_accountTree;
0103     }
0104 
0105     Ui::KInstitutionsView   *ui;
0106     MyMoneyInstitution      m_currentInstitution;
0107     AccountsProxyModel*     m_proxyModel;
0108 };
0109 
0110 
0111 
0112 KInstitutionsView::KInstitutionsView(QWidget *parent) :
0113     KMyMoneyViewBase(*new KInstitutionsViewPrivate(this), parent)
0114 {
0115     Q_D(KInstitutionsView);
0116     d->init();
0117 
0118     connect(d->ui->m_closeButton, &QToolButton::clicked, this, [&]() {
0119         Q_D(KInstitutionsView);
0120         d->ui->m_searchWidget->clear();
0121         d->ui->m_filterContainer->hide();
0122     });
0123 
0124     connect(pActions[eMenu::Action::ShowFilterWidget], &QAction::triggered, this, [&]() {
0125         Q_D(KInstitutionsView);
0126         // only react if this is the current view
0127         if (isVisible()) {
0128             d->ui->m_filterContainer->show();
0129             d->ui->m_searchWidget->setFocus();
0130         }
0131     });
0132 
0133     connect(pActions[eMenu::Action::NewInstitution],    &QAction::triggered, this, &KInstitutionsView::slotNewInstitution);
0134     connect(pActions[eMenu::Action::EditInstitution],   &QAction::triggered, this, &KInstitutionsView::slotEditInstitution);
0135     connect(pActions[eMenu::Action::DeleteInstitution], &QAction::triggered, this, &KInstitutionsView::slotDeleteInstitution);
0136 
0137     d->ui->m_accountTree->setItemDelegate(new AccountDelegate(d->ui->m_accountTree));
0138     connect(MyMoneyFile::instance()->accountsModel(), &AccountsModel::netWorthChanged, this, &KInstitutionsView::slotNetWorthChanged);
0139 
0140     d->m_sharedToolbarActions.insert(eMenu::Action::FileNew, pActions[eMenu::Action::NewInstitution]);
0141 }
0142 
0143 KInstitutionsView::~KInstitutionsView()
0144 {
0145 }
0146 
0147 bool KInstitutionsView::eventFilter(QObject* watched, QEvent* event)
0148 {
0149     Q_D(KInstitutionsView);
0150     if (watched == d->ui->m_searchWidget) {
0151         if (event->type() == QEvent::KeyPress) {
0152             const auto kev = static_cast<QKeyEvent*>(event);
0153             if (kev->modifiers() == Qt::NoModifier && kev->key() == Qt::Key_Escape) {
0154                 d->ui->m_closeButton->animateClick();
0155                 return true;
0156             }
0157         }
0158     }
0159     return QWidget::eventFilter(watched, event);
0160 }
0161 
0162 
0163 void KInstitutionsView::slotSettingsChanged()
0164 {
0165     Q_D(KInstitutionsView);
0166     d->m_proxyModel->setHideClosedAccounts(!KMyMoneySettings::showAllAccounts());
0167     d->m_proxyModel->setHideEquityAccounts(!KMyMoneySettings::expertMode());
0168     d->m_proxyModel->setHideFavoriteAccounts(true);
0169 
0170     MyMoneyFile::instance()->institutionsModel()->setColorScheme(AccountsModel::Positive, KMyMoneySettings::schemeColor(SchemeColor::Positive));
0171     MyMoneyFile::instance()->institutionsModel()->setColorScheme(AccountsModel::Negative, KMyMoneySettings::schemeColor(SchemeColor::Negative));
0172 }
0173 
0174 
0175 void KInstitutionsView::updateActions(const SelectedObjects& selections)
0176 {
0177     Q_D(KInstitutionsView);
0178 
0179     pActions[eMenu::Action::EditInstitution]->setEnabled(false);
0180     pActions[eMenu::Action::DeleteInstitution]->setEnabled(false);
0181 
0182     // check if there is anything todo and quit if not
0183     if (selections.selection(SelectedObjects::Institution).count() < 1
0184             && d->m_currentInstitution.id().isEmpty() ) {
0185         return;
0186     }
0187 
0188     const auto ids = selections.selection(SelectedObjects::Institution);
0189     if (ids.isEmpty()) {
0190         d->m_currentInstitution = MyMoneyInstitution();
0191         return;
0192     }
0193 
0194     const auto file = MyMoneyFile::instance();
0195     const auto inst = file->institutionsModel()->itemById(ids.at(0));
0196 
0197     auto b = inst.id().isEmpty() ? false : true;
0198     pActions[eMenu::Action::EditInstitution]->setEnabled(b);
0199     pActions[eMenu::Action::DeleteInstitution]->setEnabled(b && !MyMoneyFile::instance()->isReferenced(inst));
0200     d->m_currentInstitution = inst;
0201 }
0202 
0203 void KInstitutionsView::slotNetWorthChanged(const MyMoneyMoney &netWorth, bool isApproximate)
0204 {
0205     Q_D(KInstitutionsView);
0206     const auto formattedValue = d->formatViewLabelValue(netWorth);
0207     d->updateViewLabel(d->ui->m_totalProfitsLabel,
0208                        isApproximate ? i18nc("Approximate net worth", "Net Worth: ~%1", formattedValue)
0209                        : i18n("Net Worth: %1", formattedValue));
0210 }
0211 
0212 void KInstitutionsView::slotNewInstitution()
0213 {
0214     Q_D(KInstitutionsView);
0215     MyMoneyInstitution institution;
0216 
0217     QPointer<KNewInstitutionDlg> dlg = new KNewInstitutionDlg(institution);
0218     if (dlg->exec() == QDialog::Accepted && dlg != 0) {
0219         d->m_currentInstitution = dlg->institution();
0220 
0221         const auto file = MyMoneyFile::instance();
0222         MyMoneyFileTransaction ft;
0223 
0224         try {
0225             file->addInstitution(d->m_currentInstitution);
0226             ft.commit();
0227 
0228         } catch (const MyMoneyException &e) {
0229             KMessageBox::information(this, i18n("Cannot add institution: %1", QString::fromLatin1(e.what())));
0230         }
0231     }
0232     delete dlg;
0233 }
0234 
0235 void KInstitutionsView::slotEditInstitution()
0236 {
0237     Q_D(KInstitutionsView);
0238 
0239     // make sure the selected object has an id
0240     if (d->m_currentInstitution.id().isEmpty())
0241         return;
0242 
0243     try {
0244         const auto file = MyMoneyFile::instance();
0245 
0246         //grab a pointer to the view, regardless of it being a account or institution view.
0247         auto institution = file->institution(d->m_currentInstitution.id());
0248 
0249         // bankSuccess is not checked anymore because d->m_file->institution will throw anyway
0250         QPointer<KNewInstitutionDlg> dlg = new KNewInstitutionDlg(institution);
0251         if (dlg->exec() == QDialog::Accepted && dlg != 0) {
0252             MyMoneyFileTransaction ft;
0253             try {
0254                 file->modifyInstitution(dlg->institution());
0255                 ft.commit();
0256             } catch (const MyMoneyException &e) {
0257                 KMessageBox::information(this, i18n("Unable to store institution: %1", QString::fromLatin1(e.what())));
0258             }
0259         }
0260         delete dlg;
0261 
0262     } catch (const MyMoneyException &e) {
0263         KMessageBox::information(this, i18n("Unable to edit institution: %1", QString::fromLatin1(e.what())));
0264     }
0265 }
0266 
0267 void KInstitutionsView::slotDeleteInstitution()
0268 {
0269     Q_D(KInstitutionsView);
0270     const auto file = MyMoneyFile::instance();
0271     try {
0272         auto institution = file->institution(d->m_currentInstitution.id());
0273         if ((KMessageBox::questionTwoActions(this,
0274                                              i18n("<p>Do you really want to delete the institution <b>%1</b>?</p>", institution.name()),
0275                                              i18nc("@title:window", "Delete institution"),
0276                                              KMMYesNo::yes(),
0277                                              KMMYesNo::no()))
0278             == KMessageBox::SecondaryAction)
0279             return;
0280         MyMoneyFileTransaction ft;
0281 
0282         try {
0283             file->removeInstitution(institution);
0284             ft.commit();
0285         } catch (const MyMoneyException &e) {
0286             KMessageBox::information(this, i18n("Unable to delete institution: %1", QString::fromLatin1(e.what())));
0287         }
0288     } catch (const MyMoneyException &e) {
0289         KMessageBox::information(this, i18n("Unable to delete institution: %1", QString::fromLatin1(e.what())));
0290     }
0291 }