/*
    SPDX-FileCopyrightText: 2000-2002 Michael Edwardes <mte@users.sourceforge.net>
    SPDX-FileCopyrightText: 2000-2002 Javier Campos Morales <javi_c@users.sourceforge.net>
    SPDX-FileCopyrightText: 2000-2002 Felix Rodriguez <frodriguez@users.sourceforge.net>
    SPDX-FileCopyrightText: 2000-2002 John C <thetacoturtle@users.sourceforge.net>
    SPDX-FileCopyrightText: 2000-2002 Thomas Baumgart <ipwizard@users.sourceforge.net>
    SPDX-FileCopyrightText: 2000-2002 Kevin Tambascio <ktambascio@users.sourceforge.net>
    SPDX-FileCopyrightText: 2017 Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com>
    SPDX-License-Identifier: GPL-2.0-or-later
*/

#ifndef KSCHEDULEDVIEW_P_H
#define KSCHEDULEDVIEW_P_H

#include "kscheduledview.h"

// ----------------------------------------------------------------------------
// QT Includes

#include <QList>
#include <QTimer>
#include <QPushButton>
#include <QMenu>
#include <QIcon>
#include <QScopedPointer>
#include <QDebug>

// ----------------------------------------------------------------------------
// KDE Includes

#include <KLocalizedString>
#include <KConfig>
#include <KMessageBox>
#include <KSharedConfig>
#include <KTreeWidgetSearchLine>
#include <KTreeWidgetSearchLineWidget>

// ----------------------------------------------------------------------------
// Project Includes

#include "ui_kscheduledview.h"
#include "kmymoneyviewbase_p.h"
#include "kenterscheduledlg.h"
#include "kbalancewarning.h"
#include "transactioneditor.h"
#include "kconfirmmanualenterdlg.h"
#include "kmymoneymvccombo.h"
#include "kmymoneyutils.h"
#include "kmymoneysettings.h"
#include "mymoneyexception.h"
#include "kscheduletreeitem.h"
#include "ktreewidgetfilterlinewidget.h"
#include "icons/icons.h"
#include "mymoneyutils.h"
#include "mymoneyaccount.h"
#include "mymoneymoney.h"
#include "mymoneysecurity.h"
#include "mymoneyschedule.h"
#include "mymoneyfile.h"
#include "mymoneypayee.h"
#include "mymoneysplit.h"
#include "mymoneytransaction.h"
#include "mymoneyenums.h"
#include "menuenums.h"
#include "dialogenums.h"

using namespace Icons;

class KScheduledViewPrivate : public KMyMoneyViewBasePrivate
{
    Q_DECLARE_PUBLIC(KScheduledView)

public:
    explicit KScheduledViewPrivate(KScheduledView *qq) :
        KMyMoneyViewBasePrivate(),
        q_ptr(qq),
        ui(new Ui::KScheduledView),
        m_kaccPopup(nullptr),
        m_openBills(true),
        m_openDeposits(true),
        m_openTransfers(true),
        m_openLoans(true),
        m_needLoad(true),
        m_searchWidget(nullptr),
        m_balanceWarning(nullptr)
    {
    }

    ~KScheduledViewPrivate()
    {
        if(!m_needLoad)
            writeConfig();
        delete ui;
    }

