File indexing completed on 2024-05-12 16:44:00

0001 /*
0002     SPDX-FileCopyrightText: 2010-2014 Cristian Oneț <onet.cristian@gmail.com>
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 "kmymoneyaccounttreeview.h"
0008 
0009 // ----------------------------------------------------------------------------
0010 // QT Includes
0011 
0012 #include <QHeaderView>
0013 #include <QMouseEvent>
0014 #include <QPoint>
0015 
0016 // ----------------------------------------------------------------------------
0017 // KDE Includes
0018 
0019 #include <KConfigGroup>
0020 #include <KSharedConfig>
0021 
0022 // ----------------------------------------------------------------------------
0023 // Project Includes
0024 
0025 #include "mymoneyinstitution.h"
0026 #include "mymoneyaccount.h"
0027 #include "models.h"
0028 #include "accountsmodel.h"
0029 #include "accountsviewproxymodel.h"
0030 #include "budgetviewproxymodel.h"
0031 #include "modelenums.h"
0032 #include "mymoneyenums.h"
0033 #include "viewenums.h"
0034 
0035 class KMyMoneyAccountTreeViewPrivate
0036 {
0037     Q_DISABLE_COPY(KMyMoneyAccountTreeViewPrivate)
0038     Q_DECLARE_PUBLIC(KMyMoneyAccountTreeView)
0039 
0040 public:
0041     explicit KMyMoneyAccountTreeViewPrivate(KMyMoneyAccountTreeView *qq) :
0042         q_ptr(qq),
0043         m_model(nullptr),
0044         m_view(View::None)
0045     {
0046     }
0047 
0048     ~KMyMoneyAccountTreeViewPrivate()
0049     {
0050     }
0051 
0052     QVector<eMyMoney::Account::Type> getVisibleGroups(const View view)
0053     {
0054         switch (view) {
0055         case View::Institutions:
0056         case View::Accounts:
0057             return QVector<eMyMoney::Account::Type> {eMyMoney::Account::Type::Asset, eMyMoney::Account::Type::Liability, eMyMoney::Account::Type::Equity};
0058         case View::Categories:
0059         case View::Budget:
0060             return QVector<eMyMoney::Account::Type> {eMyMoney::Account::Type::Income, eMyMoney::Account::Type::Expense};
0061         default:
0062             return QVector<eMyMoney::Account::Type> ();
0063         }
0064     }
0065 
0066     QSet<eAccountsModel::Column> readVisibleColumns(const View view)
0067     {
0068         QSet<eAccountsModel::Column> columns;
0069 
0070         const auto grp = KSharedConfig::openConfig()->group(getConfGrpName(view));
0071         const auto cfgColumns = grp.readEntry("ColumnsSelection", QList<int>());
0072         columns.insert(eAccountsModel::Column::Account);
0073         foreach (const auto column, cfgColumns)
0074             columns.insert(static_cast<eAccountsModel::Column>(column));
0075         return columns;
0076     }
0077 
0078     void openIndex(const QModelIndex &index)
0079     {
0080         Q_Q(KMyMoneyAccountTreeView);
0081         if (index.isValid()) {
0082             QVariant data = q->model()->data(index, (int)eAccountsModel::Role::Account);
0083             if (data.isValid()) {
0084                 if (data.canConvert<MyMoneyAccount>()) {
0085                     emit q->selectByObject(data.value<MyMoneyAccount>(), eView::Intent::OpenObject);
0086                 }
0087                 if (data.canConvert<MyMoneyInstitution>()) {
0088                     emit q->selectByObject(data.value<MyMoneyInstitution>(), eView::Intent::OpenObject);
0089                 }
0090             }
0091         }
0092     }
0093 
0094     static QString getConfGrpName(const View view)
0095     {
0096         switch (view) {
0097         case View::Institutions:
0098             return QStringLiteral("KInstitutionsView");
0099         case View::Accounts:
0100             return QStringLiteral("KAccountsView");
0101         case View::Categories:
0102             return QStringLiteral("KCategoriesView");
0103         case View::Budget:
0104             return QStringLiteral("KBudgetsView");
0105         default:
0106             return QString();
0107         }
0108     }
0109 
0110     KMyMoneyAccountTreeView *q_ptr;
0111     AccountsViewProxyModel  *m_model;
0112     View                     m_view;
0113 };
0114 
0115 KMyMoneyAccountTreeView::KMyMoneyAccountTreeView(QWidget *parent) :
0116     QTreeView(parent),
0117     d_ptr(new KMyMoneyAccountTreeViewPrivate(this))
0118 {
0119     setContextMenuPolicy(Qt::CustomContextMenu);            // allow context menu to be opened on tree items
0120     header()->setContextMenuPolicy(Qt::CustomContextMenu);  // allow context menu to be opened on tree header for columns selection
0121     connect(this, &QWidget::customContextMenuRequested, this, &KMyMoneyAccountTreeView::customContextMenuRequested);
0122     setAllColumnsShowFocus(true);
0123     setAlternatingRowColors(true);
0124     setIconSize(QSize(22, 22));
0125     setSortingEnabled(true);
0126 }
0127 
0128 KMyMoneyAccountTreeView::~KMyMoneyAccountTreeView()
0129 {
0130     Q_D(KMyMoneyAccountTreeView);
0131     if (d->m_view != View::None) {
0132         auto grp = KSharedConfig::openConfig()->group(d->getConfGrpName(d->m_view));
0133         const auto columns = header()->saveState();
0134         grp.writeEntry("HeaderState", columns);
0135         QList<int> visColumns;
0136         foreach (const auto column, d->m_model->getVisibleColumns())
0137             visColumns.append(static_cast<int>(column));
0138         grp.writeEntry("ColumnsSelection", visColumns);
0139         grp.sync();
0140     }
0141     delete d;
0142 }
0143 
0144 AccountsViewProxyModel *KMyMoneyAccountTreeView::init(View view)
0145 {
0146     Q_D(KMyMoneyAccountTreeView);
0147     d->m_view = view;
0148     if (view != View::Budget)
0149         d->m_model = new AccountsViewProxyModel(this);
0150     else
0151         d->m_model = new BudgetViewProxyModel(this);
0152 
0153     d->m_model->addAccountGroup(d->getVisibleGroups(view));
0154 
0155     const auto accountsModel = Models::instance()->accountsModel();
0156     const auto institutionsModel = Models::instance()->institutionsModel();
0157 
0158     AccountsModel *sourceModel;
0159     if (view != View::Institutions)
0160         sourceModel = accountsModel;
0161     else
0162         sourceModel = institutionsModel;
0163 
0164     foreach (const auto column, d->readVisibleColumns(view)) {
0165         d->m_model->setColumnVisibility(column, true);
0166         accountsModel->setColumnVisibility(column, true);
0167         institutionsModel->setColumnVisibility(column, true);
0168     }
0169 
0170     d->m_model->setSourceColumns(sourceModel->getColumns());
0171     d->m_model->setSourceModel(sourceModel);
0172     d->m_model->setFilterCaseSensitivity(Qt::CaseInsensitive);
0173     d->m_model->setSortLocaleAware(true);
0174     setModel(d->m_model);
0175 
0176     connect(this->header(), &QWidget::customContextMenuRequested, d->m_model, &AccountsViewProxyModel::slotColumnsMenu);
0177     connect(d->m_model, &AccountsViewProxyModel::columnToggled, this, &KMyMoneyAccountTreeView::slotColumnToggled);
0178 
0179     // restore the headers
0180     const auto grp = KSharedConfig::openConfig()->group(d->getConfGrpName(view));
0181     const auto columnNames = grp.readEntry("HeaderState", QByteArray());
0182     header()->restoreState(columnNames);
0183 
0184     return d->m_model;
0185 }
0186 
0187 void KMyMoneyAccountTreeView::mouseDoubleClickEvent(QMouseEvent *event)
0188 {
0189     Q_D(KMyMoneyAccountTreeView);
0190     d->openIndex(currentIndex());
0191     event->accept();
0192 }
0193 
0194 void KMyMoneyAccountTreeView::keyPressEvent(QKeyEvent *event)
0195 {
0196     Q_D(KMyMoneyAccountTreeView);
0197     if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
0198         d->openIndex(currentIndex());
0199         emit returnPressed();
0200         event->accept();
0201     } else {
0202         QTreeView::keyPressEvent(event);
0203     }
0204 }
0205 
0206 void KMyMoneyAccountTreeView::customContextMenuRequested(const QPoint)
0207 {
0208     const auto index = model()->index(currentIndex().row(), (int)eAccountsModel::Column::Account, currentIndex().parent());
0209     if (index.isValid() && (model()->flags(index) & Qt::ItemIsSelectable)) {
0210         const auto dataVariant = model()->data(index, (int)eAccountsModel::Role::Account);
0211         if (dataVariant.isValid()) {
0212             if (dataVariant.canConvert<MyMoneyAccount>()) {
0213                 emit selectByObject(dataVariant.value<MyMoneyAccount>(), eView::Intent::None);
0214                 emit selectByObject(dataVariant.value<MyMoneyAccount>(), eView::Intent::OpenContextMenu);
0215             }
0216             if (dataVariant.canConvert<MyMoneyInstitution>()) {
0217                 emit selectByObject(dataVariant.value<MyMoneyInstitution>(), eView::Intent::None);
0218                 emit selectByObject(dataVariant.value<MyMoneyInstitution>(), eView::Intent::OpenContextMenu);
0219             }
0220         }
0221     }
0222 }
0223 
0224 void KMyMoneyAccountTreeView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
0225 {
0226     QTreeView::selectionChanged(selected, deselected);
0227     if (!selected.empty()) {
0228         auto indexes = selected.front().indexes();
0229         if (!indexes.empty()) {
0230             const auto dataVariant = model()->data(model()->index(indexes.front().row(), (int)eAccountsModel::Column::Account, indexes.front().parent()), (int)eAccountsModel::Role::Account);
0231             if (dataVariant.isValid()) {
0232                 if (dataVariant.canConvert<MyMoneyAccount>())
0233                     emit selectByObject(dataVariant.value<MyMoneyAccount>(), eView::Intent::None);
0234 
0235                 if (dataVariant.canConvert<MyMoneyInstitution>())
0236                     emit selectByObject(dataVariant.value<MyMoneyInstitution>(), eView::Intent::None);
0237 
0238                 // an object was successfully selected
0239                 return;
0240             }
0241         }
0242     }
0243     // since no object was selected reset the object selection
0244     emit selectByObject(MyMoneyAccount(), eView::Intent::None);
0245     emit selectByObject(MyMoneyInstitution(), eView::Intent::None);
0246 }
0247 
0248 void KMyMoneyAccountTreeView::slotColumnToggled(const eAccountsModel::Column column, const bool show)
0249 {
0250     emit selectByVariant(QVariantList {QVariant::fromValue(column), QVariant(show)}, eView::Intent::ToggleColumn);
0251 }