File indexing completed on 2024-06-16 04:46:40
0001 /* 0002 SPDX-FileCopyrightText: 2000-2004 Michael Edwardes <mte@users.sourceforge.net> 0003 SPDX-FileCopyrightText: 2000-2004 Javier Campos Morales <javi_c@users.sourceforge.net> 0004 SPDX-FileCopyrightText: 2000-2004 Felix Rodriguez <frodriguez@users.sourceforge.net> 0005 SPDX-FileCopyrightText: 2000-2004 John C <thetacoturtle@users.sourceforge.net> 0006 SPDX-FileCopyrightText: 2000-2004 Thomas Baumgart <ipwizard@users.sourceforge.net> 0007 SPDX-FileCopyrightText: 2000-2004 Kevin Tambascio <ktambascio@users.sourceforge.net> 0008 SPDX-FileCopyrightText: 2000-2004 Ace Jones <ace.j@hotpop.com> 0009 SPDX-FileCopyrightText: 2017 Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com> 0010 SPDX-FileCopyrightText: 2021 Dawid Wróbel <me@dawidwrobel.com> 0011 SPDX-License-Identifier: GPL-2.0-or-later 0012 */ 0013 0014 #include "kreportsview_p.h" 0015 0016 #include <typeinfo> 0017 0018 // ---------------------------------------------------------------------------- 0019 // QT Includes 0020 0021 #include <QFileDialog> 0022 #include <QLocale> 0023 #include <QMenu> 0024 #include <QTreeWidget> 0025 #include <QUrlQuery> 0026 0027 // ---------------------------------------------------------------------------- 0028 // KDE Includes 0029 0030 #include <KMessageBox> 0031 #include <KRecentDirs> 0032 #include <KLocalizedString> 0033 0034 // ---------------------------------------------------------------------------- 0035 // Project Includes 0036 0037 #include "ui_reportcontrol.h" 0038 0039 #include "icons.h" 0040 #include "journalmodel.h" 0041 #include "kbalancechartdlg.h" 0042 #include "kmymoneysettings.h" 0043 #include "kreportchartview.h" 0044 #include "kreportconfigurationfilterdlg.h" 0045 #include "menuenums.h" 0046 #include "mymoneyenums.h" 0047 #include "mymoneyexception.h" 0048 #include "mymoneyfile.h" 0049 #include "mymoneyreport.h" 0050 #include "objectinfotable.h" 0051 #include "pivottable.h" 0052 #include "querytable.h" 0053 #include "reportcontrolimpl.h" 0054 #include "reporttable.h" 0055 #include "tocitem.h" 0056 #include "tocitemgroup.h" 0057 #include "tocitemreport.h" 0058 0059 using namespace reports; 0060 using namespace eMyMoney; 0061 using namespace Icons; 0062 0063 #define VIEW_LEDGER "ledger" 0064 #define VIEW_SCHEDULE "schedule" 0065 #define VIEW_WELCOME "welcome" 0066 #define VIEW_HOME "home" 0067 #define VIEW_REPORTS "reports" 0068 0069 /** 0070 * KReportsView Implementation 0071 */ 0072 0073 KReportsView::KReportsView(QWidget *parent) : 0074 KMyMoneyViewBase(*new KReportsViewPrivate(this), parent) 0075 { 0076 connect(pActions[eMenu::Action::ReportAccountTransactions], &QAction::triggered, this, &KReportsView::slotReportAccountTransactions); 0077 0078 connect(pActions[eMenu::Action::ReportNew], &QAction::triggered, this, &KReportsView::slotDuplicate); 0079 connect(pActions[eMenu::Action::ReportConfigure], &QAction::triggered, this, &KReportsView::slotConfigure); 0080 connect(pActions[eMenu::Action::ReportExport], &QAction::triggered, this, &KReportsView::slotExportView); 0081 connect(pActions[eMenu::Action::ReportDelete], &QAction::triggered, this, &KReportsView::slotDelete); 0082 connect(pActions[eMenu::Action::ReportClose], &QAction::triggered, this, &KReportsView::slotCloseCurrent); 0083 0084 pActions[eMenu::Action::ReportNew]->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Plus)); 0085 pActions[eMenu::Action::ReportConfigure]->setShortcut(QKeySequence(Qt::SHIFT | Qt::Key_P)); 0086 pActions[eMenu::Action::ReportDelete]->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Delete)); 0087 pActions[eMenu::Action::ReportClose]->setShortcut(QKeySequence(Qt::SHIFT | Qt::Key_W)); 0088 } 0089 0090 KReportsView::~KReportsView() 0091 { 0092 } 0093 0094 void KReportsView::executeAction(eMenu::Action action, const SelectedObjects& selections) 0095 { 0096 Q_D(KReportsView); 0097 switch (action) { 0098 case eMenu::Action::ReportOpen: 0099 slotOpenReport(selections.firstSelection(SelectedObjects::Report)); 0100 break; 0101 case eMenu::Action::Print: 0102 if (d->isActiveView()) { 0103 slotPrintView(); 0104 } 0105 break; 0106 case eMenu::Action::PrintPreview: 0107 if (d->isActiveView()) { 0108 slotPrintPreviewView(); 0109 } 0110 break; 0111 case eMenu::Action::ChartAccountBalance: { 0112 const auto account = MyMoneyFile::instance()->accountsModel()->itemById(selections.firstSelection(SelectedObjects::Account)); 0113 if (!account.id().isEmpty()) { 0114 QPointer<KBalanceChartDlg> dlg = new KBalanceChartDlg(account, this); 0115 dlg->exec(); 0116 delete dlg; 0117 } 0118 } break; 0119 case eMenu::Action::FileClose: 0120 slotCloseAll(); 0121 default: 0122 break; 0123 } 0124 } 0125 0126 void KReportsView::executeCustomAction(eView::Action action) 0127 { 0128 switch(action) { 0129 case eView::Action::Refresh: 0130 refresh(); 0131 break; 0132 0133 default: 0134 break; 0135 } 0136 } 0137 0138 void KReportsView::refresh() 0139 { 0140 Q_D(KReportsView); 0141 if (isVisible()) { 0142 d->loadView(); 0143 d->m_needsRefresh = false; 0144 } else { 0145 d->m_needsRefresh = true; 0146 } 0147 } 0148 0149 void KReportsView::showEvent(QShowEvent * event) 0150 { 0151 Q_D(KReportsView); 0152 if (d->m_needLoad) { 0153 d->init(); 0154 connect(d->ui.m_closeButton, &QToolButton::clicked, this, [&]() { 0155 Q_D(KReportsView); 0156 d->ui.m_filterContainer->hide(); 0157 d->ui.m_searchWidget->clear(); 0158 d->ui.m_reportTabWidget->setFocus(); 0159 }); 0160 connect(pActions[eMenu::Action::ShowFilterWidget], &QAction::triggered, this, [&]() { 0161 if (isVisible()) { 0162 Q_D(KReportsView); 0163 d->ui.m_filterContainer->show(); 0164 d->ui.m_searchWidget->setFocus(); 0165 } 0166 }); 0167 connect(d->ui.m_searchWidget, &QLineEdit::textChanged, this, [&](const QString& text) { 0168 Q_D(KReportsView); 0169 d->setFilter(text); 0170 }); 0171 } 0172 if (d->m_needsRefresh) { 0173 refresh(); 0174 d->setFilter(d->ui.m_searchWidget->text()); 0175 } 0176 0177 if (auto tab = dynamic_cast<KReportTab*>(d->ui.m_reportTabWidget->currentWidget())) 0178 Q_EMIT reportSelected(tab->report()); 0179 else 0180 Q_EMIT reportSelected(MyMoneyReport()); 0181 0182 // don't forget base class implementation 0183 QWidget::showEvent(event); 0184 } 0185 0186 bool KReportsView::eventFilter(QObject* watched, QEvent* event) 0187 { 0188 Q_D(KReportsView); 0189 0190 if (event->type() == QEvent::KeyPress) { 0191 if (watched == d->ui.m_searchWidget || watched == d->ui.m_tocTreeWidget) { 0192 const auto kev = static_cast<QKeyEvent*>(event); 0193 if (kev->modifiers() == Qt::NoModifier && kev->key() == Qt::Key_Escape) { 0194 d->ui.m_closeButton->animateClick(); 0195 return true; 0196 } 0197 } 0198 0199 } else if (event->type() == QEvent::ShortcutOverride) { 0200 const auto kev = static_cast<QKeyEvent*>(event); 0201 const auto keySeq = QKeySequence(kev->modifiers() | kev->key()); 0202 const auto buttons = findChildren<QToolButton*>(); 0203 for (const auto& button : qAsConst(buttons)) { 0204 const auto action = button->defaultAction(); 0205 if (action) { 0206 const auto actionSeq = action->shortcut(); 0207 if (keySeq == actionSeq) { 0208 action->trigger(); 0209 event->accept(); 0210 return true; 0211 } 0212 } 0213 } 0214 } 0215 0216 return QWidget::eventFilter(watched, event); 0217 } 0218 0219 void KReportsView::updateActions(const SelectedObjects& selections) 0220 { 0221 Q_D(KReportsView); 0222 bool enable = false; 0223 0224 if (!selections.selection(SelectedObjects::Account).isEmpty()) { 0225 const auto file = MyMoneyFile::instance(); 0226 const auto accId = selections.selection(SelectedObjects::Account).at(0); 0227 if (!file->isStandardAccount(accId)) { 0228 d->m_currentAccount = file->accountsModel()->itemById(accId); 0229 switch (d->m_currentAccount.accountType()) { 0230 case eMyMoney::Account::Type::Asset: 0231 case eMyMoney::Account::Type::Liability: 0232 case eMyMoney::Account::Type::Equity: 0233 case eMyMoney::Account::Type::Checkings: 0234 enable = true; 0235 break; 0236 default: 0237 break; 0238 } 0239 } 0240 } 0241 pActions[eMenu::Action::ReportAccountTransactions]->setEnabled(enable); 0242 0243 // only access the widgets if they are initialized 0244 if (!d->m_needLoad) { 0245 if (auto tab = dynamic_cast<KReportTab*>(d->ui.m_reportTabWidget->currentWidget())) { 0246 tab->enableAllReportActions(); 0247 } 0248 } 0249 } 0250 0251 void KReportsView::slotOpenUrl(const QUrl &url) 0252 { 0253 QString view = url.fileName(); 0254 if (view.isEmpty()) 0255 return; 0256 QString command = QUrlQuery(url).queryItemValue("command"); 0257 QString id = QUrlQuery(url).queryItemValue("id"); 0258 QString tid = QUrlQuery(url).queryItemValue("tid"); 0259 0260 if (view == VIEW_REPORTS) { 0261 0262 if (command.isEmpty()) { 0263 // slotRefreshView(); 0264 } else if (command == QLatin1String("print")) 0265 slotPrintView(); 0266 else if (command == QLatin1String("save")) 0267 slotExportView(); 0268 else if (command == QLatin1String("configure")) 0269 slotConfigure(); 0270 else if (command == QLatin1String("duplicate")) 0271 slotDuplicate(); 0272 else if (command == QLatin1String("close")) 0273 slotCloseCurrent(); 0274 else if (command == QLatin1String("delete")) 0275 slotDelete(); 0276 else 0277 qWarning() << i18n("Unknown command '%1' in KReportsView::slotOpenUrl()", qPrintable(command)); 0278 0279 } else if (view == VIEW_LEDGER) { 0280 const auto gotoAccount = pActions[eMenu::Action::GoToAccount]; 0281 gotoAccount->setData(id); 0282 0283 // convert transaction id to journalEntryId and make it the current selection 0284 SelectedObjects selection; 0285 const auto indexes = MyMoneyFile::instance()->journalModel()->indexesByTransactionId(tid); 0286 for (const auto& idx : indexes) { 0287 if (idx.data(eMyMoney::Model::JournalSplitAccountIdRole).toString() == id) { 0288 tid = idx.data(eMyMoney::Model::IdRole).toString(); 0289 break; 0290 } 0291 } 0292 selection.setSelection(SelectedObjects::JournalEntry, tid); 0293 Q_EMIT requestSelectionChange(selection); 0294 0295 gotoAccount->trigger(); 0296 } else { 0297 qWarning() << i18n("Unknown view '%1' in KReportsView::slotOpenUrl()", qPrintable(view)); 0298 } 0299 } 0300 0301 void KReportsView::slotPrintView() 0302 { 0303 Q_D(KReportsView); 0304 if (auto tab = dynamic_cast<KReportTab*>(d->ui.m_reportTabWidget->currentWidget())) 0305 tab->print(); 0306 } 0307 0308 void KReportsView::slotPrintPreviewView() 0309 { 0310 Q_D(KReportsView); 0311 if (auto tab = dynamic_cast<KReportTab*>(d->ui.m_reportTabWidget->currentWidget())) 0312 tab->printPreview(); 0313 } 0314 0315 void KReportsView::slotExportView() 0316 { 0317 Q_D(KReportsView); 0318 if (auto tab = dynamic_cast<KReportTab*>(d->ui.m_reportTabWidget->currentWidget())) { 0319 QPointer<QFileDialog> dialog = new QFileDialog(this, i18n("Export as"), KRecentDirs::dir(":kmymoney-export")); 0320 dialog->setMimeTypeFilters({QStringLiteral("text/csv"), QStringLiteral("text/html")}); 0321 dialog->setFileMode(QFileDialog::AnyFile); 0322 dialog->setAcceptMode(QFileDialog::AcceptSave); 0323 dialog->selectFile(tab->report().name()); 0324 0325 QUrl newURL; 0326 QString selectedMimeType; 0327 if (dialog->exec() == QDialog::Accepted) { 0328 newURL = dialog->selectedUrls().first(); 0329 selectedMimeType = dialog->selectedMimeTypeFilter(); 0330 } 0331 delete dialog; 0332 0333 if (!newURL.isEmpty()) { 0334 KRecentDirs::add(":kmymoney-export", newURL.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).path()); 0335 QString newName = newURL.toDisplayString(QUrl::PreferLocalFile); 0336 0337 try { 0338 tab->saveAs(newName, selectedMimeType); 0339 } catch (const MyMoneyException &e) { 0340 KMessageBox::error(this, i18n("Failed to save: %1", QString::fromLatin1(e.what()))); 0341 } 0342 } 0343 } 0344 } 0345 0346 void KReportsView::slotConfigure() 0347 { 0348 doConfigure(NoConfigureOption); 0349 } 0350 0351 void KReportsView::doConfigure(ConfigureOption configureOption) 0352 { 0353 Q_D(KReportsView); 0354 QString cm = "KReportsView::slotConfigure"; 0355 0356 auto tab = dynamic_cast<KReportTab*>(d->ui.m_reportTabWidget->currentWidget()); 0357 0358 if (!tab) // nothing to do 0359 return; 0360 int tabNr = d->ui.m_reportTabWidget->currentIndex(); 0361 0362 tab->updateDataRange(); // range will be needed during configuration, but cannot be obtained earlier 0363 0364 MyMoneyReport report = tab->report(); 0365 if (report.comment() == i18n("Default Report") || report.comment() == i18n("Generated Report")) { 0366 report.setComment(i18n("Custom Report")); 0367 report.setName(i18n("%1 (Customized)", report.name())); 0368 } 0369 0370 QPointer<KReportConfigurationFilterDlg> dlg = new KReportConfigurationFilterDlg(report); 0371 0372 if (dlg->exec()) { 0373 MyMoneyReport newreport = dlg->getConfig(); 0374 0375 // If this report has an ID, then MODIFY it, otherwise ADD it 0376 MyMoneyFileTransaction ft; 0377 try { 0378 if (! newreport.id().isEmpty()) { 0379 MyMoneyFile::instance()->modifyReport(newreport); 0380 ft.commit(); 0381 tab->modifyReport(newreport); 0382 0383 d->ui.m_reportTabWidget->setTabText(tabNr, newreport.name()); 0384 d->ui.m_reportTabWidget->setCurrentIndex(tabNr); 0385 } else { 0386 MyMoneyFile::instance()->addReport(newreport); 0387 ft.commit(); 0388 0389 QString reportGroupName = newreport.group(); 0390 0391 // find report group 0392 TocItemGroup* tocItemGroup = d->m_allTocItemGroups[reportGroupName]; 0393 if (!tocItemGroup) { 0394 QString error = i18n("Could not find reportgroup \"%1\" for report \"%2\".\nPlease report this error to the developer's list: kmymoney-devel@kde.org", reportGroupName, newreport.name()); 0395 0396 // write to messagehandler 0397 qWarning() << cm << error; 0398 0399 // also inform user 0400 KMessageBox::error(d->ui.m_reportTabWidget, error, i18n("Critical Error")); 0401 0402 // cleanup 0403 delete dlg; 0404 0405 return; 0406 } 0407 0408 // do not add TocItemReport to TocItemGroup here, 0409 // this is done in loadView 0410 0411 d->addReportTab(newreport, OpenImmediately); 0412 } 0413 } catch (const MyMoneyException &e) { 0414 KMessageBox::error(this, i18n("Failed to configure report: %1", QString::fromLatin1(e.what()))); 0415 } 0416 } else if (configureOption == LoadReportOnCancel) { 0417 tab->loadTab(); 0418 } 0419 delete dlg; 0420 } 0421 0422 void KReportsView::slotDuplicate() 0423 { 0424 Q_D(KReportsView); 0425 QString cm = "KReportsView::slotDuplicate"; 0426 0427 auto tab = dynamic_cast<KReportTab*>(d->ui.m_reportTabWidget->currentWidget()); 0428 0429 if (!tab) { 0430 // nothing to do 0431 return; 0432 } 0433 0434 MyMoneyReport dupe = tab->report(); 0435 dupe.setName(i18n("Copy of %1", dupe.name())); 0436 if (dupe.comment() == i18n("Default Report")) 0437 dupe.setComment(i18n("Custom Report")); 0438 dupe.clearId(); 0439 0440 QPointer<KReportConfigurationFilterDlg> dlg = new KReportConfigurationFilterDlg(dupe); 0441 if (dlg->exec()) { 0442 MyMoneyReport newReport = dlg->getConfig(); 0443 MyMoneyFileTransaction ft; 0444 try { 0445 MyMoneyFile::instance()->addReport(newReport); 0446 ft.commit(); 0447 0448 QString reportGroupName = newReport.group(); 0449 0450 // find report group 0451 TocItemGroup* tocItemGroup = d->m_allTocItemGroups[reportGroupName]; 0452 if (!tocItemGroup) { 0453 QString error = i18n("Could not find reportgroup \"%1\" for report \"%2\".\nPlease report this error to the developer's list: kmymoney-devel@kde.org", reportGroupName, newReport.name()); 0454 0455 // write to messagehandler 0456 qWarning() << cm << error; 0457 0458 // also inform user 0459 KMessageBox::error(d->ui.m_reportTabWidget, error, i18n("Critical Error")); 0460 0461 // cleanup 0462 delete dlg; 0463 0464 return; 0465 } 0466 0467 // do not add TocItemReport to TocItemGroup here, 0468 // this is done in loadView 0469 0470 d->addReportTab(newReport, OpenImmediately); 0471 } catch (const MyMoneyException &e) { 0472 QString error = i18n("Cannot add report, reason: \"%1\"", e.what()); 0473 0474 // write to messagehandler 0475 qWarning() << cm << error; 0476 0477 // also inform user 0478 KMessageBox::error(d->ui.m_reportTabWidget, error, i18n("Critical Error")); 0479 } 0480 } 0481 delete dlg; 0482 } 0483 0484 void KReportsView::slotDelete() 0485 { 0486 Q_D(KReportsView); 0487 auto tab = dynamic_cast<KReportTab*>(d->ui.m_reportTabWidget->currentWidget()); 0488 if (!tab) { 0489 // nothing to do 0490 return; 0491 } 0492 0493 MyMoneyReport report = tab->report(); 0494 if (! report.id().isEmpty()) { 0495 if (KMessageBox::Continue == d->deleteReportDialog(report.name())) { 0496 // close the tab and then remove the report so that it is not 0497 // generated again during the following loadView() call 0498 slotClose(d->ui.m_reportTabWidget->currentIndex()); 0499 0500 MyMoneyFileTransaction ft; 0501 MyMoneyFile::instance()->removeReport(report); 0502 ft.commit(); 0503 } 0504 } else { 0505 KMessageBox::information(this, 0506 QString("<qt>") + 0507 i18n("<b>%1</b> is a default report, so it cannot be deleted.", 0508 report.name()) + QString("</qt>"), i18n("Delete Report?")); 0509 } 0510 } 0511 0512 0513 void KReportsView::slotOpenReport(const QString& id) 0514 { 0515 Q_D(KReportsView); 0516 if (id.isEmpty()) { 0517 // nothing to do 0518 return; 0519 } 0520 0521 KReportTab* page = 0; 0522 0523 // Find the tab which contains the report 0524 int index = 1; 0525 while (index < d->ui.m_reportTabWidget->count()) { 0526 auto current = dynamic_cast<KReportTab*>(d->ui.m_reportTabWidget->widget(index)); 0527 0528 if (current && current->report().id() == id) { 0529 page = current; 0530 break; 0531 } 0532 0533 ++index; 0534 } 0535 0536 // Show the tab, or create a new one, as needed 0537 if (page) 0538 d->ui.m_reportTabWidget->setCurrentIndex(index); 0539 else 0540 d->addReportTab(MyMoneyFile::instance()->report(id), OpenImmediately); 0541 } 0542 0543 void KReportsView::slotOpenReport(const MyMoneyReport& report) 0544 { 0545 Q_D(KReportsView); 0546 if (d->m_needLoad) 0547 d->init(); 0548 KReportTab* page = 0; 0549 0550 // Find the tab which contains the report indicated by this list item 0551 int index = 1; 0552 while (index < d->ui.m_reportTabWidget->count()) { 0553 auto current = dynamic_cast<KReportTab*>(d->ui.m_reportTabWidget->widget(index)); 0554 0555 if (current && current->report().name() == report.name()) { 0556 page = current; 0557 break; 0558 } 0559 0560 ++index; 0561 } 0562 0563 // Show the tab, or create a new one, as needed 0564 if (page) 0565 d->ui.m_reportTabWidget->setCurrentIndex(index); 0566 else 0567 d->addReportTab(report, OpenImmediately); 0568 0569 if (!isVisible()) 0570 Q_EMIT switchViewRequested(View::Reports); 0571 } 0572 0573 void KReportsView::slotItemDoubleClicked(QTreeWidgetItem* item, int column) 0574 { 0575 doItemDoubleClicked(item, column, OpenImmediately); 0576 } 0577 0578 void KReportsView::doItemDoubleClicked(QTreeWidgetItem* item, int column, OpenOption openOption) 0579 { 0580 Q_UNUSED(column) 0581 0582 Q_D(KReportsView); 0583 auto tocItem = dynamic_cast<TocItem*>(item); 0584 if (tocItem && !tocItem->isReport()) { 0585 // toggle the expanded-state for reportgroup-items 0586 item->setExpanded(item->isExpanded() ? false : true); 0587 0588 // nothing else to do for reportgroup-items 0589 return; 0590 } 0591 0592 TocItemReport* reportTocItem = dynamic_cast<TocItemReport*>(tocItem); 0593 0594 MyMoneyReport& report = reportTocItem->getReport(); 0595 0596 KReportTab* page = 0; 0597 0598 // Find the tab which contains the report indicated by this list item 0599 int index = 1; 0600 while (index < d->ui.m_reportTabWidget->count()) { 0601 auto current = dynamic_cast<KReportTab*>(d->ui.m_reportTabWidget->widget(index)); 0602 if (current) { 0603 // If this report has an ID, we'll use the ID to match 0604 if (! report.id().isEmpty()) { 0605 if (current->report().id() == report.id()) { 0606 page = current; 0607 break; 0608 } 0609 } 0610 // Otherwise, use the name to match. THIS ASSUMES that no 2 default reports 0611 // have the same name...but that would be pretty a boneheaded thing to do. 0612 else { 0613 if (current->report().name() == report.name()) { 0614 page = current; 0615 break; 0616 } 0617 } 0618 } 0619 0620 ++index; 0621 } 0622 0623 // Show the tab, or create a new one, as needed 0624 if (page) 0625 d->ui.m_reportTabWidget->setCurrentIndex(index); 0626 else 0627 d->addReportTab(report, openOption); 0628 } 0629 0630 void KReportsView::slotToggleChart() 0631 { 0632 Q_D(KReportsView); 0633 if (auto tab = dynamic_cast<KReportTab*>(d->ui.m_reportTabWidget->currentWidget())) 0634 tab->toggleChart(); 0635 } 0636 0637 bool KReportsView::hasClosableView() const 0638 { 0639 Q_D(const KReportsView); 0640 return d->ui.m_reportTabWidget->count() > 1; 0641 } 0642 0643 void KReportsView::closeCurrentView() 0644 { 0645 Q_D(KReportsView); 0646 const auto idx = d->ui.m_reportTabWidget->currentIndex(); 0647 if (idx > 0) { 0648 slotClose(idx); 0649 } 0650 } 0651 0652 void KReportsView::slotCloseCurrent() 0653 { 0654 Q_D(KReportsView); 0655 slotClose(d->ui.m_reportTabWidget->currentIndex()); 0656 } 0657 0658 void KReportsView::slotClose(int index) 0659 { 0660 Q_D(KReportsView); 0661 if (auto tab = dynamic_cast<KReportTab*>(d->ui.m_reportTabWidget->widget(index))) { 0662 d->ui.m_reportTabWidget->removeTab(index); 0663 tab->setReadyToDelete(true); 0664 } 0665 } 0666 0667 void KReportsView::slotCloseAll() 0668 { 0669 Q_D(KReportsView); 0670 if(!d->m_needLoad) { 0671 while (true) { 0672 if (auto tab = dynamic_cast<KReportTab*>(d->ui.m_reportTabWidget->widget(1))) { 0673 d->ui.m_reportTabWidget->removeTab(1); 0674 tab->setReadyToDelete(true); 0675 } else 0676 break; 0677 } 0678 } 0679 } 0680 0681 0682 void KReportsView::slotListContextMenu(const QPoint & p) 0683 { 0684 Q_D(KReportsView); 0685 const auto items = d->ui.m_tocTreeWidget->selectedItems(); 0686 0687 if (items.isEmpty()) { 0688 return; 0689 } 0690 0691 QList<TocItem*> tocItems; 0692 for (const auto& item : items) { 0693 auto tocItem = dynamic_cast<TocItem*>(item); 0694 if (tocItem && tocItem->isReport()) { 0695 tocItems.append(tocItem); 0696 } 0697 } 0698 0699 if (tocItems.isEmpty()) { 0700 return; 0701 } 0702 0703 auto contextmenu = new QMenu(this); 0704 0705 contextmenu->addSection(i18nc("@title:menu Report context menu", "Report options")); 0706 contextmenu->addAction(i18nc("To open a new report", "&Open"), 0707 this, SLOT(slotOpenFromList())); 0708 0709 contextmenu->addAction(i18nc("To print a report", "&Print"), 0710 this, SLOT(slotPrintFromList())); 0711 0712 if (tocItems.count() == 1) { 0713 contextmenu->addAction(i18nc("Configure a report", "&Configure"), 0714 this, SLOT(slotConfigureFromList())); 0715 0716 contextmenu->addAction(i18n("&New report"), 0717 this, SLOT(slotNewFromList())); 0718 0719 // Only add this option if it's a custom report. Default reports cannot be deleted 0720 0721 auto reportTocItem = dynamic_cast<TocItemReport*>(tocItems.at(0)); 0722 0723 if (reportTocItem) { 0724 MyMoneyReport& report = reportTocItem->getReport(); 0725 if (! report.id().isEmpty()) { 0726 contextmenu->addAction(i18n("&Delete"), 0727 this, SLOT(slotDeleteFromList())); 0728 } 0729 } 0730 } 0731 0732 contextmenu->popup(d->ui.m_tocTreeWidget->viewport()->mapToGlobal(p)); 0733 } 0734 0735 void KReportsView::slotOpenFromList() 0736 { 0737 Q_D(KReportsView); 0738 0739 const auto items = d->ui.m_tocTreeWidget->selectedItems(); 0740 0741 if (items.isEmpty()) { 0742 return; 0743 } 0744 0745 for (const auto& item : items) { 0746 auto tocItem = dynamic_cast<TocItem*>(item); 0747 if (tocItem && tocItem->isReport()) { 0748 slotItemDoubleClicked(tocItem, 0); 0749 } 0750 } 0751 } 0752 0753 void KReportsView::slotPrintFromList() 0754 { 0755 Q_D(KReportsView); 0756 0757 const auto items = d->ui.m_tocTreeWidget->selectedItems(); 0758 0759 if (items.isEmpty()) { 0760 return; 0761 } 0762 0763 for (const auto& item : items) { 0764 auto tocItem = dynamic_cast<TocItem*>(item); 0765 if (tocItem && tocItem->isReport()) { 0766 slotItemDoubleClicked(tocItem, 0); 0767 slotPrintView(); 0768 } 0769 } 0770 } 0771 0772 void KReportsView::slotConfigureFromList() 0773 { 0774 Q_D(KReportsView); 0775 if (auto tocItem = dynamic_cast<TocItem*>(d->ui.m_tocTreeWidget->currentItem())) { 0776 doItemDoubleClicked(tocItem, 0, OpenAfterConfiguration); 0777 doConfigure(LoadReportOnCancel); 0778 } 0779 } 0780 0781 void KReportsView::slotNewFromList() 0782 { 0783 Q_D(KReportsView); 0784 if (auto tocItem = dynamic_cast<TocItem*>(d->ui.m_tocTreeWidget->currentItem())) { 0785 slotItemDoubleClicked(tocItem, 0); 0786 slotDuplicate(); 0787 } 0788 } 0789 0790 void KReportsView::slotDeleteFromList() 0791 { 0792 Q_D(KReportsView); 0793 if (auto tocItem = dynamic_cast<TocItem*>(d->ui.m_tocTreeWidget->currentItem())) { 0794 if (auto reportTocItem = dynamic_cast<TocItemReport*>(tocItem)) { 0795 MyMoneyReport& report = reportTocItem->getReport(); 0796 0797 // If this report does not have an ID, it's a default report and cannot be deleted 0798 if (! report.id().isEmpty() && 0799 KMessageBox::Continue == d->deleteReportDialog(report.name())) { 0800 // check if report's tab is open; start from 1 because 0 is toc tab 0801 for (int i = 1; i < d->ui.m_reportTabWidget->count(); ++i) { 0802 auto tab = dynamic_cast<KReportTab*>(d->ui.m_reportTabWidget->widget(i)); 0803 if (tab && tab->report().id() == report.id()) { 0804 slotClose(i); // if open, close it, so no crash when switching to it 0805 break; 0806 } 0807 } 0808 MyMoneyFileTransaction ft; 0809 MyMoneyFile::instance()->removeReport(report); 0810 ft.commit(); 0811 } 0812 } 0813 } 0814 } 0815 0816 void KReportsView::slotReportAccountTransactions() 0817 { 0818 Q_D(KReportsView); 0819 // Generate a transaction report that contains transactions for only the 0820 // currently selected account. 0821 if (!d->m_currentAccount.id().isEmpty()) { 0822 MyMoneyReport report( 0823 eMyMoney::Report::RowType::Account, 0824 eMyMoney::Report::QueryColumn::Number | eMyMoney::Report::QueryColumn::Payee | eMyMoney::Report::QueryColumn::Category, 0825 eMyMoney::TransactionFilter::Date::YearToDate, 0826 eMyMoney::Report::DetailLevel::All, 0827 i18n("%1 YTD Account Transactions", d->m_currentAccount.name()), 0828 i18n("Generated Report") 0829 ); 0830 report.setGroup(i18n("Transactions")); 0831 report.addAccount(d->m_currentAccount.id()); 0832 slotOpenReport(report); 0833 } 0834 } 0835 0836 // Make sure, that these definitions are only used within this file 0837 // this does not seem to be necessary, but when building RPMs the 0838 // build option 'final' is used and all CPP files are concatenated. 0839 // So it could well be, that in another CPP file these definitions 0840 // are also used. 0841 #undef VIEW_LEDGER 0842 #undef VIEW_SCHEDULE 0843 #undef VIEW_WELCOME 0844 #undef VIEW_HOME 0845 #undef VIEW_REPORTS