    void init()
    {
        Q_Q(KScheduledView);
        m_needLoad = false;
        ui->setupUi(q);

        // create the searchline widget
        // and insert it into the existing layout
        m_searchWidget = new KTreeWidgetFilterLineWidget(q, ui->m_scheduleTree);
        ui->vboxLayout->insertWidget(1, m_searchWidget);

        //enable custom context menu
        ui->m_scheduleTree->setContextMenuPolicy(Qt::CustomContextMenu);
        ui->m_scheduleTree->setSelectionMode(QAbstractItemView::SingleSelection);

        readConfig();

        q->connect(ui->m_qbuttonNew, &QAbstractButton::clicked, pActions[eMenu::Action::NewSchedule], &QAction::trigger);

        // attach popup to 'Filter...' button
        m_kaccPopup = new QMenu(q);
        ui->m_accountsCombo->setMenu(m_kaccPopup);
        q->connect(m_kaccPopup, &QMenu::triggered, q, &KScheduledView::slotAccountActivated);

        KGuiItem::assign(ui->m_qbuttonNew, KMyMoneyUtils::scheduleNewGuiItem());
        KGuiItem::assign(ui->m_accountsCombo, KMyMoneyUtils::accountsFilterGuiItem());

        q->connect(ui->m_scheduleTree, &QWidget::customContextMenuRequested, q, &KScheduledView::customContextMenuRequested);
        q->connect(ui->m_scheduleTree, &QTreeWidget::itemSelectionChanged,
                   q, &KScheduledView::slotSetSelectedItem);

        q->connect(ui->m_scheduleTree, &QTreeWidget::itemDoubleClicked,
                   q, &KScheduledView::slotListItemExecuted);
        q->connect(ui->m_scheduleTree, &QTreeWidget::itemExpanded,
                   q, &KScheduledView::slotListViewExpanded);
        q->connect(ui->m_scheduleTree, &QTreeWidget::itemCollapsed,
                   q, &KScheduledView::slotListViewCollapsed);

        q->connect(MyMoneyFile::instance(), &MyMoneyFile::dataChanged, q, &KScheduledView::refresh);
    }

    static bool accountNameLessThan(const MyMoneyAccount& acc1, const MyMoneyAccount& acc2)
    {
        return acc1.name().toLower() < acc2.name().toLower();
    }

