File indexing completed on 2024-05-12 16:43:48
0001 /* 0002 SPDX-FileCopyrightText: 2007 Thomas Baumgart <ipwizard@users.sourceforge.net> 0003 SPDX-FileCopyrightText: 2017 Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com> 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kinvestmentview_p.h" 0008 0009 #include <typeinfo> 0010 0011 // ---------------------------------------------------------------------------- 0012 // QT Includes 0013 0014 #include <QTimer> 0015 #include <QAction> 0016 #include <QMenu> 0017 #include <QBitArray> 0018 0019 // ---------------------------------------------------------------------------- 0020 // KDE Includes 0021 0022 #include <KMessageBox> 0023 0024 // ---------------------------------------------------------------------------- 0025 // Project Includes 0026 0027 #include "mymoneymoney.h" 0028 #include "mymoneyprice.h" 0029 #include "kequitypriceupdatedlg.h" 0030 #include "kcurrencycalculator.h" 0031 #include "knewinvestmentwizard.h" 0032 #include "kmymoneyutils.h" 0033 #include "menuenums.h" 0034 #include "storageenums.h" 0035 0036 using namespace Icons; 0037 0038 KInvestmentView::KInvestmentView(QWidget *parent) : 0039 KMyMoneyViewBase(*new KInvestmentViewPrivate(this), parent) 0040 { 0041 connect(pActions[eMenu::Action::NewInvestment], &QAction::triggered, this, &KInvestmentView::slotNewInvestment); 0042 connect(pActions[eMenu::Action::EditInvestment], &QAction::triggered, this, &KInvestmentView::slotEditInvestment); 0043 connect(pActions[eMenu::Action::DeleteInvestment], &QAction::triggered, this, &KInvestmentView::slotDeleteInvestment); 0044 connect(pActions[eMenu::Action::UpdatePriceOnline], &QAction::triggered, this, &KInvestmentView::slotUpdatePriceOnline); 0045 connect(pActions[eMenu::Action::UpdatePriceManually], &QAction::triggered, this, &KInvestmentView::slotUpdatePriceManually); 0046 } 0047 0048 KInvestmentView::~KInvestmentView() 0049 { 0050 } 0051 0052 void KInvestmentView::setDefaultFocus() 0053 { 0054 Q_D(KInvestmentView); 0055 auto tab = static_cast<eView::Investment::Tab>(d->ui->m_tab->currentIndex()); 0056 0057 switch (tab) { 0058 case eView::Investment::Tab::Equities: 0059 QTimer::singleShot(0, d->ui->m_equitiesTree, SLOT(setFocus())); 0060 break; 0061 case eView::Investment::Tab::Securities: 0062 QTimer::singleShot(0, d->ui->m_securitiesTree, SLOT(setFocus())); 0063 break; 0064 } 0065 } 0066 0067 void KInvestmentView::executeCustomAction(eView::Action action) 0068 { 0069 switch(action) { 0070 case eView::Action::Refresh: 0071 refresh(); 0072 break; 0073 0074 case eView::Action::SetDefaultFocus: 0075 setDefaultFocus(); 0076 break; 0077 0078 default: 0079 break; 0080 } 0081 } 0082 0083 void KInvestmentView::refresh() 0084 { 0085 Q_D(KInvestmentView); 0086 d->m_needReload[eView::Investment::Tab::Equities] = d->m_needReload[eView::Investment::Tab::Securities] = true; 0087 if (isVisible()) 0088 slotLoadTab(d->ui->m_tab->currentIndex()); 0089 } 0090 0091 void KInvestmentView::showEvent(QShowEvent* event) 0092 { 0093 Q_D(KInvestmentView); 0094 if (d->m_needLoad) 0095 d->init(); 0096 0097 emit customActionRequested(View::Investments, eView::Action::AboutToShow); 0098 0099 d->m_needReload[eView::Investment::Tab::Equities] = true; // ensure tree view will be reloaded after selecting account in ledger view 0100 if (d->m_needReload[eView::Investment::Tab::Equities] == true || 0101 d->m_needReload[eView::Investment::Tab::Securities] == true) 0102 refresh(); 0103 0104 // don't forget base class implementation 0105 QWidget::showEvent(event); 0106 } 0107 0108 void KInvestmentView::updateActions(const MyMoneyObject& obj) 0109 { 0110 Q_D(KInvestmentView); 0111 if (typeid(obj) != typeid(MyMoneyAccount) && 0112 (obj.id().isEmpty() && d->m_currentEquity.id().isEmpty())) // do not disable actions that were already disabled))) 0113 return; 0114 0115 const auto& acc = static_cast<const MyMoneyAccount&>(obj); 0116 0117 const auto file = MyMoneyFile::instance(); 0118 auto b = acc.accountType() == eMyMoney::Account::Type::Investment ? true : false; 0119 if (isVisible() && !d->m_idInvAcc.isEmpty()) 0120 b = true; 0121 0122 pActions[eMenu::Action::NewInvestment]->setEnabled(b); 0123 0124 b = acc.isInvest() ? true : false; 0125 pActions[eMenu::Action::EditInvestment]->setEnabled(b); 0126 pActions[eMenu::Action::DeleteInvestment]->setEnabled(b && !file->isReferenced(acc)); 0127 pActions[eMenu::Action::UpdatePriceManually]->setEnabled(b); 0128 pActions[eMenu::Action::UpdatePriceOnline]->setEnabled(b && !file->security(acc.currencyId()).value("kmm-online-source").isEmpty()); 0129 0130 switch (acc.accountType()) { 0131 case eMyMoney::Account::Type::Investment: 0132 case eMyMoney::Account::Type::Stock: 0133 d->m_currentEquity = acc; 0134 break; 0135 default: 0136 d->m_currentEquity = MyMoneyAccount(); 0137 break; 0138 } 0139 } 0140 0141 void KInvestmentView::slotLoadTab(int index) 0142 { 0143 Q_D(KInvestmentView); 0144 auto tab = static_cast<eView::Investment::Tab>(index); 0145 if (d->m_needReload[tab]) { 0146 switch (tab) { 0147 case eView::Investment::Tab::Equities: 0148 d->loadInvestmentTab(); 0149 break; 0150 case eView::Investment::Tab::Securities: 0151 d->loadSecuritiesTab(); 0152 break; 0153 } 0154 d->m_needReload[tab] = false; 0155 } 0156 } 0157 0158 void KInvestmentView::slotEquitySelected(const QModelIndex ¤t, const QModelIndex &previous) 0159 { 0160 Q_D(KInvestmentView); 0161 Q_UNUSED(current); 0162 Q_UNUSED(previous); 0163 emit selectByObject(d->currentEquity(), eView::Intent::None); 0164 } 0165 0166 void KInvestmentView::slotSecuritySelected(const QModelIndex ¤t, const QModelIndex &previous) 0167 { 0168 Q_D(KInvestmentView); 0169 Q_UNUSED(current); 0170 Q_UNUSED(previous); 0171 const auto sec = d->currentSecurity(); 0172 if (!sec.id().isEmpty()) { 0173 QBitArray skip((int)eStorage::Reference::Count); 0174 skip.fill(false); 0175 skip.setBit((int)eStorage::Reference::Price); 0176 d->ui->m_editSecurityButton->setEnabled(true); 0177 d->ui->m_deleteSecurityButton->setEnabled(!MyMoneyFile::instance()->isReferenced(sec, skip)); 0178 } else { 0179 d->ui->m_editSecurityButton->setEnabled(false); 0180 d->ui->m_deleteSecurityButton->setEnabled(false); 0181 } 0182 } 0183 0184 void KInvestmentView::slotSelectAccount(const QString &id) 0185 { 0186 Q_D(KInvestmentView); 0187 if (!id.isEmpty()) { 0188 d->m_idInvAcc = id; 0189 if (isVisible()) { 0190 d->ui->m_accountComboBox->setSelected(id); 0191 slotSecuritySelected(QModelIndex(), QModelIndex()); 0192 slotEquitySelected(QModelIndex(), QModelIndex()); 0193 } 0194 } 0195 } 0196 0197 void KInvestmentView::slotSelectAccount(const MyMoneyObject &obj) 0198 { 0199 if (typeid(obj) != typeid(MyMoneyAccount)) 0200 return; 0201 const auto acc = dynamic_cast<const MyMoneyAccount &>(obj); 0202 0203 if (acc.accountType() == eMyMoney::Account::Type::Investment) 0204 slotSelectAccount(acc.id()); 0205 } 0206 0207 void KInvestmentView::slotLoadAccount(const QString &id) 0208 { 0209 Q_D(KInvestmentView); 0210 const auto indexList = d->m_equitiesProxyModel->match(d->m_equitiesProxyModel->index(0,0), EquitiesModel::InvestmentID, id, 1, 0211 Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive | Qt::MatchWrap)); 0212 0213 const auto acc = MyMoneyFile::instance()->account(id); 0214 if (!indexList.isEmpty()) { 0215 d->ui->m_equitiesTree->setRootIndex(indexList.first()); 0216 d->m_idInvAcc = id; 0217 if (isVisible()) 0218 emit selectByObject(acc, eView::Intent::SynchronizeAccountInLedgersView); 0219 } 0220 updateActions(acc); 0221 } 0222 0223 void KInvestmentView::slotInvestmentMenuRequested(const QPoint&) 0224 { 0225 Q_D(KInvestmentView); 0226 MyMoneyAccount acc; 0227 auto treeItem = d->ui->m_equitiesTree->currentIndex(); 0228 if (treeItem.isValid()) { 0229 auto mdlItem = d->m_equitiesProxyModel->index(treeItem.row(), EquitiesModel::Equity, treeItem.parent()); 0230 acc = MyMoneyFile::instance()->account(mdlItem.data(EquitiesModel::EquityID).toString()); 0231 } 0232 slotShowInvestmentMenu(acc); 0233 } 0234 0235 void KInvestmentView::slotShowInvestmentMenu(const MyMoneyAccount& acc) 0236 { 0237 Q_UNUSED(acc); 0238 pMenus[eMenu::Menu::Investment]->exec(QCursor::pos()); 0239 } 0240 0241 void KInvestmentView::slotSelectByObject(const MyMoneyObject& obj, eView::Intent intent) 0242 { 0243 switch(intent) { 0244 case eView::Intent::UpdateActions: 0245 updateActions(obj); 0246 break; 0247 0248 case eView::Intent::SynchronizeAccountInInvestmentView: 0249 if (KMyMoneySettings::syncLedgerInvestment()) 0250 slotSelectAccount(obj); 0251 break; 0252 0253 case eView::Intent::OpenContextMenu: 0254 slotShowInvestmentMenu(static_cast<const MyMoneyAccount&>(obj)); 0255 break; 0256 0257 default: 0258 break; 0259 } 0260 } 0261 0262 void KInvestmentView::slotNewInvestment() 0263 { 0264 Q_D(KInvestmentView); 0265 if (!isVisible()) 0266 KNewInvestmentWizard::newInvestment(d->m_currentEquity); 0267 else 0268 KNewInvestmentWizard::newInvestment(MyMoneyFile::instance()->account(d->m_idInvAcc)); 0269 } 0270 0271 void KInvestmentView::slotEditInvestment() 0272 { 0273 Q_D(KInvestmentView); 0274 KNewInvestmentWizard::editInvestment(d->m_currentEquity); 0275 } 0276 0277 void KInvestmentView::slotDeleteInvestment() 0278 { 0279 Q_D(KInvestmentView); 0280 if (KMessageBox::questionYesNo(this, 0281 i18n("<p>Do you really want to delete the investment <b>%1</b>?</p>", d->m_currentEquity.name()), 0282 i18n("Delete investment"), 0283 KStandardGuiItem::yes(), KStandardGuiItem::no(), 0284 "DeleteInvestment") == KMessageBox::Yes) { 0285 auto file = MyMoneyFile::instance(); 0286 MyMoneyFileTransaction ft; 0287 try { 0288 // d->m_selectedAccount = MyMoneyAccount(); // CAUTION: deleting equity from investments view needs this, if ID of the equity to be deleted is the smallest from all 0289 file->removeAccount(d->m_currentEquity); 0290 ft.commit(); 0291 } catch (const MyMoneyException &e) { 0292 KMessageBox::information(this, i18n("Unable to delete investment: %1", QString::fromLatin1(e.what()))); 0293 } 0294 } else { 0295 // we should not keep the 'no' setting because that can confuse people like 0296 // I have seen in some usability tests. So we just delete it right away. 0297 KSharedConfigPtr kconfig = KSharedConfig::openConfig(); 0298 if (kconfig) { 0299 kconfig->group(QLatin1String("Notification Messages")).deleteEntry(QLatin1String("DeleteInvestment")); 0300 } 0301 } 0302 } 0303 0304 void KInvestmentView::slotUpdatePriceOnline() 0305 { 0306 Q_D(KInvestmentView); 0307 if (!d->m_currentEquity.id().isEmpty()) { 0308 QPointer<KEquityPriceUpdateDlg> dlg = new KEquityPriceUpdateDlg(0, d->m_currentEquity.currencyId()); 0309 if (dlg->exec() == QDialog::Accepted && dlg != nullptr) 0310 dlg->storePrices(); 0311 delete dlg; 0312 } 0313 } 0314 0315 void KInvestmentView::slotUpdatePriceManually() 0316 { 0317 Q_D(KInvestmentView); 0318 if (!d->m_currentEquity.id().isEmpty()) { 0319 try { 0320 auto security = MyMoneyFile::instance()->security(d->m_currentEquity.currencyId()); 0321 auto currency = MyMoneyFile::instance()->security(security.tradingCurrency()); 0322 const auto& price = MyMoneyFile::instance()->price(security.id(), currency.id()); 0323 0324 QPointer<KCurrencyCalculator> calc = 0325 new KCurrencyCalculator(security, currency, MyMoneyMoney::ONE, 0326 price.rate(currency.id()), price.date(), 0327 MyMoneyMoney::precToDenom(security.pricePrecision())); 0328 calc->setupPriceEditor(); 0329 0330 // The dialog takes care of adding the price if necessary 0331 calc->exec(); 0332 delete calc; 0333 } catch (const MyMoneyException &e) { 0334 qDebug("Error in price update: %s", e.what()); 0335 } 0336 } 0337 } 0338 0339 void KInvestmentView::slotEditSecurity() 0340 { 0341 Q_D(KInvestmentView); 0342 auto sec = d->currentSecurity(); 0343 0344 if (!sec.id().isEmpty()) { 0345 QPointer<KNewInvestmentWizard> dlg = new KNewInvestmentWizard(sec, this); 0346 dlg->setObjectName("KNewInvestmentWizard"); 0347 if (dlg->exec() == QDialog::Accepted) 0348 dlg->createObjects(QString()); 0349 delete dlg; 0350 } 0351 } 0352 0353 void KInvestmentView::slotDeleteSecurity() 0354 { 0355 Q_D(KInvestmentView); 0356 auto sec = d->currentSecurity(); 0357 if (!sec.id().isEmpty()) 0358 KMyMoneyUtils::deleteSecurity(sec, this); 0359 }