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