    void refreshSchedule(bool full, const QString& schedId)
    {
        Q_Q(KScheduledView);
        ui->m_scheduleTree->header()->setFont(KMyMoneySettings::listHeaderFontEx());

        ui->m_scheduleTree->clear();

        try {
            if (full) {
                try {
                    m_kaccPopup->clear();

                    MyMoneyFile* file = MyMoneyFile::instance();

                    // extract a list of all accounts under the asset group
                    // and sort them by name
                    QList<MyMoneyAccount> list;
                    QStringList accountList = file->asset().accountList();
                    accountList.append(file->liability().accountList());
                    file->accountList(list, accountList, true);
                    qStableSort(list.begin(), list.end(), accountNameLessThan);

                    QList<MyMoneyAccount>::ConstIterator it_a;
                    for (it_a = list.constBegin(); it_a != list.constEnd(); ++it_a) {
                        if (!(*it_a).isClosed()) {
                            QAction* act;
                            act = m_kaccPopup->addAction((*it_a).name());
                            act->setCheckable(true);
                            act->setChecked(true);
                        }
                    }

                } catch (const MyMoneyException &e) {
                    KMessageBox::detailedError(q, i18n("Unable to load accounts: "), e.what());
                }
            }

            MyMoneyFile *file = MyMoneyFile::instance();
            QList<MyMoneySchedule> scheduledItems = file->scheduleList();

            if (scheduledItems.count() == 0)
                return;

            //disable sorting for performance
            ui->m_scheduleTree->setSortingEnabled(false);

            KScheduleTreeItem *itemBills = new KScheduleTreeItem(ui->m_scheduleTree);
            itemBills->setIcon(0, Icons::get(Icon::Expense));
            itemBills->setText(0, i18n("Bills"));
            itemBills->setData(0, KScheduleTreeItem::OrderRole, QVariant("0"));
            itemBills->setFirstColumnSpanned(true);
            itemBills->setFlags(Qt::ItemIsEnabled);
            QFont bold = itemBills->font(0);
            bold.setBold(true);
            itemBills->setFont(0, bold);
            KScheduleTreeItem *itemDeposits = new KScheduleTreeItem(ui->m_scheduleTree);
            itemDeposits->setIcon(0, Icons::get(Icon::Income));
            itemDeposits->setText(0, i18n("Deposits"));
            itemDeposits->setData(0, KScheduleTreeItem::OrderRole, QVariant("1"));
            itemDeposits->setFirstColumnSpanned(true);
            itemDeposits->setFlags(Qt::ItemIsEnabled);
            itemDeposits->setFont(0, bold);
            KScheduleTreeItem *itemLoans = new KScheduleTreeItem(ui->m_scheduleTree);
            itemLoans->setIcon(0, Icons::get(Icon::Loan));
            itemLoans->setText(0, i18n("Loans"));
            itemLoans->setData(0, KScheduleTreeItem::OrderRole, QVariant("2"));
            itemLoans->setFirstColumnSpanned(true);
            itemLoans->setFlags(Qt::ItemIsEnabled);
            itemLoans->setFont(0, bold);
            KScheduleTreeItem *itemTransfers = new KScheduleTreeItem(ui->m_scheduleTree);
            itemTransfers->setIcon(0, Icons::get(Icon::Transaction));
            itemTransfers->setText(0, i18n("Transfers"));
            itemTransfers->setData(0, KScheduleTreeItem::OrderRole, QVariant("3"));
            itemTransfers->setFirstColumnSpanned(true);
            itemTransfers->setFlags(Qt::ItemIsEnabled);
            itemTransfers->setFont(0, bold);

            QList<MyMoneySchedule>::Iterator it;

            QTreeWidgetItem *openItem = 0;

            for (it = scheduledItems.begin(); it != scheduledItems.end(); ++it) {
                MyMoneySchedule schedData = (*it);
                QTreeWidgetItem* item = 0;

                bool bContinue = true;
                QStringList::iterator accIt;
                for (accIt = m_filterAccounts.begin(); accIt != m_filterAccounts.end(); ++accIt) {
                    if (*accIt == schedData.account().id()) {
                        bContinue = false; // Filter it out
                        break;
                    }
                }

                if (!bContinue)
                    continue;

                QTreeWidgetItem* parent = 0;
                switch (schedData.type()) {
                case eMyMoney::Schedule::Type::Any:
                // Should we display an error ?
                // We just sort it as bill and fall through here

                case eMyMoney::Schedule::Type::Bill:
                    parent = itemBills;
                    break;

                case eMyMoney::Schedule::Type::Deposit:
                    parent = itemDeposits;
                    break;

                case eMyMoney::Schedule::Type::Transfer:
                    parent = itemTransfers;
                    break;

                case eMyMoney::Schedule::Type::LoanPayment:
                    parent = itemLoans;
                    break;

                }
                if (parent) {
                    if (!KMyMoneySettings::hideFinishedSchedules() || !schedData.isFinished()) {
                        item = addScheduleItem(parent, schedData);
                        if (schedData.id() == schedId)
                            openItem = item;
                    }
                }
            }

            if (openItem) {
                ui->m_scheduleTree->setCurrentItem(openItem);
            }
            // using a timeout is the only way, I got the 'ensureTransactionVisible'
            // working when coming from hidden form to visible form. I assume, this
            // has something to do with the delayed update of the display somehow.
            q->resize(q->width(), q->height() - 1);
            QTimer::singleShot(10, q, SLOT(slotTimerDone()));
            ui->m_scheduleTree->update();

            // force repaint in case the filter is set
            m_searchWidget->searchLine()->updateSearch(QString());

            if (m_openBills)
                itemBills->setExpanded(true);

            if (m_openDeposits)
                itemDeposits->setExpanded(true);

            if (m_openTransfers)
                itemTransfers->setExpanded(true);

            if (m_openLoans)
                itemLoans->setExpanded(true);

        } catch (const MyMoneyException &e) {
            KMessageBox::error(q, e.what());
        }

        for (int i = 0; i < ui->m_scheduleTree->columnCount(); ++i) {
            ui->m_scheduleTree->resizeColumnToContents(i);
        }

        //reenable sorting after loading items
        ui->m_scheduleTree->setSortingEnabled(true);
    }

