File indexing completed on 2024-05-12 16:43:49
0001 /* 0002 SPDX-FileCopyrightText: 2000-2001 Michael Edwardes <mte@users.sourceforge.net> 0003 SPDX-FileCopyrightText: 2004 Thomas Baumgart <ipwizard@users.sourceforge.net> 0004 SPDX-FileCopyrightText: 2017, 2018 Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com> 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include <config-kmymoney.h> 0009 #include "kmymoneyview.h" 0010 0011 // ---------------------------------------------------------------------------- 0012 // Std Includes 0013 0014 #include <memory> 0015 0016 // ---------------------------------------------------------------------------- 0017 // QT Includes 0018 0019 #include <QFile> 0020 #include <QRegExp> 0021 #include <QLayout> 0022 #include <QList> 0023 #include <QByteArray> 0024 #include <QUrl> 0025 #include <QIcon> 0026 #include <QTemporaryFile> 0027 #include <QUrlQuery> 0028 0029 // ---------------------------------------------------------------------------- 0030 // KDE Includes 0031 0032 #include <KMessageBox> 0033 #include <KTitleWidget> 0034 #include <KSharedConfig> 0035 #include <KBackup> 0036 #include <KActionCollection> 0037 #include <KIO/StoredTransferJob> 0038 #include <KJobWidgets> 0039 #include <KLocalizedString> 0040 0041 // ---------------------------------------------------------------------------- 0042 // Project Includes 0043 0044 #ifdef ENABLE_UNFINISHEDFEATURES 0045 #include "simpleledgerview.h" 0046 #endif 0047 0048 #include "kmymoneysettings.h" 0049 #include "kmymoneytitlelabel.h" 0050 #include "kcurrencyeditdlg.h" 0051 #include "mymoneyexception.h" 0052 #include "khomeview.h" 0053 #include "kaccountsview.h" 0054 #include "kcategoriesview.h" 0055 #include "kinstitutionsview.h" 0056 #include "kpayeesview.h" 0057 #include "ktagsview.h" 0058 #include "kscheduledview.h" 0059 #include "kgloballedgerview.h" 0060 #include "kinvestmentview.h" 0061 #include "models.h" 0062 #include "accountsmodel.h" 0063 #include "equitiesmodel.h" 0064 #include "securitiesmodel.h" 0065 #include "icons.h" 0066 #include "onlinejobadministration.h" 0067 #include "kmymoneyaccounttreeview.h" 0068 #include "accountsviewproxymodel.h" 0069 #include "mymoneymoney.h" 0070 #include "mymoneyprice.h" 0071 #include "mymoneyschedule.h" 0072 #include "mymoneysplit.h" 0073 #include "mymoneyaccount.h" 0074 #include "mymoneyinstitution.h" 0075 #include "mymoneytag.h" 0076 #include "mymoneyfile.h" 0077 #include "mymoneysecurity.h" 0078 #include "mymoneyreport.h" 0079 #include "kmymoneyplugin.h" 0080 #include "mymoneyenums.h" 0081 #include "menuenums.h" 0082 0083 using namespace Icons; 0084 using namespace eMyMoney; 0085 0086 typedef void(KMyMoneyView::*KMyMoneyViewFunc)(); 0087 0088 KMyMoneyView::KMyMoneyView() 0089 : KPageWidget(nullptr), 0090 m_header(0) 0091 { 0092 // this is a workaround for the bug in KPageWidget that causes the header to be shown 0093 // for a short while during page switch which causes a kind of bouncing of the page's 0094 // content and if the page's content is at it's minimum size then during a page switch 0095 // the main window's size is also increased to fit the header that is shown for a sort 0096 // period - reading the code in kpagewidget.cpp we know that the header should be at (1,1) 0097 // in a grid layout so if we find it there remove it for good to avoid the described issues 0098 QGridLayout* gridLayout = qobject_cast<QGridLayout*>(layout()); 0099 if (gridLayout) { 0100 QLayoutItem* headerItem = gridLayout->itemAtPosition(1, 1); 0101 // make sure that we remove only the header - we avoid surprises if the header is not at (1,1) in the layout 0102 if (headerItem && qobject_cast<KTitleWidget*>(headerItem->widget()) != NULL) { 0103 gridLayout->removeItem(headerItem); 0104 // after we remove the KPageWidget standard header replace it with our own title label 0105 m_header = new KMyMoneyTitleLabel(this); 0106 m_header->setObjectName("titleLabel"); 0107 m_header->setMinimumSize(QSize(100, 30)); 0108 m_header->setRightImageFile("pics/titlelabel_background.png"); 0109 m_header->setVisible(KMyMoneySettings::showTitleBar()); 0110 gridLayout->addWidget(m_header, 1, 1); 0111 } 0112 } 0113 0114 // newStorage(); 0115 m_model = new KPageWidgetModel(this); // cannot be parentless, otherwise segfaults at exit 0116 0117 viewBases[View::Home] = new KHomeView; 0118 viewBases[View::Institutions] = new KInstitutionsView; 0119 viewBases[View::Accounts] = new KAccountsView; 0120 viewBases[View::Schedules] = new KScheduledView; 0121 viewBases[View::Categories] = new KCategoriesView; 0122 viewBases[View::Tags] = new KTagsView; 0123 viewBases[View::Payees] = new KPayeesView; 0124 viewBases[View::Ledgers] = new KGlobalLedgerView; 0125 viewBases[View::Investments] = new KInvestmentView; 0126 #ifdef ENABLE_UNFINISHEDFEATURES 0127 viewBases[View::NewLedgers] = new SimpleLedgerView; 0128 #endif 0129 0130 struct viewInfo 0131 { 0132 View id; 0133 QString name; 0134 Icon icon; 0135 }; 0136 0137 const QVector<viewInfo> viewsInfo 0138 { 0139 {View::Home, i18n("Home"), Icon::Home}, 0140 {View::Institutions, i18n("Institutions"), Icon::Institutions}, 0141 {View::Accounts, i18n("Accounts"), Icon::Accounts}, 0142 {View::Schedules, i18n("Scheduled\ntransactions"), Icon::Schedule}, 0143 {View::Categories, i18n("Categories"), Icon::FinancialCategories}, 0144 {View::Tags, i18n("Tags"), Icon::Tags}, 0145 {View::Payees, i18n("Payees"), Icon::Payees}, 0146 {View::Ledgers, i18n("Ledgers"), Icon::Ledger}, 0147 {View::Investments, i18n("Investments"), Icon::Investments}, 0148 #ifdef ENABLE_UNFINISHEDFEATURES 0149 {View::NewLedgers, i18n("New ledger"), Icon::DocumentProperties}, 0150 #endif 0151 }; 0152 0153 for (const viewInfo& view : viewsInfo) { 0154 addView(viewBases[view.id], view.name, view.id, view.icon); 0155 } 0156 0157 connect(Models::instance()->accountsModel(), &AccountsModel::netWorthChanged, this, &KMyMoneyView::slotSelectByVariant); 0158 connect(Models::instance()->accountsModel(), &AccountsModel::profitChanged, this, &KMyMoneyView::slotSelectByVariant); 0159 connect(Models::instance()->institutionsModel(), &AccountsModel::netWorthChanged, this, &KMyMoneyView::slotSelectByVariant); 0160 connect(Models::instance()->institutionsModel(), &AccountsModel::profitChanged, this, &KMyMoneyView::slotSelectByVariant); 0161 0162 // set the model 0163 setModel(m_model); 0164 setCurrentPage(viewFrames[View::Home]); 0165 connect(this, SIGNAL(currentPageChanged(QModelIndex,QModelIndex)), this, SLOT(slotCurrentPageChanged(QModelIndex,QModelIndex))); 0166 0167 updateViewType(); 0168 } 0169 0170 KMyMoneyView::~KMyMoneyView() 0171 { 0172 } 0173 0174 void KMyMoneyView::slotFileOpened() 0175 { 0176 if (viewBases.contains(View::OnlineJobOutbox)) 0177 viewBases[View::OnlineJobOutbox]->executeCustomAction(eView::Action::InitializeAfterFileOpen); 0178 0179 if (viewBases.contains(View::Ledgers)) 0180 viewBases[View::Ledgers]->executeCustomAction(eView::Action::InitializeAfterFileOpen); 0181 0182 #ifdef ENABLE_UNFINISHEDFEATURES 0183 static_cast<SimpleLedgerView*>(viewBases[View::NewLedgers])->openFavoriteLedgers(); 0184 #endif 0185 // delay the switchToDefaultView call until the event loop is running 0186 QMetaObject::invokeMethod(this, "switchToDefaultView", Qt::QueuedConnection); 0187 slotObjectSelected(MyMoneyAccount()); // in order to enable update all accounts on file reload 0188 } 0189 0190 void KMyMoneyView::slotFileClosed() 0191 { 0192 slotShowHomePage(); 0193 if (viewBases.contains(View::Home)) 0194 viewBases[View::Home]->executeCustomAction(eView::Action::CleanupBeforeFileClose); 0195 0196 if (viewBases.contains(View::Reports)) 0197 viewBases[View::Reports]->executeCustomAction(eView::Action::CleanupBeforeFileClose); 0198 0199 if (viewBases.contains(View::OnlineJobOutbox)) 0200 viewBases[View::OnlineJobOutbox]->executeCustomAction(eView::Action::CleanupBeforeFileClose); 0201 0202 if (viewBases.contains(View::Ledgers)) 0203 viewBases[View::Ledgers]->executeCustomAction(eView::Action::CleanupBeforeFileClose); 0204 0205 #ifdef ENABLE_UNFINISHEDFEATURES 0206 static_cast<SimpleLedgerView*>(viewBases[View::NewLedgers])->closeLedgers(); 0207 #endif 0208 0209 pActions[eMenu::Action::Print]->setEnabled(false); 0210 pActions[eMenu::Action::AccountCreditTransfer]->setEnabled(false); 0211 pActions[eMenu::Action::UpdateAllAccounts]->setEnabled(false); 0212 } 0213 0214 void KMyMoneyView::slotShowHomePage() 0215 { 0216 showPageAndFocus(View::Home); 0217 } 0218 0219 void KMyMoneyView::slotShowInstitutionsPage() 0220 { 0221 showPageAndFocus(View::Institutions); 0222 } 0223 0224 void KMyMoneyView::slotShowAccountsPage() 0225 { 0226 showPageAndFocus(View::Accounts); 0227 } 0228 0229 void KMyMoneyView::slotShowSchedulesPage() 0230 { 0231 showPageAndFocus(View::Schedules); 0232 } 0233 0234 void KMyMoneyView::slotShowCategoriesPage() 0235 { 0236 showPageAndFocus(View::Categories); 0237 } 0238 0239 void KMyMoneyView::slotShowTagsPage() 0240 { 0241 showPageAndFocus(View::Tags); 0242 } 0243 0244 void KMyMoneyView::slotShowPayeesPage() 0245 { 0246 showPageAndFocus(View::Payees); 0247 } 0248 0249 void KMyMoneyView::slotShowLedgersPage() 0250 { 0251 showPageAndFocus(View::Ledgers); 0252 } 0253 0254 void KMyMoneyView::slotShowInvestmentsPage() 0255 { 0256 showPageAndFocus(View::Investments); 0257 } 0258 0259 void KMyMoneyView::slotShowReportsPage() 0260 { 0261 showPageAndFocus(View::Reports); 0262 } 0263 0264 void KMyMoneyView::slotShowBudgetPage() 0265 { 0266 showPageAndFocus(View::Budget); 0267 } 0268 0269 void KMyMoneyView::slotShowForecastPage() 0270 { 0271 showPageAndFocus(View::Forecast); 0272 } 0273 0274 void KMyMoneyView::slotShowOutboxPage() 0275 { 0276 showPageAndFocus(View::OnlineJobOutbox); 0277 } 0278 0279 void KMyMoneyView::showTitleBar(bool show) 0280 { 0281 if (m_header) 0282 m_header->setVisible(show); 0283 } 0284 0285 void KMyMoneyView::updateViewType() 0286 { 0287 // set the face type 0288 KPageView::FaceType faceType = KPageView::List; 0289 switch (KMyMoneySettings::viewType()) { 0290 case 0: 0291 faceType = KPageView::List; 0292 break; 0293 case 1: 0294 faceType = KPageView::Tree; 0295 break; 0296 case 2: 0297 faceType = KPageView::Tabbed; 0298 break; 0299 } 0300 if (faceType != KMyMoneyView::faceType()) { 0301 setFaceType(faceType); 0302 if (faceType == KPageView::Tree) { 0303 QList<QTreeView *> views = findChildren<QTreeView*>(); 0304 foreach (QTreeView * view, views) { 0305 if (view && (view->parent() == this)) { 0306 view->setRootIsDecorated(false); 0307 break; 0308 } 0309 } 0310 } 0311 } 0312 } 0313 0314 void KMyMoneyView::slotAccountTreeViewChanged(const eAccountsModel::Column column, const bool show) 0315 { 0316 QVector<AccountsViewProxyModel *> proxyModels 0317 { 0318 static_cast<KMyMoneyAccountsViewBase*>(viewBases[View::Institutions])->getProxyModel(), 0319 static_cast<KMyMoneyAccountsViewBase*>(viewBases[View::Accounts])->getProxyModel(), 0320 static_cast<KMyMoneyAccountsViewBase*>(viewBases[View::Categories])->getProxyModel() 0321 }; 0322 0323 if (viewBases.contains(View::Budget)) 0324 proxyModels.append(static_cast<KMyMoneyAccountsViewBase*>(viewBases[View::Budget])->getProxyModel()); 0325 0326 for (auto i = proxyModels.count() - 1; i >= 0; --i) { // weed out unloaded views 0327 if (!proxyModels.at(i)) 0328 proxyModels.removeAt(i); 0329 } 0330 0331 QString question; 0332 0333 if (show) 0334 question = i18n("Do you want to show <b>%1</b> column on every loaded view?", AccountsModel::getHeaderName(column)); 0335 else 0336 question = i18n("Do you want to hide <b>%1</b> column on every loaded view?", AccountsModel::getHeaderName(column)); 0337 0338 0339 if (proxyModels.count() == 1 || // no need to ask what to do with other views because they aren't loaded 0340 KMessageBox::questionYesNo(this, 0341 question, 0342 QString(), 0343 KStandardGuiItem::yes(), KStandardGuiItem::no(), 0344 QStringLiteral("ShowColumnOnEveryView")) == KMessageBox::Yes) { 0345 Models::instance()->accountsModel()->setColumnVisibility(column, show); 0346 Models::instance()->institutionsModel()->setColumnVisibility(column, show); 0347 foreach(AccountsViewProxyModel *proxyModel, proxyModels) { 0348 if (!proxyModel) 0349 continue; 0350 proxyModel->setColumnVisibility(column, show); 0351 proxyModel->invalidate(); 0352 } 0353 } else if(show) { 0354 // in case we need to show it, we have to make sure to set the visibility 0355 // in the base model as well. Otherwise, we don't see the column through the proxy model 0356 Models::instance()->accountsModel()->setColumnVisibility(column, show); 0357 Models::instance()->institutionsModel()->setColumnVisibility(column, show); 0358 } 0359 } 0360 0361 void KMyMoneyView::setOnlinePlugins(QMap<QString, KMyMoneyPlugin::OnlinePlugin*>& plugins) 0362 { 0363 if (viewBases.contains(View::Accounts)) 0364 viewBases[View::Accounts]->slotSelectByVariant(QVariantList {QVariant::fromValue(static_cast<void*>(&plugins))}, eView::Intent::SetOnlinePlugins); 0365 0366 if (viewBases.contains(View::OnlineJobOutbox)) 0367 viewBases[View::OnlineJobOutbox]->slotSelectByVariant(QVariantList {QVariant::fromValue(static_cast<void*>(&plugins))}, eView::Intent::SetOnlinePlugins); 0368 } 0369 0370 eDialogs::ScheduleResultCode KMyMoneyView::enterSchedule(MyMoneySchedule& schedule, bool autoEnter, bool extendedKeys) 0371 { 0372 return static_cast<KScheduledView*>(viewBases[View::Schedules])->enterSchedule(schedule, autoEnter, extendedKeys); 0373 } 0374 0375 void KMyMoneyView::addView(KMyMoneyViewBase* view, const QString& name, View idView, Icons::Icon icon) 0376 { 0377 /* There is a bug in 0378 * static int layoutText(QTextLayout *layout, int maxWidth) 0379 * from kpageview_p.cpp from kwidgetsaddons. 0380 * The method doesn't break strings that are too long. Following line 0381 * workarounds this by using LINE SEPARATOR character which is accepted by 0382 * QTextLayout::createLine().*/ 0383 auto adjustedName(name); 0384 adjustedName.replace(QLatin1Char('\n'), QString::fromUtf8("\xe2\x80\xa8")); 0385 0386 auto isViewInserted = false; 0387 for (auto i = (int)idView; i < (int)View::None; ++i) { 0388 if (viewFrames.contains((View)i)) { 0389 viewFrames[idView] = m_model->insertPage(viewFrames[(View)i],view, adjustedName); 0390 isViewInserted = true; 0391 break; 0392 } 0393 } 0394 0395 if (!isViewInserted) 0396 viewFrames[idView] = m_model->addPage(view, adjustedName); 0397 0398 viewFrames[idView]->setIcon(Icons::get(icon)); 0399 viewBases[idView] = view; 0400 connect(viewBases[idView], &KMyMoneyViewBase::selectByObject, this, &KMyMoneyView::slotSelectByObject); 0401 connect(viewBases[idView], &KMyMoneyViewBase::selectByVariant, this, &KMyMoneyView::slotSelectByVariant); 0402 connect(viewBases[idView], &KMyMoneyViewBase::customActionRequested, this, &KMyMoneyView::slotCustomActionRequested); 0403 } 0404 0405 void KMyMoneyView::removeView(View idView) 0406 { 0407 if (!viewBases.contains(idView)) 0408 return; 0409 0410 disconnect(viewBases[idView], &KMyMoneyViewBase::selectByObject, this, &KMyMoneyView::slotSelectByObject); 0411 disconnect(viewBases[idView], &KMyMoneyViewBase::selectByVariant, this, &KMyMoneyView::slotSelectByVariant); 0412 disconnect(viewBases[idView], &KMyMoneyViewBase::customActionRequested, this, &KMyMoneyView::slotCustomActionRequested); 0413 0414 m_model->removePage(viewFrames[idView]); 0415 viewFrames.remove(idView); 0416 viewBases.remove(idView); 0417 } 0418 0419 QHash<eMenu::Action, QAction *> KMyMoneyView::actionsToBeConnected() 0420 { 0421 using namespace eMenu; 0422 // add fast switching of main views through Ctrl + NUM_X 0423 struct pageInfo { 0424 Action view; 0425 KMyMoneyViewFunc callback; 0426 QString text; 0427 QKeySequence shortcut = QKeySequence(); 0428 }; 0429 0430 const QVector<pageInfo> pageInfos { 0431 {Action::ShowHomeView, &KMyMoneyView::slotShowHomePage, i18n("Show home page"), Qt::CTRL + Qt::Key_1}, 0432 {Action::ShowInstitutionsView, &KMyMoneyView::slotShowInstitutionsPage, i18n("Show institutions page"), Qt::CTRL + Qt::Key_2}, 0433 {Action::ShowAccountsView, &KMyMoneyView::slotShowAccountsPage, i18n("Show accounts page"), Qt::CTRL + Qt::Key_3}, 0434 {Action::ShowSchedulesView, &KMyMoneyView::slotShowSchedulesPage, i18n("Show scheduled transactions page"), Qt::CTRL + Qt::Key_4}, 0435 {Action::ShowCategoriesView, &KMyMoneyView::slotShowCategoriesPage, i18n("Show categories page"), Qt::CTRL + Qt::Key_5}, 0436 {Action::ShowTagsView, &KMyMoneyView::slotShowTagsPage, i18n("Show tags page"), }, 0437 {Action::ShowPayeesView, &KMyMoneyView::slotShowPayeesPage, i18n("Show payees page"), Qt::CTRL + Qt::Key_6}, 0438 {Action::ShowLedgersView, &KMyMoneyView::slotShowLedgersPage, i18n("Show ledgers page"), Qt::CTRL + Qt::Key_7}, 0439 {Action::ShowInvestmentsView, &KMyMoneyView::slotShowInvestmentsPage, i18n("Show investments page"), Qt::CTRL + Qt::Key_8}, 0440 {Action::ShowReportsView, &KMyMoneyView::slotShowReportsPage, i18n("Show reports page"), Qt::CTRL + Qt::Key_9}, 0441 {Action::ShowBudgetView, &KMyMoneyView::slotShowBudgetPage, i18n("Show budget page"), }, 0442 {Action::ShowForecastView, &KMyMoneyView::slotShowForecastPage, i18n("Show forecast page"), }, 0443 {Action::ShowOnlineJobOutboxView, &KMyMoneyView::slotShowOutboxPage, i18n("Show outbox page") }, 0444 }; 0445 0446 QHash<Action, QAction *> lutActions; 0447 auto pageCount = 0; 0448 for (const pageInfo& info : pageInfos) { 0449 auto a = new QAction(this); 0450 // KActionCollection::addAction by name sets object name anyways, 0451 // so, as better alternative, set it here right from the start 0452 a->setObjectName(QString::fromLatin1("ShowPage%1").arg(QString::number(pageCount++))); 0453 a->setText(info.text); 0454 connect(a, &QAction::triggered, this, info.callback); 0455 lutActions.insert(info.view, a); // store QAction's pointer for later processing 0456 if (!info.shortcut.isEmpty()) 0457 a->setShortcut(info.shortcut); 0458 } 0459 return lutActions; 0460 } 0461 0462 bool KMyMoneyView::showPageHeader() const 0463 { 0464 return false; 0465 } 0466 0467 void KMyMoneyView::showPageAndFocus(View idView) 0468 { 0469 if (viewFrames.contains(idView)) { 0470 showPage(idView); 0471 viewBases[idView]->executeCustomAction(eView::Action::SetDefaultFocus); 0472 } 0473 } 0474 0475 void KMyMoneyView::showPage(View idView) 0476 { 0477 if (!viewFrames.contains(idView) || 0478 currentPage() == viewFrames[idView]) 0479 return; 0480 0481 resetViewSelection(); 0482 setCurrentPage(viewFrames[idView]); 0483 } 0484 0485 bool KMyMoneyView::canPrint() 0486 { 0487 return (MyMoneyFile::instance()->storageAttached() && 0488 ((viewFrames.contains(View::Reports) && viewFrames[View::Reports] == currentPage()) || 0489 (viewFrames.contains(View::Home) && viewFrames[View::Home] == currentPage())) 0490 ); 0491 } 0492 0493 void KMyMoneyView::enableViewsIfFileOpen(bool fileOpen) 0494 { 0495 // call set enabled only if the state differs to avoid widgets 'bouncing on the screen' while doing this 0496 Q_ASSERT_X(((int)(View::Home)+1) == (int)View::Institutions, "viewenums.h", "View::Home must be first and View::Institutions second entry"); 0497 0498 for (auto i = (int)View::Institutions; i < (int)View::None; ++i) 0499 if (viewFrames.contains(View(i))) 0500 if (viewFrames[View(i)]->isEnabled() != fileOpen) 0501 viewFrames[View(i)]->setEnabled(fileOpen); 0502 0503 emit viewStateChanged(fileOpen); 0504 } 0505 0506 void KMyMoneyView::switchToDefaultView() 0507 { 0508 const auto idView = KMyMoneySettings::startLastViewSelected() ? 0509 static_cast<View>(KMyMoneySettings::lastViewSelected()) : 0510 View::Home; 0511 // if we currently see a different page, then select the right one 0512 if (viewFrames.contains(idView) && viewFrames[idView] != currentPage()) 0513 showPage(idView); 0514 } 0515 0516 void KMyMoneyView::slotPayeeSelected(const QString& payee, const QString& account, const QString& transaction) 0517 { 0518 showPage(View::Payees); 0519 static_cast<KPayeesView*>(viewBases[View::Payees])->slotSelectPayeeAndTransaction(payee, account, transaction); 0520 } 0521 0522 void KMyMoneyView::slotTagSelected(const QString& tag, const QString& account, const QString& transaction) 0523 { 0524 showPage(View::Tags); 0525 static_cast<KTagsView*>(viewBases[View::Tags])->slotSelectTagAndTransaction(tag, account, transaction); 0526 } 0527 0528 void KMyMoneyView::finishReconciliation(const MyMoneyAccount& /* account */) 0529 { 0530 Models::instance()->accountsModel()->slotReconcileAccount(MyMoneyAccount(), QDate(), MyMoneyMoney()); 0531 static_cast<KGlobalLedgerView*>(viewBases[View::Ledgers])->slotSetReconcileAccount(MyMoneyAccount(), QDate(), MyMoneyMoney()); 0532 } 0533 0534 void KMyMoneyView::viewAccountList(const QString& /*selectAccount*/) 0535 { 0536 if (viewFrames[View::Accounts] != currentPage()) 0537 showPage(View::Accounts); 0538 viewBases[View::Accounts]->show(); 0539 } 0540 0541 void KMyMoneyView::slotRefreshViews() 0542 { 0543 showTitleBar(KMyMoneySettings::showTitleBar()); 0544 0545 for (auto i = (int)View::Home; i < (int)View::None; ++i) 0546 if (viewBases.contains(View(i))) 0547 viewBases[View(i)]->executeCustomAction(eView::Action::Refresh); 0548 0549 viewBases[View::Payees]->executeCustomAction(eView::Action::ClosePayeeIdentifierSource); 0550 } 0551 0552 void KMyMoneyView::slotShowTransactionDetail(bool detailed) 0553 { 0554 KMyMoneySettings::setShowRegisterDetailed(detailed); 0555 slotRefreshViews(); 0556 } 0557 0558 void KMyMoneyView::slotCurrentPageChanged(const QModelIndex current, const QModelIndex previous) 0559 { 0560 // set the current page's title in the header 0561 if (m_header) 0562 m_header->setText(m_model->data(current, KPageModel::HeaderRole).toString()); 0563 0564 const auto view = currentPage(); 0565 // remember the selected view if there is a real change 0566 if (previous.isValid()) { 0567 QHash<View, KPageWidgetItem*>::const_iterator it; 0568 for(it = viewFrames.cbegin(); it != viewFrames.cend(); ++it) { 0569 if ((*it) == view) { 0570 emit viewActivated(it.key()); 0571 break; 0572 } 0573 } 0574 } 0575 0576 if (viewBases.contains(View::Ledgers) && view != viewFrames.value(View::Ledgers)) 0577 viewBases[View::Ledgers]->executeCustomAction(eView::Action::DisableViewDepenedendActions); 0578 0579 pActions[eMenu::Action::Print]->setEnabled(canPrint()); 0580 pActions[eMenu::Action::AccountCreditTransfer]->setEnabled(onlineJobAdministration::instance()->canSendCreditTransfer()); 0581 } 0582 0583 void KMyMoneyView::createSchedule(MyMoneySchedule newSchedule, MyMoneyAccount& newAccount) 0584 { 0585 // Add the schedule only if one exists 0586 // 0587 // Remember to modify the first split to reference the newly created account 0588 if (!newSchedule.name().isEmpty()) { 0589 MyMoneyFileTransaction ft; 0590 try { 0591 // We assume at least 2 splits in the transaction 0592 MyMoneyTransaction t = newSchedule.transaction(); 0593 if (t.splitCount() < 2) { 0594 throw MYMONEYEXCEPTION_CSTRING("Transaction for schedule has less than 2 splits!"); 0595 } 0596 // now search the split that does not have an account reference 0597 // and set it up to be the one of the account we just added 0598 // to the account pool. Note: the schedule code used to leave 0599 // this always the first split, but the loan code leaves it as 0600 // the second one. So I thought, searching is a good alternative .... 0601 foreach (const auto split, t.splits()) { 0602 if (split.accountId().isEmpty()) { 0603 MyMoneySplit s = split; 0604 s.setAccountId(newAccount.id()); 0605 t.modifySplit(s); 0606 break; 0607 } 0608 } 0609 newSchedule.setTransaction(t); 0610 0611 MyMoneyFile::instance()->addSchedule(newSchedule); 0612 0613 // in case of a loan account, we keep a reference to this 0614 // schedule in the account 0615 if (newAccount.isLoan()) { 0616 newAccount.setValue("schedule", newSchedule.id()); 0617 MyMoneyFile::instance()->modifyAccount(newAccount); 0618 } 0619 ft.commit(); 0620 } catch (const MyMoneyException &e) { 0621 KMessageBox::information(this, i18n("Unable to add schedule: %1", QString::fromLatin1(e.what()))); 0622 } 0623 } 0624 } 0625 0626 void KMyMoneyView::slotPrintView() 0627 { 0628 if (viewFrames.contains(View::Reports) && viewFrames[View::Reports] == currentPage()) 0629 viewBases[View::Reports]->executeCustomAction(eView::Action::Print); 0630 else if (viewFrames.contains(View::Home) && viewFrames[View::Home] == currentPage()) 0631 viewBases[View::Home]->executeCustomAction(eView::Action::Print); 0632 } 0633 0634 void KMyMoneyView::resetViewSelection() 0635 { 0636 if (!MyMoneyFile::instance()->storageAttached()) 0637 return; 0638 slotObjectSelected(MyMoneyAccount()); 0639 slotObjectSelected(MyMoneyInstitution()); 0640 slotObjectSelected(MyMoneySchedule()); 0641 slotObjectSelected(MyMoneyTag()); 0642 slotSelectByVariant(QVariantList {QVariant::fromValue(KMyMoneyRegister::SelectedTransactions())}, eView::Intent::SelectRegisterTransactions); 0643 } 0644 0645 void KMyMoneyView::slotOpenObjectRequested(const MyMoneyObject& obj) 0646 { 0647 if (typeid(obj) == typeid(MyMoneyAccount)) { 0648 const auto& acc = static_cast<const MyMoneyAccount&>(obj); 0649 // check if we can open this account 0650 // currently it make's sense for asset and liability accounts 0651 if (!MyMoneyFile::instance()->isStandardAccount(acc.id())) 0652 if (viewBases.contains(View::Ledgers)) 0653 viewBases[View::Ledgers]->slotSelectByVariant(QVariantList {QVariant(acc.id()), QVariant(QString()) }, eView::Intent::ShowTransaction ); 0654 0655 } else if (typeid(obj) == typeid(MyMoneyInstitution)) { 0656 // const auto& inst = static_cast<const MyMoneyInstitution&>(obj); 0657 if (viewBases.contains(View::Institutions)) 0658 viewBases[View::Institutions]->executeCustomAction(eView::Action::EditInstitution); 0659 } else if (typeid(obj) == typeid(MyMoneySchedule)) { 0660 if (viewBases.contains(View::Schedules)) 0661 viewBases[View::Schedules]->executeCustomAction(eView::Action::EditSchedule); 0662 } else if (typeid(obj) == typeid(MyMoneyReport)) { 0663 // const auto& rep = static_cast<const MyMoneyReport&>(obj); 0664 showPage(View::Reports); 0665 if (viewBases.contains(View::Reports)) 0666 viewBases[View::Reports]->slotSelectByObject(obj, eView::Intent::OpenObject); 0667 } 0668 } 0669 0670 void KMyMoneyView::slotSelectByObject(const MyMoneyObject& obj, eView::Intent intent) 0671 { 0672 switch (intent) { 0673 case eView::Intent::None: 0674 slotObjectSelected(obj); 0675 break; 0676 0677 case eView::Intent::SynchronizeAccountInInvestmentView: 0678 if (viewBases.contains(View::Investments)) 0679 viewBases[View::Investments]->slotSelectByObject(obj, intent); 0680 break; 0681 0682 case eView::Intent::SynchronizeAccountInLedgersView: 0683 if (viewBases.contains(View::Ledgers)) 0684 viewBases[View::Ledgers]->slotSelectByObject(obj, intent); 0685 break; 0686 0687 case eView::Intent::OpenObject: 0688 slotOpenObjectRequested(obj); 0689 break; 0690 0691 case eView::Intent::OpenContextMenu: 0692 slotContextMenuRequested(obj); 0693 break; 0694 0695 case eView::Intent::StartEnteringOverdueScheduledTransactions: 0696 if (viewBases.contains(View::Schedules)) 0697 viewBases[View::Schedules]->slotSelectByObject(obj, intent); 0698 break; 0699 0700 case eView::Intent::FinishEnteringOverdueScheduledTransactions: 0701 if (viewBases.contains(View::Ledgers)) { 0702 showPage(View::Ledgers); 0703 viewBases[View::Ledgers]->slotSelectByObject(obj, intent); 0704 } 0705 break; 0706 0707 default: 0708 break; 0709 } 0710 } 0711 0712 void KMyMoneyView::slotSelectByVariant(const QVariantList& variant, eView::Intent intent) 0713 { 0714 switch(intent) { 0715 case eView::Intent::ReportProgress: 0716 if (variant.count() == 2) 0717 emit statusProgress(variant.at(0).toInt(), variant.at(1).toInt()); 0718 break; 0719 0720 case eView::Intent::ReportProgressMessage: 0721 if (variant.count() == 1) 0722 emit statusMsg(variant.first().toString()); 0723 break; 0724 0725 case eView::Intent::UpdateNetWorth: 0726 if (viewBases.contains(View::Accounts)) 0727 viewBases[View::Accounts]->slotSelectByVariant(variant, intent); 0728 0729 if (viewBases.contains(View::Institutions)) 0730 viewBases[View::Institutions]->slotSelectByVariant(variant, intent); 0731 break; 0732 0733 case eView::Intent::UpdateProfit: 0734 if (viewBases.contains(View::Categories)) 0735 viewBases[View::Categories]->slotSelectByVariant(variant, intent); 0736 break; 0737 0738 case eView::Intent::ShowTransaction: 0739 if (viewBases.contains(View::Ledgers)) { 0740 showPage(View::Ledgers); 0741 viewBases[View::Ledgers]->slotSelectByVariant(variant, intent); 0742 } 0743 break; 0744 0745 case eView::Intent::ToggleColumn: 0746 if (variant.count() == 2) 0747 slotAccountTreeViewChanged(variant.at(0).value<eAccountsModel::Column>(), variant.at(1).value<bool>()); 0748 break; 0749 0750 case eView::Intent::ShowPayee: 0751 if (viewBases.contains(View::Payees)) { 0752 showPage(View::Payees); 0753 viewBases[View::Payees]->slotSelectByVariant(variant, intent); 0754 } 0755 break; 0756 0757 case eView::Intent::SelectRegisterTransactions: 0758 if (variant.count() == 1) { 0759 emit transactionsSelected(variant.at(0).value<KMyMoneyRegister::SelectedTransactions>()); // for plugins 0760 if (viewBases.contains(View::Ledgers)) 0761 viewBases[View::Ledgers]->slotSelectByVariant(variant, intent); 0762 } 0763 break; 0764 0765 case eView::Intent::AccountReconciled: 0766 if (variant.count() == 5) 0767 emit accountReconciled(variant.at(0).value<MyMoneyAccount>(), 0768 variant.at(1).value<QDate>(), 0769 variant.at(2).value<MyMoneyMoney>(), 0770 variant.at(3).value<MyMoneyMoney>(), 0771 variant.at(4).value<QList<QPair<MyMoneyTransaction, MyMoneySplit>>>()); // for plugins 0772 break; 0773 0774 default: 0775 break; 0776 } 0777 } 0778 0779 void KMyMoneyView::slotCustomActionRequested(View view, eView::Action action) 0780 { 0781 switch (action) { 0782 case eView::Action::AboutToShow: 0783 resetViewSelection(); 0784 break; 0785 case eView::Action::SwitchView: 0786 showPage(view); 0787 break; 0788 case eView::Action::ShowBalanceChart: 0789 if (viewBases.contains(View::Reports)) 0790 viewBases[View::Reports]->executeCustomAction(action); 0791 break; 0792 default: 0793 break; 0794 } 0795 } 0796 0797 void KMyMoneyView::slotObjectSelected(const MyMoneyObject& obj) 0798 { 0799 // carrying some slots over to views isn't easy for all slots... 0800 // ...so calls to kmymoney still must be here 0801 if (typeid(obj) == typeid(MyMoneyAccount)) { 0802 QVector<View> views {View::Investments, View::Categories, View::Accounts, 0803 View::Ledgers, View::Reports, View::OnlineJobOutbox}; 0804 for (const auto view : views) 0805 if (viewBases.contains(view)) 0806 viewBases[view]->slotSelectByObject(obj, eView::Intent::UpdateActions); 0807 0808 // for plugin only 0809 const auto& acc = static_cast<const MyMoneyAccount&>(obj); 0810 if (!acc.isIncomeExpense() && 0811 !MyMoneyFile::instance()->isStandardAccount(acc.id())) 0812 emit accountSelected(acc); 0813 } else if (typeid(obj) == typeid(MyMoneyInstitution)) { 0814 viewBases[View::Institutions]->slotSelectByObject(obj, eView::Intent::UpdateActions); 0815 } else if (typeid(obj) == typeid(MyMoneySchedule)) { 0816 viewBases[View::Schedules]->slotSelectByObject(obj, eView::Intent::UpdateActions); 0817 } 0818 } 0819 0820 void KMyMoneyView::slotContextMenuRequested(const MyMoneyObject& obj) 0821 { 0822 if (typeid(obj) == typeid(MyMoneyAccount)) { 0823 const auto& acc = static_cast<const MyMoneyAccount&>(obj); 0824 if (acc.isInvest()) 0825 viewBases[View::Investments]->slotSelectByObject(obj, eView::Intent::OpenContextMenu); 0826 else if (acc.isIncomeExpense()) 0827 viewBases[View::Categories]->slotSelectByObject(obj, eView::Intent::OpenContextMenu); 0828 else 0829 viewBases[View::Accounts]->slotSelectByObject(obj, eView::Intent::OpenContextMenu); 0830 0831 } else if (typeid(obj) == typeid(MyMoneyInstitution)) { 0832 viewBases[View::Institutions]->slotSelectByObject(obj, eView::Intent::OpenContextMenu); 0833 } else if (typeid(obj) == typeid(MyMoneySchedule)) { 0834 viewBases[View::Schedules]->slotSelectByObject(obj, eView::Intent::OpenContextMenu); 0835 } 0836 }