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 }