    void readConfig()
    {
        KSharedConfigPtr config = KSharedConfig::openConfig();
        KConfigGroup grp = config->group("Last Use Settings");
        m_openBills = grp.readEntry("KScheduleView_openBills", true);
        m_openDeposits = grp.readEntry("KScheduleView_openDeposits", true);
        m_openTransfers = grp.readEntry("KScheduleView_openTransfers", true);
        m_openLoans = grp.readEntry("KScheduleView_openLoans", true);
        QByteArray columns;
        columns = grp.readEntry("KScheduleView_treeState", columns);
        ui->m_scheduleTree->header()->restoreState(columns);
        ui->m_scheduleTree->header()->setFont(KMyMoneySettings::listHeaderFontEx());
    }

    void writeConfig()
    {
        KSharedConfigPtr config = KSharedConfig::openConfig();
        KConfigGroup grp = config->group("Last Use Settings");
        grp.writeEntry("KScheduleView_openBills", m_openBills);
        grp.writeEntry("KScheduleView_openDeposits", m_openDeposits);
        grp.writeEntry("KScheduleView_openTransfers", m_openTransfers);
        grp.writeEntry("KScheduleView_openLoans", m_openLoans);
        QByteArray columns = ui->m_scheduleTree->header()->saveState();
        grp.writeEntry("KScheduleView_treeState", columns);

        config->sync();
    }

    QTreeWidgetItem* addScheduleItem(QTreeWidgetItem* parent, MyMoneySchedule& schedule)
    {
        KScheduleTreeItem* item = new KScheduleTreeItem(parent);
        item->setData(0, Qt::UserRole, QVariant::fromValue(schedule));
        item->setData(0, KScheduleTreeItem::OrderRole, schedule.name());
        if (!schedule.isFinished()) {
            if (schedule.isOverdue()) {
                item->setIcon(0, Icons::get(Icon::UpcomingEvents));
                QBrush brush = item->foreground(0);
                brush.setColor(Qt::red);
                for (int i = 0; i < ui->m_scheduleTree->columnCount(); ++i) {
                    item->setForeground(i, brush);
                }
            } else {
                item->setIcon(0, Icons::get(Icon::CalendarDay));
            }
        } else {
            item->setIcon(0, Icons::get(Icon::DialogClose));
            QBrush brush = item->foreground(0);
            brush.setColor(Qt::darkGreen);
            for (int i = 0; i < ui->m_scheduleTree->columnCount(); ++i) {
                item->setForeground(i, brush);
            }
        }

        try {
            MyMoneyTransaction transaction = schedule.transaction();
            MyMoneySplit s1 = (transaction.splits().size() < 1) ? MyMoneySplit() : transaction.splits()[0];
            MyMoneySplit s2 = (transaction.splits().size() < 2) ? MyMoneySplit() : transaction.splits()[1];
            MyMoneySplit split;
            MyMoneyAccount acc;

            switch (schedule.type()) {
            case eMyMoney::Schedule::Type::Deposit:
                if (s1.value().isNegative())
                    split = s2;
                else
                    split = s1;
                break;

            case eMyMoney::Schedule::Type::LoanPayment:
            {
                auto found = false;
                foreach (const auto it_split, transaction.splits()) {
                    acc = MyMoneyFile::instance()->account(it_split.accountId());
                    if (acc.accountGroup() == eMyMoney::Account::Type::Asset
                            || acc.accountGroup() == eMyMoney::Account::Type::Liability) {
                        if (acc.accountType() != eMyMoney::Account::Type::Loan
                                && acc.accountType() != eMyMoney::Account::Type::AssetLoan) {
                            split = it_split;
                            found = true;
                            break;
                        }
                    }
                }
                if (!found) {
                    qWarning("Split for payment account not found in %s:%d.", __FILE__, __LINE__);
                }
                break;
            }
            default:
                if (!s1.value().isPositive())
                    split = s1;
                else
                    split = s2;
                break;
            }
            acc = MyMoneyFile::instance()->account(split.accountId());

            item->setText(0, schedule.name());
            MyMoneySecurity currency = MyMoneyFile::instance()->currency(acc.currencyId());

            QString accName =  acc.name();
            if (!accName.isEmpty()) {
                item->setText(1, accName);
            } else {
                item->setText(1, "---");
            }
            item->setData(1, KScheduleTreeItem::OrderRole, QVariant(accName));

            QString payeeName;
            if (!s1.payeeId().isEmpty()) {
                payeeName = MyMoneyFile::instance()->payee(s1.payeeId()).name();
                item->setText(2, payeeName);
            } else {
                item->setText(2, "---");
            }
            item->setData(2, KScheduleTreeItem::OrderRole, QVariant(payeeName));

            MyMoneyMoney amount = split.shares().abs();
            item->setData(3, Qt::UserRole, QVariant::fromValue(amount));
            if (!accName.isEmpty()) {
                item->setText(3, QString("%1  ").arg(MyMoneyUtils::formatMoney(amount, acc, currency)));
            } else {
                //there are some cases where the schedule does not have an account
                //in those cases the account will not have a fraction
                //use base currency instead
                item->setText(3, QString("%1  ").arg(MyMoneyUtils::formatMoney(amount, MyMoneyFile::instance()->baseCurrency())));
            }
            item->setTextAlignment(3, Qt::AlignRight | Qt::AlignVCenter);
            item->setData(3, KScheduleTreeItem::OrderRole, QVariant::fromValue(amount));

            // Do the real next payment like ms-money etc
            QDate nextDueDate;
            if (schedule.isFinished()) {
                item->setText(4, i18nc("Finished schedule", "Finished"));
            } else {
                nextDueDate = schedule.adjustedNextDueDate();
                item->setText(4, QLocale().toString(schedule.adjustedNextDueDate(), QLocale::ShortFormat));
            }
            item->setData(4, KScheduleTreeItem::OrderRole, QVariant(nextDueDate));
            item->setText(5, i18nc("Frequency of schedule", schedule.occurrenceToString().toLatin1()));
            item->setText(6, KMyMoneyUtils::paymentMethodToString(schedule.paymentType()));
        } catch (const MyMoneyException &e) {
            item->setText(0, "Error:");
            item->setText(1, e.what());
        }
        return item;
    }

