File indexing completed on 2024-05-12 16:43:49

0001 /*
0002     SPDX-FileCopyrightText: 2000-2002 Michael Edwardes <mte@users.sourceforge.net>
0003     SPDX-FileCopyrightText: 2000-2002 Javier Campos Morales <javi_c@users.sourceforge.net>
0004     SPDX-FileCopyrightText: 2000-2002 Felix Rodriguez <frodriguez@users.sourceforge.net>
0005     SPDX-FileCopyrightText: 2000-2002 John C <thetacoturtle@users.sourceforge.net>
0006     SPDX-FileCopyrightText: 2000-2002 Thomas Baumgart <ipwizard@users.sourceforge.net>
0007     SPDX-FileCopyrightText: 2000-2002 Kevin Tambascio <ktambascio@users.sourceforge.net>
0008     SPDX-FileCopyrightText: 2000-2002 Andreas Nicolai <Andreas.Nicolai@gmx.net>
0009     SPDX-FileCopyrightText: 2017 Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com>
0010     SPDX-License-Identifier: GPL-2.0-or-later
0011 */
0012 
0013 #include "kpayeesview_p.h"
0014 
0015 // ----------------------------------------------------------------------------
0016 // QT Includes
0017 
0018 #include <QMap>
0019 #include <QList>
0020 #include <QTimer>
0021 #include <QMenu>
0022 #include <QDesktopServices>
0023 #include <QIcon>
0024 
0025 // ----------------------------------------------------------------------------
0026 // KDE Includes
0027 
0028 #include <KLocalizedString>
0029 #include <KMessageBox>
0030 #include <KGuiItem>
0031 #include <KHelpClient>
0032 #include <KSharedConfig>
0033 #include <KListWidgetSearchLine>
0034 
0035 // ----------------------------------------------------------------------------
0036 // Project Includes
0037 
0038 #include <config-kmymoney.h>
0039 #include "ui_kpayeesview.h"
0040 #include "kmymoneyviewbase_p.h"
0041 #include "kpayeeidentifierview.h"
0042 #include "mymoneypayee.h"
0043 #include "mymoneyexception.h"
0044 #include "mymoneyfile.h"
0045 #include "mymoneyaccount.h"
0046 #include "mymoneymoney.h"
0047 #include "mymoneytransactionfilter.h"
0048 #include "kmymoneysettings.h"
0049 #include "models.h"
0050 #include "accountsmodel.h"
0051 #include "mymoneysecurity.h"
0052 #include "mymoneycontact.h"
0053 #include "mymoneyprice.h"
0054 #include "mymoneysplit.h"
0055 #include "mymoneytransaction.h"
0056 #include "icons/icons.h"
0057 #include "transaction.h"
0058 #include "widgetenums.h"
0059 #include "mymoneyenums.h"
0060 #include "modelenums.h"
0061 #include "menuenums.h"
0062 
0063 using namespace Icons;
0064 
0065 // *** KPayeesView Implementation ***
0066 
0067 KPayeesView::KPayeesView(QWidget *parent) :
0068     KMyMoneyViewBase(*new KPayeesViewPrivate(this), parent)
0069 {
0070     connect(pActions[eMenu::Action::NewPayee],    &QAction::triggered, this, &KPayeesView::slotNewPayee);
0071     connect(pActions[eMenu::Action::RenamePayee], &QAction::triggered, this, &KPayeesView::slotRenamePayee);
0072     connect(pActions[eMenu::Action::DeletePayee], &QAction::triggered, this, &KPayeesView::slotDeletePayee);
0073     connect(pActions[eMenu::Action::MergePayee],  &QAction::triggered, this, &KPayeesView::slotMergePayee);
0074 }
0075 
0076 KPayeesView::~KPayeesView()
0077 {
0078 }
0079 
0080 void KPayeesView::slotChooseDefaultAccount()
0081 {
0082     Q_D(KPayeesView);
0083     MyMoneyFile* file = MyMoneyFile::instance();
0084     QMap<QString, int> account_count;
0085 
0086     KMyMoneyRegister::RegisterItem* item = d->ui->m_register->firstItem();
0087     while (item) {
0088         //only walk through selectable items. eg. transactions and not group markers
0089         if (item->isSelectable()) {
0090             auto t = dynamic_cast<KMyMoneyRegister::Transaction*>(item);
0091             if (!t)
0092                 return;
0093             MyMoneySplit s = t->transaction().splitByPayee(d->m_payee.id());
0094             const MyMoneyAccount& acc = file->account(s.accountId());
0095 
0096             if (s.action() != MyMoneySplit::actionName(eMyMoney::Split::Action::Amortization)
0097                     && acc.accountType() != eMyMoney::Account::Type::AssetLoan
0098                     && !file->isTransfer(t->transaction())
0099                     && t->transaction().splitCount() == 2) {
0100                 MyMoneySplit s0 = t->transaction().splitByAccount(s.accountId(), false);
0101                 if (account_count.contains(s0.accountId())) {
0102                     account_count[s0.accountId()]++;
0103                 } else {
0104                     account_count[s0.accountId()] = 1;
0105                 }
0106             }
0107         }
0108         item = item->nextItem();
0109     }
0110 
0111     QMap<QString, int>::Iterator most_frequent, iter;
0112     most_frequent = account_count.begin();
0113     for (iter = account_count.begin(); iter != account_count.end(); ++iter) {
0114         if (iter.value() > most_frequent.value()) {
0115             most_frequent = iter;
0116         }
0117     }
0118 
0119     if (most_frequent != account_count.end()) {
0120         d->ui->checkEnableDefaultCategory->setChecked(true);
0121         d->ui->comboDefaultCategory->setSelected(most_frequent.key());
0122         d->setDirty(true);
0123     }
0124 }
0125 
0126 void KPayeesView::slotClosePayeeIdentifierSource()
0127 {
0128     Q_D(KPayeesView);
0129     if (!d->m_needLoad)
0130         d->ui->payeeIdentifiers->closeSource();
0131 }
0132 
0133 void KPayeesView::slotSelectByVariant(const QVariantList& variant, eView::Intent intent)
0134 {
0135     switch (intent) {
0136     case eView::Intent::ShowPayee:
0137         if (variant.count() == 3)
0138             slotSelectPayeeAndTransaction(variant.at(0).toString(), variant.at(1).toString(), variant.at(2).toString());
0139         break;
0140     default:
0141         break;
0142     }
0143 }
0144 
0145 
0146 void KPayeesView::slotStartRename(QListWidgetItem* item)
0147 {
0148     Q_D(KPayeesView);
0149     d->m_allowEditing = true;
0150     d->ui->m_payeesList->editItem(item);
0151 }
0152 
0153 // This variant is only called when a single payee is selected and renamed.
0154 void KPayeesView::slotRenameSinglePayee(QListWidgetItem* p)
0155 {
0156     Q_D(KPayeesView);
0157     //if there is no current item selected, exit
0158     if (d->m_allowEditing == false || !d->ui->m_payeesList->currentItem() || p != d->ui->m_payeesList->currentItem())
0159         return;
0160 
0161     //qDebug() << "[KPayeesView::slotRenamePayee]";
0162     // create a copy of the new name without appended whitespaces
0163     QString new_name = p->text();
0164     if (d->m_payee.name() != new_name) {
0165         MyMoneyFileTransaction ft;
0166         try {
0167             // check if we already have a payee with the new name
0168             try {
0169                 // this function call will throw an exception, if the payee
0170                 // hasn't been found.
0171                 MyMoneyFile::instance()->payeeByName(new_name);
0172                 // the name already exists, ask the user whether he's sure to keep the name
0173                 if (KMessageBox::questionYesNo(this,
0174                                                i18n("A payee with the name '%1' already exists. It is not advisable to have "
0175                                                     "multiple payees with the same identification name. Are you sure you would like "
0176                                                     "to rename the payee?", new_name)) != KMessageBox::Yes) {
0177                     p->setText(d->m_payee.name());
0178                     return;
0179                 }
0180             } catch (const MyMoneyException &) {
0181                 // all ok, the name is unique
0182             }
0183 
0184             d->m_payee.setName(new_name);
0185             d->m_newName = new_name;
0186             MyMoneyFile::instance()->modifyPayee(d->m_payee);
0187 
0188             // the above call to modifyPayee will reload the view so
0189             // all references and pointers to the view have to be
0190             // re-established.
0191 
0192             // make sure, that the record is visible even if it moved
0193             // out of sight due to the rename operation
0194             d->ensurePayeeVisible(d->m_payee.id());
0195 
0196             ft.commit();
0197 
0198         } catch (const MyMoneyException &e) {
0199             KMessageBox::detailedSorry(this, i18n("Unable to modify payee"), QString::fromLatin1(e.what()));
0200         }
0201     } else {
0202         p->setText(new_name);
0203     }
0204 }
0205 
0206 void KPayeesView::slotSelectPayee(QListWidgetItem* cur, QListWidgetItem* prev)
0207 {
0208     Q_D(KPayeesView);
0209     Q_UNUSED(cur);
0210     Q_UNUSED(prev);
0211 
0212     d->m_allowEditing = false;
0213 }
0214 
0215 void KPayeesView::slotSelectPayee()
0216 {
0217     Q_D(KPayeesView);
0218     // check if the content of a currently selected payee was modified
0219     // and ask to store the data
0220     if (d->isDirty()) {
0221         if (KMessageBox::questionYesNo(this,
0222                                        i18n("<qt>Do you want to save the changes for <b>%1</b>?</qt>", d->m_newName),
0223                                        i18n("Save changes")) == KMessageBox::Yes) {
0224             d->m_inSelection = true;
0225             slotUpdatePayee();
0226             d->m_inSelection = false;
0227         }
0228     }
0229 
0230     // make sure we always clear the selected list when listing again
0231     d->m_selectedPayeesList.clear();
0232 
0233     // loop over all payees and count the number of payees, also
0234     // obtain last selected payee
0235     d->selectedPayees(d->m_selectedPayeesList);
0236     updatePayeeActions(d->m_selectedPayeesList);
0237 
0238     emit selectObjects(d->m_selectedPayeesList);
0239 
0240     if (d->m_selectedPayeesList.isEmpty()) {
0241         d->ui->m_tabWidget->setEnabled(false); // disable tab widget
0242         d->ui->m_balanceLabel->hide();
0243         d->ui->m_deleteButton->setEnabled(false); //disable delete, rename and merge buttons
0244         d->ui->m_renameButton->setEnabled(false);
0245         d->ui->m_mergeButton->setEnabled(false);
0246         d->clearItemData();
0247         d->m_payee = MyMoneyPayee();
0248         d->ui->m_syncAddressbook->setEnabled(false);
0249         return; // make sure we don't access an undefined payee
0250     }
0251 
0252     d->ui->m_deleteButton->setEnabled(true); //re-enable delete button
0253 
0254     d->ui->m_syncAddressbook->setEnabled(true);
0255 
0256     // if we have multiple payees selected, clear and disable the payee information
0257     if (d->m_selectedPayeesList.count() > 1) {
0258         d->ui->m_tabWidget->setEnabled(false); // disable tab widget
0259         d->ui->m_renameButton->setEnabled(false); // disable also the rename button
0260         d->ui->m_mergeButton->setEnabled(true);
0261         d->ui->m_balanceLabel->hide();
0262         d->clearItemData();
0263     } else {
0264         d->ui->m_mergeButton->setEnabled(false);
0265         d->ui->m_renameButton->setEnabled(true);
0266     }
0267 
0268     // otherwise we have just one selected, enable payee information widget
0269     d->ui->m_tabWidget->setEnabled(true);
0270     d->ui->m_balanceLabel->show();
0271 
0272     // as of now we are updating only the last selected payee, and until
0273     // selection mode of the QListView has been changed to Extended, this
0274     // will also be the only selection and behave exactly as before - Andreas
0275     try {
0276         d->m_payee = d->m_selectedPayeesList[0];
0277 
0278         d->m_newName = d->m_payee.name();
0279 
0280         d->ui->addressEdit->setEnabled(true);
0281         d->ui->addressEdit->setText(d->m_payee.address());
0282         d->ui->payeecityEdit->setEnabled(true);
0283         d->ui->payeecityEdit->setText(d->m_payee.city());
0284         d->ui->payeestateEdit->setEnabled(true);
0285         d->ui->payeestateEdit->setText(d->m_payee.state());
0286         d->ui->postcodeEdit->setEnabled(true);
0287         d->ui->postcodeEdit->setText(d->m_payee.postcode());
0288         d->ui->telephoneEdit->setEnabled(true);
0289         d->ui->telephoneEdit->setText(d->m_payee.telephone());
0290         d->ui->emailEdit->setEnabled(true);
0291         d->ui->emailEdit->setText(d->m_payee.email());
0292         d->ui->notesEdit->setText(d->m_payee.notes());
0293 
0294         QStringList keys;
0295         bool ignorecase = false;
0296         auto type = d->m_payee.matchData(ignorecase, keys);
0297 
0298         d->ui->matchTypeCombo->setCurrentIndex(d->ui->matchTypeCombo->findData(static_cast<int>(type)));
0299         d->ui->matchKeyEditList->clear();
0300         d->ui->matchKeyEditList->insertStringList(keys);
0301         d->ui->checkMatchIgnoreCase->setChecked(ignorecase);
0302 
0303         d->ui->checkEnableDefaultCategory->setChecked(!d->m_payee.defaultAccountId().isEmpty());
0304         d->ui->comboDefaultCategory->setCurrentIndex(-1);
0305         d->ui->comboDefaultCategory->setSelected(d->m_payee.defaultAccountId());
0306 
0307         d->ui->payeeIdentifiers->setSource(d->m_payee);
0308 
0309         slotPayeeDataChanged();
0310 
0311         d->showTransactions();
0312 
0313     } catch (const MyMoneyException &e) {
0314         qDebug("exception during display of payee: %s", e.what());
0315         d->ui->m_register->clear();
0316         d->m_selectedPayeesList.clear();
0317         d->m_payee = MyMoneyPayee();
0318     }
0319     d->m_allowEditing = true;
0320 }
0321 
0322 void KPayeesView::slotKeyListChanged()
0323 {
0324     Q_D(KPayeesView);
0325     bool rc = false;
0326     bool ignorecase = false;
0327     QStringList keys;
0328 
0329     d->m_payee.matchData(ignorecase, keys);
0330     if (static_cast<eMyMoney::Payee::MatchType>(d->ui->matchTypeCombo->currentData().toUInt()) == eMyMoney::Payee::MatchType::Key) {
0331         rc |= (keys != d->ui->matchKeyEditList->items());
0332     }
0333     d->setDirty(rc);
0334 }
0335 
0336 void KPayeesView::slotPayeeDataChanged()
0337 {
0338     Q_D(KPayeesView);
0339     bool rc = false;
0340 
0341     if (d->ui->m_tabWidget->isEnabled()) {
0342         rc |= ((d->m_payee.email().isEmpty() != d->ui->emailEdit->text().isEmpty())
0343                || (!d->ui->emailEdit->text().isEmpty() && d->m_payee.email() != d->ui->emailEdit->text()));
0344         rc |= ((d->m_payee.address().isEmpty() != d->ui->addressEdit->toPlainText().isEmpty())
0345                || (!d->ui->addressEdit->toPlainText().isEmpty() && d->m_payee.address() != d->ui->addressEdit->toPlainText()));
0346         rc |= ((d->m_payee.city().isEmpty() != d->ui->payeecityEdit->text().isEmpty())
0347                || (!d->ui->payeecityEdit->text().isEmpty() && d->m_payee.city() != d->ui->payeecityEdit->text()));
0348         rc |= ((d->m_payee.state().isEmpty() != d->ui->payeestateEdit->text().isEmpty())
0349                || (!d->ui->payeestateEdit->text().isEmpty() && d->m_payee.state() != d->ui->payeestateEdit->text()));
0350         rc |= ((d->m_payee.postcode().isEmpty() != d->ui->postcodeEdit->text().isEmpty())
0351                || (!d->ui->postcodeEdit->text().isEmpty() && d->m_payee.postcode() != d->ui->postcodeEdit->text()));
0352         rc |= ((d->m_payee.telephone().isEmpty() != d->ui->telephoneEdit->text().isEmpty())
0353                || (!d->ui->telephoneEdit->text().isEmpty() && d->m_payee.telephone() != d->ui->telephoneEdit->text()));
0354         rc |= ((d->m_payee.name().isEmpty() != d->m_newName.isEmpty())
0355                || (!d->m_newName.isEmpty() && d->m_payee.name() != d->m_newName));
0356         rc |= ((d->m_payee.notes().isEmpty() != d->ui->notesEdit->toPlainText().isEmpty())
0357                || (!d->ui->notesEdit->toPlainText().isEmpty() && d->m_payee.notes() != d->ui->notesEdit->toPlainText()));
0358 
0359         bool ignorecase = false;
0360         QStringList keys;
0361 
0362         const auto selectedMatchType = static_cast<eMyMoney::Payee::MatchType>(d->ui->matchTypeCombo->currentData().toUInt());
0363         const auto storedMatchType = d->m_payee.matchData(ignorecase, keys);
0364         rc |= (storedMatchType != selectedMatchType);
0365 
0366         d->ui->checkMatchIgnoreCase->setEnabled(false);
0367         d->ui->matchKeyEditList->setEnabled(false);
0368 
0369         if (selectedMatchType != eMyMoney::Payee::MatchType::Disabled) {
0370             d->ui->checkMatchIgnoreCase->setEnabled(true);
0371             // if we turn matching on, we default to 'ignore case'
0372             // TODO maybe make the default a user option
0373             if (storedMatchType == eMyMoney::Payee::MatchType::Disabled && (selectedMatchType != eMyMoney::Payee::MatchType::Disabled))
0374                 d->ui->checkMatchIgnoreCase->setChecked(true);
0375             rc |= (ignorecase != d->ui->checkMatchIgnoreCase->isChecked());
0376             if (selectedMatchType == eMyMoney::Payee::MatchType::Key) {
0377                 d->ui->matchKeyEditList->setEnabled(true);
0378                 rc |= (keys != d->ui->matchKeyEditList->items());
0379             }
0380         }
0381 
0382         rc |= (d->ui->checkEnableDefaultCategory->isChecked() != !d->m_payee.defaultAccountId().isEmpty());
0383         if (d->ui->checkEnableDefaultCategory->isChecked()) {
0384             d->ui->comboDefaultCategory->setEnabled(true);
0385             d->ui->labelDefaultCategory->setEnabled(true);
0386             // this is only going to understand the first in the list of selected accounts
0387             if (d->ui->comboDefaultCategory->getSelected().isEmpty()) {
0388                 rc |= !d->m_payee.defaultAccountId().isEmpty();
0389             } else {
0390                 QString temp = d->ui->comboDefaultCategory->getSelected();
0391                 rc |= (temp.isEmpty() != d->m_payee.defaultAccountId().isEmpty())
0392                       || (!d->m_payee.defaultAccountId().isEmpty() && temp != d->m_payee.defaultAccountId());
0393             }
0394         } else {
0395             d->ui->comboDefaultCategory->setEnabled(false);
0396             d->ui->labelDefaultCategory->setEnabled(false);
0397         }
0398 
0399         rc |= (d->m_payee.payeeIdentifiers() != d->ui->payeeIdentifiers->identifiers());
0400     }
0401     d->setDirty(rc);
0402 }
0403 
0404 void KPayeesView::slotUpdatePayee()
0405 {
0406     Q_D(KPayeesView);
0407     if (d->isDirty()) {
0408         MyMoneyFileTransaction ft;
0409         d->setDirty(false);
0410         try {
0411             d->m_payee.setName(d->m_newName);
0412             d->m_payee.setAddress(d->ui->addressEdit->toPlainText());
0413             d->m_payee.setCity(d->ui->payeecityEdit->text());
0414             d->m_payee.setState(d->ui->payeestateEdit->text());
0415             d->m_payee.setPostcode(d->ui->postcodeEdit->text());
0416             d->m_payee.setTelephone(d->ui->telephoneEdit->text());
0417             d->m_payee.setEmail(d->ui->emailEdit->text());
0418             d->m_payee.setNotes(d->ui->notesEdit->toPlainText());
0419             d->m_payee.setMatchData(static_cast<eMyMoney::Payee::MatchType>(d->ui->matchTypeCombo->currentData().toUInt()), d->ui->checkMatchIgnoreCase->isChecked(), d->ui->matchKeyEditList->items());
0420             d->m_payee.setDefaultAccountId();
0421             d->m_payee.resetPayeeIdentifiers(d->ui->payeeIdentifiers->identifiers());
0422 
0423             if (d->ui->checkEnableDefaultCategory->isChecked()) {
0424                 QString temp;
0425                 if (!d->ui->comboDefaultCategory->getSelected().isEmpty()) {
0426                     temp = d->ui->comboDefaultCategory->getSelected();
0427                     d->m_payee.setDefaultAccountId(temp);
0428                 }
0429             }
0430 
0431             MyMoneyFile::instance()->modifyPayee(d->m_payee);
0432             ft.commit();
0433 
0434         } catch (const MyMoneyException &e) {
0435             KMessageBox::detailedSorry(this, i18n("Unable to modify payee"), QString::fromLatin1(e.what()));
0436         }
0437     }
0438 }
0439 
0440 void KPayeesView::slotSyncAddressBook()
0441 {
0442     Q_D(KPayeesView);
0443     if (d->m_payeeRows.isEmpty()) {                            // empty list means no syncing is pending...
0444         foreach (auto item, d->ui->m_payeesList->selectedItems()) {
0445             d->m_payeeRows.append(d->ui->m_payeesList->row(item));        // ...so initialize one
0446         }
0447         d->ui->m_payeesList->clearSelection();                       // otherwise slotSelectPayee will be run after every payee update
0448 //    d->ui->m_syncAddressbook->setEnabled(false);                 // disallow concurrent syncs
0449     }
0450 
0451     if (d->m_payeeRows.count() <= d->m_payeeRow) {
0452         if (auto item = dynamic_cast<KPayeeListItem*>(d->ui->m_payeesList->currentItem())) { // update ui if something is selected
0453             d->m_payee = item->payee();
0454             d->ui->addressEdit->setText(d->m_payee.address());
0455             d->ui->payeecityEdit->setText(d->m_payee.city());
0456             d->ui->payeestateEdit->setText(d->m_payee.state());
0457             d->ui->postcodeEdit->setText(d->m_payee.postcode());
0458             d->ui->telephoneEdit->setText(d->m_payee.telephone());
0459         }
0460         d->m_payeeRows.clear();  // that means end of sync
0461         d->m_payeeRow = 0;
0462         return;
0463     }
0464 
0465     if (auto item = dynamic_cast<KPayeeListItem*>(d->ui->m_payeesList->item(d->m_payeeRows.at(d->m_payeeRow))))
0466         d->m_payee = item->payee();
0467     ++d->m_payeeRow;
0468 
0469     d->m_contact->fetchContact(d->m_payee.email()); // search for payee's data in addressbook and receive it in slotContactFetched
0470 }
0471 
0472 void KPayeesView::slotContactFetched(const ContactData &identity)
0473 {
0474     Q_D(KPayeesView);
0475     if (!identity.email.isEmpty()) {  // empty e-mail means no identity fetched
0476         QString txt;
0477         if (!identity.street.isEmpty())
0478             txt.append(identity.street + '\n');
0479         if (!identity.locality.isEmpty()) {
0480             txt.append(identity.locality);
0481             if (!identity.postalCode.isEmpty())
0482                 txt.append(' ' + identity.postalCode + '\n');
0483             else
0484                 txt.append('\n');
0485         }
0486         if (!identity.country.isEmpty())
0487             txt.append(identity.country + '\n');
0488 
0489         if (!txt.isEmpty() && d->m_payee.address().compare(txt) != 0)
0490             d->m_payee.setAddress(txt);
0491 
0492         if (!identity.city.isEmpty() && d->m_payee.city().compare(identity.city) != 0)
0493             d->m_payee.setCity(identity.city);
0494 
0495         if (!identity.state.isEmpty() && d->m_payee.state().compare(identity.state) != 0)
0496             d->m_payee.setState(identity.state);
0497 
0498         if (!identity.postalCode.isEmpty() && d->m_payee.postcode().compare(identity.postalCode) != 0)
0499             d->m_payee.setPostcode(identity.postalCode);
0500 
0501         if (!identity.phoneNumber.isEmpty() && d->m_payee.telephone().compare(identity.phoneNumber) != 0)
0502             d->m_payee.setTelephone(identity.phoneNumber);
0503 
0504         MyMoneyFileTransaction ft;
0505         try {
0506             MyMoneyFile::instance()->modifyPayee(d->m_payee);
0507             ft.commit();
0508         } catch (const MyMoneyException &e) {
0509             KMessageBox::detailedSorry(this, i18n("Unable to modify payee"), QString::fromLatin1(e.what()));
0510         }
0511     }
0512 
0513     slotSyncAddressBook();  // process next payee
0514 }
0515 
0516 void KPayeesView::slotSendMail()
0517 {
0518     Q_D(KPayeesView);
0519     QRegularExpression re(".+@.+");
0520     if (re.match(d->m_payee.email()).hasMatch())
0521         QDesktopServices::openUrl(QUrl(QStringLiteral("mailto:?to=") + d->m_payee.email(), QUrl::TolerantMode));
0522 }
0523 
0524 void KPayeesView::executeCustomAction(eView::Action action)
0525 {
0526     Q_D(KPayeesView);
0527     switch(action) {
0528     case eView::Action::Refresh:
0529         refresh();
0530         break;
0531 
0532     case eView::Action::SetDefaultFocus:
0533         QTimer::singleShot(0, d->m_searchWidget, SLOT(setFocus()));
0534         break;
0535 
0536     case eView::Action::ClosePayeeIdentifierSource:
0537         slotClosePayeeIdentifierSource();
0538         break;
0539 
0540     default:
0541         break;
0542     }
0543 }
0544 
0545 void KPayeesView::refresh()
0546 {
0547     Q_D(KPayeesView);
0548     if (isVisible()) {
0549         if (d->m_inSelection) {
0550             QTimer::singleShot(0, this, SLOT(refresh()));
0551         } else {
0552             d->loadPayees();
0553             d->m_needsRefresh = false;
0554         }
0555     } else {
0556         d->m_needsRefresh = true;
0557     }
0558 }
0559 
0560 void KPayeesView::showEvent(QShowEvent* event)
0561 {
0562     if (MyMoneyFile::instance()->storageAttached()) {
0563         Q_D(KPayeesView);
0564         if (d->m_needLoad)
0565             d->init();
0566 
0567         emit customActionRequested(View::Payees, eView::Action::AboutToShow);
0568 
0569         if (d->m_needsRefresh)
0570             refresh();
0571 
0572         QList<MyMoneyPayee> list;
0573         d->selectedPayees(list);
0574         emit selectObjects(list);
0575     }
0576 
0577     // don't forget base class implementation
0578     QWidget::showEvent(event);
0579 }
0580 
0581 void KPayeesView::updatePayeeActions(const QList<MyMoneyPayee> &payees)
0582 {
0583     pActions[eMenu::Action::NewPayee]->setEnabled(true);
0584     const auto payeesCount = payees.count();
0585     auto b = payeesCount == 1 ? true : false;
0586     pActions[eMenu::Action::RenamePayee]->setEnabled(b);
0587     b = payeesCount > 1 ? true : false;
0588     pActions[eMenu::Action::MergePayee]->setEnabled(b);
0589     b = payeesCount == 0 ? false : true;
0590     pActions[eMenu::Action::DeletePayee]->setEnabled(b);
0591 }
0592 
0593 void KPayeesView::slotSelectTransaction()
0594 {
0595     Q_D(KPayeesView);
0596     auto list = d->ui->m_register->selectedItems();
0597     if (!list.isEmpty()) {
0598         const auto t = dynamic_cast<KMyMoneyRegister::Transaction*>(list[0]);
0599         if (t)
0600             emit selectByVariant(QVariantList {QVariant(t->split().accountId()), QVariant(t->transaction().id()) }, eView::Intent::ShowTransaction);
0601     }
0602 }
0603 
0604 void KPayeesView::slotSelectPayeeAndTransaction(const QString& payeeId, const QString& accountId, const QString& transactionId)
0605 {
0606     Q_D(KPayeesView);
0607     if (!isVisible())
0608         return;
0609 
0610     try {
0611         // clear filter
0612         d->m_searchWidget->clear();
0613         d->m_searchWidget->updateSearch();
0614 
0615         // deselect all other selected items
0616         QList<QListWidgetItem *> selectedItems = d->ui->m_payeesList->selectedItems();
0617         QList<QListWidgetItem *>::const_iterator payeesIt = selectedItems.constBegin();
0618         while (payeesIt != selectedItems.constEnd()) {
0619             if (auto item = dynamic_cast<KPayeeListItem*>(*payeesIt))
0620                 item->setSelected(false);
0621             ++payeesIt;
0622         }
0623 
0624         // find the payee in the list
0625         QListWidgetItem* it;
0626         for (int i = 0; i < d->ui->m_payeesList->count(); ++i) {
0627             it = d->ui->m_payeesList->item(i);
0628             auto item = dynamic_cast<KPayeeListItem *>(it);
0629             if (item && item->payee().id() == payeeId) {
0630                 d->ui->m_payeesList->scrollToItem(it, QAbstractItemView::PositionAtCenter);
0631 
0632                 d->ui->m_payeesList->setCurrentItem(it);     // active item and deselect all others
0633                 d->ui->m_payeesList->setCurrentRow(i, QItemSelectionModel::ClearAndSelect); // and select it
0634 
0635                 //make sure the payee selection is updated and transactions are updated accordingly
0636                 slotSelectPayee();
0637 
0638                 KMyMoneyRegister::RegisterItem *registerItem = 0;
0639                 for (i = 0; i < d->ui->m_register->rowCount(); ++i) {
0640                     registerItem = d->ui->m_register->itemAtRow(i);
0641                     if (auto t = dynamic_cast<KMyMoneyRegister::Transaction*>(registerItem)) {
0642                         if (t->transaction().id() == transactionId && t->transaction().accountReferenced(accountId)) {
0643                             d->ui->m_register->selectItem(registerItem);
0644                             d->ui->m_register->ensureItemVisible(registerItem);
0645                             break;
0646                         }
0647                     }
0648                 }
0649                 // quit out of outer for() loop
0650                 break;
0651             }
0652         }
0653     } catch (const MyMoneyException &e) {
0654         qWarning("Unexpected exception in KPayeesView::slotSelectPayeeAndTransaction %s", e.what());
0655     }
0656 }
0657 
0658 void KPayeesView::slotShowPayeesMenu(const QPoint& /*p*/)
0659 {
0660     Q_D(KPayeesView);
0661     if (dynamic_cast<KPayeeListItem*>(d->ui->m_payeesList->currentItem())) {
0662         slotSelectPayee();
0663         pMenus[eMenu::Menu::Payee]->exec(QCursor::pos());
0664     }
0665 }
0666 
0667 void KPayeesView::slotHelp()
0668 {
0669     KHelpClient::invokeHelp("details.payees");
0670 }
0671 
0672 void KPayeesView::slotChangeFilter(int index)
0673 {
0674     Q_D(KPayeesView);
0675     //update the filter type then reload the payees list
0676     d->m_payeeFilterType = index;
0677     d->loadPayees();
0678 }
0679 
0680 void KPayeesView::slotNewPayee()
0681 {
0682     QString id;
0683     KMyMoneyUtils::newPayee(i18n("New Payee"), id);
0684     slotSelectPayeeAndTransaction(id);
0685 }
0686 
0687 void KPayeesView::slotRenamePayee()
0688 {
0689     Q_D(KPayeesView);
0690     if (d->ui->m_payeesList->currentItem() && d->ui->m_payeesList->selectedItems().count() == 1) {
0691         slotStartRename(d->ui->m_payeesList->currentItem());
0692     }
0693 }
0694 
0695 void KPayeesView::slotDeletePayee()
0696 {
0697     Q_D(KPayeesView);
0698     if (d->m_selectedPayeesList.isEmpty())
0699         return; // shouldn't happen
0700 
0701     // get confirmation from user
0702     QString prompt;
0703     if (d->m_selectedPayeesList.size() == 1)
0704         prompt = i18n("<p>Do you really want to remove the payee <b>%1</b>?</p>", d->m_selectedPayeesList.front().name());
0705     else
0706         prompt = i18n("Do you really want to remove all selected payees?");
0707 
0708     if (KMessageBox::questionYesNo(this, prompt, i18n("Remove Payee")) == KMessageBox::No)
0709         return;
0710 
0711     d->payeeReassign(KPayeeReassignDlg::TypeDelete);
0712 }
0713 
0714 void KPayeesView::slotMergePayee()
0715 {
0716     Q_D(KPayeesView);
0717     if (d->m_selectedPayeesList.size() < 1)
0718         return; // shouldn't happen
0719 
0720     if (KMessageBox::questionYesNo(this, i18n("<p>Do you really want to merge the selected payees?"),
0721                                    i18n("Merge Payees")) == KMessageBox::No)
0722         return;
0723 
0724     if (d->payeeReassign(KPayeeReassignDlg::TypeMerge))
0725         // clean selection since we just deleted the selected payees
0726         d->m_selectedPayeesList.clear();
0727 }