    /**
      * This method allows to enter the next scheduled transaction of
      * the given schedule @a s. In case @a extendedKeys is @a true,
      * the given schedule can also be skipped or ignored.
      * If @a autoEnter is @a true and the schedule does not contain
      * an estimated value, the schedule is entered as is without further
      * interaction with the user. In all other cases, the user will
      * be presented a dialog and allowed to adjust the values for this
      * instance of the schedule.
      *
      * The transaction will be created and entered into the ledger
      * and the schedule updated.
      */
    eDialogs::ScheduleResultCode enterSchedule(MyMoneySchedule& schedule, bool autoEnter = false, bool extendedKeys = false)
    {
        Q_Q(KScheduledView);
        auto rc = eDialogs::ScheduleResultCode::Cancel;
        if (!schedule.id().isEmpty()) {
            try {
                schedule = MyMoneyFile::instance()->schedule(schedule.id());
            } catch (const MyMoneyException &e) {
                KMessageBox::detailedSorry(q, i18n("Unable to enter scheduled transaction '%1'", schedule.name()), e.what());
                return rc;
            }

            QWidget* parent = QApplication::activeWindow();
            QPointer<KEnterScheduleDlg> dlg = new KEnterScheduleDlg(parent, schedule);

            try {
                QDate origDueDate = schedule.nextDueDate();

                dlg->showExtendedKeys(extendedKeys);

                QPointer<TransactionEditor> transactionEditor = dlg->startEdit();
                if (transactionEditor) {
                    KMyMoneyMVCCombo::setSubstringSearchForChildren(dlg, !KMyMoneySettings::stringMatchFromStart());
                    MyMoneyTransaction torig, taccepted;
                    transactionEditor->createTransaction(torig, dlg->transaction(),
                                                         schedule.transaction().splits().isEmpty() ? MyMoneySplit() : schedule.transaction().splits().front(), true);
                    // force actions to be available no matter what (will be updated according to the state during
                    // slotTransactionsEnter or slotTransactionsCancel)

                    KConfirmManualEnterDlg::Action action = KConfirmManualEnterDlg::ModifyOnce;
                    if (!autoEnter || !schedule.isFixed()) {
                        for (; dlg != 0;) {
                            rc = eDialogs::ScheduleResultCode::Cancel;
                            if (dlg->exec() == QDialog::Accepted && dlg != 0) {
                                pActions[eMenu::Action::CancelTransaction]->setEnabled(true);
                                pActions[eMenu::Action::EnterTransaction]->setEnabled(true);
                                rc = dlg->resultCode();
                                if (rc == eDialogs::ScheduleResultCode::Enter) {
                                    transactionEditor->createTransaction(taccepted, torig, torig.splits().isEmpty() ? MyMoneySplit() : torig.splits().front(), true);
                                    // make sure to suppress comparison of some data: postDate
                                    torig.setPostDate(taccepted.postDate());
                                    if (torig != taccepted) {
                                        QPointer<KConfirmManualEnterDlg> cdlg =
                                            new KConfirmManualEnterDlg(schedule, q);
                                        cdlg->loadTransactions(torig, taccepted);
                                        if (cdlg->exec() == QDialog::Accepted) {
                                            action = cdlg->action();
                                            delete cdlg;
                                            break;
                                        }
                                        delete cdlg;
                                        // the user has chosen 'cancel' during confirmation,
                                        // we go back to the editor
                                        continue;
                                    }
                                } else if (rc == eDialogs::ScheduleResultCode::Skip) {
                                    slotTransactionsCancel(transactionEditor, schedule);
                                    skipSchedule(schedule);
                                } else {
                                    slotTransactionsCancel(transactionEditor, schedule);
                                }
                            } else {
                                pActions[eMenu::Action::CancelTransaction]->setEnabled(true);
                                pActions[eMenu::Action::EnterTransaction]->setEnabled(true);
                                if (autoEnter) {
                                    if (KMessageBox::warningYesNo(q, i18n("Are you sure you wish to stop this scheduled transaction from being entered into the register?\n\nKMyMoney will prompt you again next time it starts unless you manually enter it later.")) == KMessageBox::No) {
                                        // the user has chosen 'No' for the above question,
                                        // we go back to the editor
                                        continue;
                                    }
                                }
                                slotTransactionsCancel(transactionEditor, schedule);
                            }
                            break;
                        }
                    }

                    // if we still have the editor around here, the user did not cancel
                    if ((transactionEditor != 0) && (dlg != 0)) {
                        MyMoneyFileTransaction ft;
                        try {
                            MyMoneyTransaction t;
                            // add the new transaction
                            switch (action) {
                            case KConfirmManualEnterDlg::UseOriginal:
                                // setup widgets with original transaction data
                                transactionEditor->setTransaction(dlg->transaction(), dlg->transaction().splits().isEmpty() ? MyMoneySplit() : dlg->transaction().splits().front());
                                // and create a transaction based on that data
                                taccepted = MyMoneyTransaction();
                                transactionEditor->createTransaction(taccepted, dlg->transaction(),
                                                                     dlg->transaction().splits().isEmpty() ? MyMoneySplit() : dlg->transaction().splits().front(), true);
                                break;

                            case KConfirmManualEnterDlg::ModifyAlways:
                                torig = taccepted;
                                torig.setPostDate(origDueDate);
                                schedule.setTransaction(torig);
                                break;

                            case KConfirmManualEnterDlg::ModifyOnce:
                                break;
                            }

                            QString newId;
                            q->connect(transactionEditor, SIGNAL(balanceWarning(QWidget*,MyMoneyAccount,QString)), m_balanceWarning.data(), SLOT(slotShowMessage(QWidget*,MyMoneyAccount,QString)));
                            if (transactionEditor->enterTransactions(newId, false)) {
                                if (!newId.isEmpty()) {
                                    t = MyMoneyFile::instance()->transaction(newId);
                                    schedule.setLastPayment(t.postDate());
                                }
                                // in case the next due date is invalid, the schedule is finished
                                // we mark it as such by setting the next due date to one day past the end
                                QDate nextDueDate = schedule.nextPayment(origDueDate);
                                if (!nextDueDate.isValid()) {
                                    schedule.setNextDueDate(schedule.endDate().addDays(1));
                                } else {
                                    schedule.setNextDueDate(nextDueDate);
                                }
                                MyMoneyFile::instance()->modifySchedule(schedule);
                                rc = eDialogs::ScheduleResultCode::Enter;

                                // delete the editor before we emit the dataChanged() signal from the
                                // engine. Calling this twice in a row does not hurt.
                                delete transactionEditor;
                                ft.commit();
                            }
                        } catch (const MyMoneyException &e) {
                            KMessageBox::detailedSorry(q, i18n("Unable to enter scheduled transaction '%1'", schedule.name()), e.what());
                        }
                        delete transactionEditor;
                    }
                }
            } catch (const MyMoneyException &e) {
                KMessageBox::detailedSorry(q, i18n("Unable to enter scheduled transaction '%1'", schedule.name()), e.what());
            }
            delete dlg;
        }
        return rc;
    }

    void slotTransactionsCancel(TransactionEditor* editor, const MyMoneySchedule& schedule)
    {
        Q_Q(KScheduledView);
        // since we jump here via code, we have to make sure to react only
        // if the action is enabled
        if (pActions[eMenu::Action::CancelTransaction]->isEnabled()) {
            // make sure, we block the enter function
            pActions[eMenu::Action::EnterTransaction]->setEnabled(false);
            // qDebug("KMyMoneyApp::slotTransactionsCancel");
            delete editor;
            emit q->selectByObject(schedule, eView::Intent::None);
        }
    }

    /**
      * This method allows to skip the next scheduled transaction of
      * the given schedule @a s.
      *
      */
    void skipSchedule(MyMoneySchedule& schedule)
    {
        const auto parentWidget = QApplication::activeWindow();

        if (!schedule.id().isEmpty()) {
            try {
                schedule = MyMoneyFile::instance()->schedule(schedule.id());
                if (!schedule.isFinished()) {
                    if (schedule.occurrence() != eMyMoney::Schedule::Occurrence::Once) {
                        QDate next = schedule.nextDueDate();
                        if (!schedule.isFinished() && (KMessageBox::questionYesNo(parentWidget, i18n("<qt>Do you really want to skip the <b>%1</b> transaction scheduled for <b>%2</b>?</qt>", schedule.name(), QLocale().toString(next, QLocale::ShortFormat)))) == KMessageBox::Yes) {
                            MyMoneyFileTransaction ft;
                            schedule.setLastPayment(next);
                            schedule.setNextDueDate(schedule.nextPayment(next));
                            MyMoneyFile::instance()->modifySchedule(schedule);
                            ft.commit();
                        }
                    }
                }
            } catch (const MyMoneyException &e) {
                KMessageBox::detailedSorry(parentWidget, i18n("<qt>Unable to skip scheduled transaction <b>%1</b>.</qt>", schedule.name()), e.what());
            }
        }
    }

    KScheduledView      *q_ptr;
    Ui::KScheduledView  *ui;
    /// The selected schedule id in the list view.
    QMenu *m_kaccPopup;
    QStringList m_filterAccounts;
    bool m_openBills;
    bool m_openDeposits;
    bool m_openTransfers;
    bool m_openLoans;

    /**
      * This member holds the load state of page
      */
    bool m_needLoad;

    /**
     * Search widget for the list
     */
    KTreeWidgetSearchLineWidget*  m_searchWidget;
    MyMoneySchedule m_currentSchedule;

    QScopedPointer<KBalanceWarning> m_balanceWarning;
};

#endif
