1 /***************************************************************************
2 kpayeesview.cpp
3 ---------------
4 begin : Thu Jan 24 2002
5 copyright : (C) 2000-2002 by Michael Edwardes <mte@users.sourceforge.net>
6 Javier Campos Morales <javi_c@users.sourceforge.net>
7 Felix Rodriguez <frodriguez@users.sourceforge.net>
8 John C <thetacoturtle@users.sourceforge.net>
9 Thomas Baumgart <ipwizard@users.sourceforge.net>
10 Kevin Tambascio <ktambascio@users.sourceforge.net>
11 Andreas Nicolai <Andreas.Nicolai@gmx.net>
12 (C) 2017 by Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com>
13 ***************************************************************************/
14
15 /***************************************************************************
16 * *
17 * This program is free software; you can redistribute it and/or modify *
18 * it under the terms of the GNU General Public License as published by *
19 * the Free Software Foundation; either version 2 of the License, or *
20 * (at your option) any later version. *
21 * *
22 ***************************************************************************/
23
24 #include "kpayeesview_p.h"
25
26 // ----------------------------------------------------------------------------
27 // QT Includes
28
29 #include <QMap>
30 #include <QList>
31 #include <QTimer>
32 #include <QMenu>
33 #include <QDesktopServices>
34 #include <QIcon>
35
36 // ----------------------------------------------------------------------------
37 // KDE Includes
38
39 #include <KLocalizedString>
40 #include <KMessageBox>
41 #include <KGuiItem>
42 #include <KHelpClient>
43 #include <KSharedConfig>
44 #include <KListWidgetSearchLine>
45
46 // ----------------------------------------------------------------------------
47 // Project Includes
48
49 #include <config-kmymoney.h>
50 #include "ui_kpayeesview.h"
51 #include "kmymoneyviewbase_p.h"
52 #include "kpayeeidentifierview.h"
53 #include "mymoneypayee.h"
54 #include "mymoneyexception.h"
55 #include "mymoneyfile.h"
56 #include "mymoneyaccount.h"
57 #include "mymoneymoney.h"
58 #include "mymoneytransactionfilter.h"
59 #include "kmymoneysettings.h"
60 #include "models.h"
61 #include "accountsmodel.h"
62 #include "mymoneysecurity.h"
63 #include "mymoneycontact.h"
64 #include "mymoneyprice.h"
65 #include "mymoneysplit.h"
66 #include "mymoneytransaction.h"
67 #include "icons/icons.h"
68 #include "transaction.h"
69 #include "widgetenums.h"
70 #include "mymoneyenums.h"
71 #include "modelenums.h"
72 #include "menuenums.h"
73
74 using namespace Icons;
75
76 // *** KPayeesView Implementation ***
77
KPayeesView(QWidget * parent)78 KPayeesView::KPayeesView(QWidget *parent) :
79 KMyMoneyViewBase(*new KPayeesViewPrivate(this), parent)
80 {
81 connect(pActions[eMenu::Action::NewPayee], &QAction::triggered, this, &KPayeesView::slotNewPayee);
82 connect(pActions[eMenu::Action::RenamePayee], &QAction::triggered, this, &KPayeesView::slotRenamePayee);
83 connect(pActions[eMenu::Action::DeletePayee], &QAction::triggered, this, &KPayeesView::slotDeletePayee);
84 connect(pActions[eMenu::Action::MergePayee], &QAction::triggered, this, &KPayeesView::slotMergePayee);
85 }
86
~KPayeesView()87 KPayeesView::~KPayeesView()
88 {
89 }
90
slotChooseDefaultAccount()91 void KPayeesView::slotChooseDefaultAccount()
92 {
93 Q_D(KPayeesView);
94 MyMoneyFile* file = MyMoneyFile::instance();
95 QMap<QString, int> account_count;
96
97 KMyMoneyRegister::RegisterItem* item = d->ui->m_register->firstItem();
98 while (item) {
99 //only walk through selectable items. eg. transactions and not group markers
100 if (item->isSelectable()) {
101 auto t = dynamic_cast<KMyMoneyRegister::Transaction*>(item);
102 if (!t)
103 return;
104 MyMoneySplit s = t->transaction().splitByPayee(d->m_payee.id());
105 const MyMoneyAccount& acc = file->account(s.accountId());
106
107 if (s.action() != MyMoneySplit::actionName(eMyMoney::Split::Action::Amortization)
108 && acc.accountType() != eMyMoney::Account::Type::AssetLoan
109 && !file->isTransfer(t->transaction())
110 && t->transaction().splitCount() == 2) {
111 MyMoneySplit s0 = t->transaction().splitByAccount(s.accountId(), false);
112 if (account_count.contains(s0.accountId())) {
113 account_count[s0.accountId()]++;
114 } else {
115 account_count[s0.accountId()] = 1;
116 }
117 }
118 }
119 item = item->nextItem();
120 }
121
122 QMap<QString, int>::Iterator most_frequent, iter;
123 most_frequent = account_count.begin();
124 for (iter = account_count.begin(); iter != account_count.end(); ++iter) {
125 if (iter.value() > most_frequent.value()) {
126 most_frequent = iter;
127 }
128 }
129
130 if (most_frequent != account_count.end()) {
131 d->ui->checkEnableDefaultCategory->setChecked(true);
132 d->ui->comboDefaultCategory->setSelected(most_frequent.key());
133 d->setDirty(true);
134 }
135 }
136
slotClosePayeeIdentifierSource()137 void KPayeesView::slotClosePayeeIdentifierSource()
138 {
139 Q_D(KPayeesView);
140 if (!d->m_needLoad)
141 d->ui->payeeIdentifiers->closeSource();
142 }
143
slotSelectByVariant(const QVariantList & variant,eView::Intent intent)144 void KPayeesView::slotSelectByVariant(const QVariantList& variant, eView::Intent intent)
145 {
146 switch (intent) {
147 case eView::Intent::ShowPayee:
148 if (variant.count() == 3)
149 slotSelectPayeeAndTransaction(variant.at(0).toString(), variant.at(1).toString(), variant.at(2).toString());
150 break;
151 default:
152 break;
153 }
154 }
155
156
slotStartRename(QListWidgetItem * item)157 void KPayeesView::slotStartRename(QListWidgetItem* item)
158 {
159 Q_D(KPayeesView);
160 d->m_allowEditing = true;
161 d->ui->m_payeesList->editItem(item);
162 }
163
164 // This variant is only called when a single payee is selected and renamed.
slotRenameSinglePayee(QListWidgetItem * p)165 void KPayeesView::slotRenameSinglePayee(QListWidgetItem* p)
166 {
167 Q_D(KPayeesView);
168 //if there is no current item selected, exit
169 if (d->m_allowEditing == false || !d->ui->m_payeesList->currentItem() || p != d->ui->m_payeesList->currentItem())
170 return;
171
172 //qDebug() << "[KPayeesView::slotRenamePayee]";
173 // create a copy of the new name without appended whitespaces
174 QString new_name = p->text();
175 if (d->m_payee.name() != new_name) {
176 MyMoneyFileTransaction ft;
177 try {
178 // check if we already have a payee with the new name
179 try {
180 // this function call will throw an exception, if the payee
181 // hasn't been found.
182 MyMoneyFile::instance()->payeeByName(new_name);
183 // the name already exists, ask the user whether he's sure to keep the name
184 if (KMessageBox::questionYesNo(this,
185 i18n("A payee with the name '%1' already exists. It is not advisable to have "
186 "multiple payees with the same identification name. Are you sure you would like "
187 "to rename the payee?", new_name)) != KMessageBox::Yes) {
188 p->setText(d->m_payee.name());
189 return;
190 }
191 } catch (const MyMoneyException &) {
192 // all ok, the name is unique
193 }
194
195 d->m_payee.setName(new_name);
196 d->m_newName = new_name;
197 MyMoneyFile::instance()->modifyPayee(d->m_payee);
198
199 // the above call to modifyPayee will reload the view so
200 // all references and pointers to the view have to be
201 // re-established.
202
203 // make sure, that the record is visible even if it moved
204 // out of sight due to the rename operation
205 d->ensurePayeeVisible(d->m_payee.id());
206
207 ft.commit();
208
209 } catch (const MyMoneyException &e) {
210 KMessageBox::detailedSorry(this, i18n("Unable to modify payee"), QString::fromLatin1(e.what()));
211 }
212 } else {
213 p->setText(new_name);
214 }
215 }
216
slotSelectPayee(QListWidgetItem * cur,QListWidgetItem * prev)217 void KPayeesView::slotSelectPayee(QListWidgetItem* cur, QListWidgetItem* prev)
218 {
219 Q_D(KPayeesView);
220 Q_UNUSED(cur);
221 Q_UNUSED(prev);
222
223 d->m_allowEditing = false;
224 }
225
slotSelectPayee()226 void KPayeesView::slotSelectPayee()
227 {
228 Q_D(KPayeesView);
229 // check if the content of a currently selected payee was modified
230 // and ask to store the data
231 if (d->isDirty()) {
232 if (KMessageBox::questionYesNo(this,
233 i18n("<qt>Do you want to save the changes for <b>%1</b>?</qt>", d->m_newName),
234 i18n("Save changes")) == KMessageBox::Yes) {
235 d->m_inSelection = true;
236 slotUpdatePayee();
237 d->m_inSelection = false;
238 }
239 }
240
241 // make sure we always clear the selected list when listing again
242 d->m_selectedPayeesList.clear();
243
244 // loop over all payees and count the number of payees, also
245 // obtain last selected payee
246 d->selectedPayees(d->m_selectedPayeesList);
247 updatePayeeActions(d->m_selectedPayeesList);
248
249 emit selectObjects(d->m_selectedPayeesList);
250
251 if (d->m_selectedPayeesList.isEmpty()) {
252 d->ui->m_tabWidget->setEnabled(false); // disable tab widget
253 d->ui->m_balanceLabel->hide();
254 d->ui->m_deleteButton->setEnabled(false); //disable delete, rename and merge buttons
255 d->ui->m_renameButton->setEnabled(false);
256 d->ui->m_mergeButton->setEnabled(false);
257 d->clearItemData();
258 d->m_payee = MyMoneyPayee();
259 d->ui->m_syncAddressbook->setEnabled(false);
260 return; // make sure we don't access an undefined payee
261 }
262
263 d->ui->m_deleteButton->setEnabled(true); //re-enable delete button
264
265 d->ui->m_syncAddressbook->setEnabled(true);
266
267 // if we have multiple payees selected, clear and disable the payee information
268 if (d->m_selectedPayeesList.count() > 1) {
269 d->ui->m_tabWidget->setEnabled(false); // disable tab widget
270 d->ui->m_renameButton->setEnabled(false); // disable also the rename button
271 d->ui->m_mergeButton->setEnabled(true);
272 d->ui->m_balanceLabel->hide();
273 d->clearItemData();
274 } else {
275 d->ui->m_mergeButton->setEnabled(false);
276 d->ui->m_renameButton->setEnabled(true);
277 }
278
279 // otherwise we have just one selected, enable payee information widget
280 d->ui->m_tabWidget->setEnabled(true);
281 d->ui->m_balanceLabel->show();
282
283 // as of now we are updating only the last selected payee, and until
284 // selection mode of the QListView has been changed to Extended, this
285 // will also be the only selection and behave exactly as before - Andreas
286 try {
287 d->m_payee = d->m_selectedPayeesList[0];
288
289 d->m_newName = d->m_payee.name();
290
291 d->ui->addressEdit->setEnabled(true);
292 d->ui->addressEdit->setText(d->m_payee.address());
293 d->ui->payeecityEdit->setEnabled(true);
294 d->ui->payeecityEdit->setText(d->m_payee.city());
295 d->ui->payeestateEdit->setEnabled(true);
296 d->ui->payeestateEdit->setText(d->m_payee.state());
297 d->ui->postcodeEdit->setEnabled(true);
298 d->ui->postcodeEdit->setText(d->m_payee.postcode());
299 d->ui->telephoneEdit->setEnabled(true);
300 d->ui->telephoneEdit->setText(d->m_payee.telephone());
301 d->ui->emailEdit->setEnabled(true);
302 d->ui->emailEdit->setText(d->m_payee.email());
303 d->ui->notesEdit->setText(d->m_payee.notes());
304
305 QStringList keys;
306 bool ignorecase = false;
307 auto type = d->m_payee.matchData(ignorecase, keys);
308
309 d->ui->matchTypeCombo->setCurrentIndex(d->ui->matchTypeCombo->findData(static_cast<int>(type)));
310 d->ui->matchKeyEditList->clear();
311 d->ui->matchKeyEditList->insertStringList(keys);
312 d->ui->checkMatchIgnoreCase->setChecked(ignorecase);
313
314 d->ui->checkEnableDefaultCategory->setChecked(!d->m_payee.defaultAccountId().isEmpty());
315 d->ui->comboDefaultCategory->setSelected(d->m_payee.defaultAccountId());
316
317 d->ui->payeeIdentifiers->setSource(d->m_payee);
318
319 slotPayeeDataChanged();
320
321 d->showTransactions();
322
323 } catch (const MyMoneyException &e) {
324 qDebug("exception during display of payee: %s", e.what());
325 d->ui->m_register->clear();
326 d->m_selectedPayeesList.clear();
327 d->m_payee = MyMoneyPayee();
328 }
329 d->m_allowEditing = true;
330 }
331
slotKeyListChanged()332 void KPayeesView::slotKeyListChanged()
333 {
334 Q_D(KPayeesView);
335 bool rc = false;
336 bool ignorecase = false;
337 QStringList keys;
338
339 d->m_payee.matchData(ignorecase, keys);
340 if (static_cast<eMyMoney::Payee::MatchType>(d->ui->matchTypeCombo->currentData().toUInt()) == eMyMoney::Payee::MatchType::Key) {
341 rc |= (keys != d->ui->matchKeyEditList->items());
342 }
343 d->setDirty(rc);
344 }
345
slotPayeeDataChanged()346 void KPayeesView::slotPayeeDataChanged()
347 {
348 Q_D(KPayeesView);
349 bool rc = false;
350
351 if (d->ui->m_tabWidget->isEnabled()) {
352 rc |= ((d->m_payee.email().isEmpty() != d->ui->emailEdit->text().isEmpty())
353 || (!d->ui->emailEdit->text().isEmpty() && d->m_payee.email() != d->ui->emailEdit->text()));
354 rc |= ((d->m_payee.address().isEmpty() != d->ui->addressEdit->toPlainText().isEmpty())
355 || (!d->ui->addressEdit->toPlainText().isEmpty() && d->m_payee.address() != d->ui->addressEdit->toPlainText()));
356 rc |= ((d->m_payee.city().isEmpty() != d->ui->payeecityEdit->text().isEmpty())
357 || (!d->ui->payeecityEdit->text().isEmpty() && d->m_payee.city() != d->ui->payeecityEdit->text()));
358 rc |= ((d->m_payee.state().isEmpty() != d->ui->payeestateEdit->text().isEmpty())
359 || (!d->ui->payeestateEdit->text().isEmpty() && d->m_payee.state() != d->ui->payeestateEdit->text()));
360 rc |= ((d->m_payee.postcode().isEmpty() != d->ui->postcodeEdit->text().isEmpty())
361 || (!d->ui->postcodeEdit->text().isEmpty() && d->m_payee.postcode() != d->ui->postcodeEdit->text()));
362 rc |= ((d->m_payee.telephone().isEmpty() != d->ui->telephoneEdit->text().isEmpty())
363 || (!d->ui->telephoneEdit->text().isEmpty() && d->m_payee.telephone() != d->ui->telephoneEdit->text()));
364 rc |= ((d->m_payee.name().isEmpty() != d->m_newName.isEmpty())
365 || (!d->m_newName.isEmpty() && d->m_payee.name() != d->m_newName));
366 rc |= ((d->m_payee.notes().isEmpty() != d->ui->notesEdit->toPlainText().isEmpty())
367 || (!d->ui->notesEdit->toPlainText().isEmpty() && d->m_payee.notes() != d->ui->notesEdit->toPlainText()));
368
369 bool ignorecase = false;
370 QStringList keys;
371
372 auto type = d->m_payee.matchData(ignorecase, keys);
373 rc |= (static_cast<unsigned int>(type) != d->ui->matchTypeCombo->currentData().toUInt());
374
375 d->ui->checkMatchIgnoreCase->setEnabled(false);
376 d->ui->matchKeyEditList->setEnabled(false);
377
378 if (static_cast<eMyMoney::Payee::MatchType>(d->ui->matchTypeCombo->currentData().toUInt()) != eMyMoney::Payee::MatchType::Disabled) {
379 d->ui->checkMatchIgnoreCase->setEnabled(true);
380 // if we turn matching on, we default to 'ignore case'
381 // TODO maybe make the default a user option
382 if (type == eMyMoney::Payee::MatchType::Disabled && static_cast<eMyMoney::Payee::MatchType>(d->ui->matchTypeCombo->currentData().toUInt()) != eMyMoney::Payee::MatchType::Disabled)
383 d->ui->checkMatchIgnoreCase->setChecked(true);
384 rc |= (ignorecase != d->ui->checkMatchIgnoreCase->isChecked());
385 if (static_cast<eMyMoney::Payee::MatchType>(d->ui->matchTypeCombo->currentData().toUInt()) == eMyMoney::Payee::MatchType::Key) {
386 d->ui->matchKeyEditList->setEnabled(true);
387 rc |= (keys != d->ui->matchKeyEditList->items());
388 }
389 }
390
391 rc |= (d->ui->checkEnableDefaultCategory->isChecked() != !d->m_payee.defaultAccountId().isEmpty());
392 if (d->ui->checkEnableDefaultCategory->isChecked()) {
393 d->ui->comboDefaultCategory->setEnabled(true);
394 d->ui->labelDefaultCategory->setEnabled(true);
395 // this is only going to understand the first in the list of selected accounts
396 if (d->ui->comboDefaultCategory->getSelected().isEmpty()) {
397 rc |= !d->m_payee.defaultAccountId().isEmpty();
398 } else {
399 QString temp = d->ui->comboDefaultCategory->getSelected();
400 rc |= (temp.isEmpty() != d->m_payee.defaultAccountId().isEmpty())
401 || (!d->m_payee.defaultAccountId().isEmpty() && temp != d->m_payee.defaultAccountId());
402 }
403 } else {
404 d->ui->comboDefaultCategory->setEnabled(false);
405 d->ui->labelDefaultCategory->setEnabled(false);
406 }
407
408 rc |= (d->m_payee.payeeIdentifiers() != d->ui->payeeIdentifiers->identifiers());
409 }
410 d->setDirty(rc);
411 }
412
slotUpdatePayee()413 void KPayeesView::slotUpdatePayee()
414 {
415 Q_D(KPayeesView);
416 if (d->isDirty()) {
417 MyMoneyFileTransaction ft;
418 d->setDirty(false);
419 try {
420 d->m_payee.setName(d->m_newName);
421 d->m_payee.setAddress(d->ui->addressEdit->toPlainText());
422 d->m_payee.setCity(d->ui->payeecityEdit->text());
423 d->m_payee.setState(d->ui->payeestateEdit->text());
424 d->m_payee.setPostcode(d->ui->postcodeEdit->text());
425 d->m_payee.setTelephone(d->ui->telephoneEdit->text());
426 d->m_payee.setEmail(d->ui->emailEdit->text());
427 d->m_payee.setNotes(d->ui->notesEdit->toPlainText());
428 d->m_payee.setMatchData(static_cast<eMyMoney::Payee::MatchType>(d->ui->matchTypeCombo->currentData().toUInt()), d->ui->checkMatchIgnoreCase->isChecked(), d->ui->matchKeyEditList->items());
429 d->m_payee.setDefaultAccountId();
430 d->m_payee.resetPayeeIdentifiers(d->ui->payeeIdentifiers->identifiers());
431
432 if (d->ui->checkEnableDefaultCategory->isChecked()) {
433 QString temp;
434 if (!d->ui->comboDefaultCategory->getSelected().isEmpty()) {
435 temp = d->ui->comboDefaultCategory->getSelected();
436 d->m_payee.setDefaultAccountId(temp);
437 }
438 }
439
440 MyMoneyFile::instance()->modifyPayee(d->m_payee);
441 ft.commit();
442
443 } catch (const MyMoneyException &e) {
444 KMessageBox::detailedSorry(this, i18n("Unable to modify payee"), QString::fromLatin1(e.what()));
445 }
446 }
447 }
448
slotSyncAddressBook()449 void KPayeesView::slotSyncAddressBook()
450 {
451 Q_D(KPayeesView);
452 if (d->m_payeeRows.isEmpty()) { // empty list means no syncing is pending...
453 foreach (auto item, d->ui->m_payeesList->selectedItems()) {
454 d->m_payeeRows.append(d->ui->m_payeesList->row(item)); // ...so initialize one
455 }
456 d->ui->m_payeesList->clearSelection(); // otherwise slotSelectPayee will be run after every payee update
457 // d->ui->m_syncAddressbook->setEnabled(false); // disallow concurrent syncs
458 }
459
460 if (d->m_payeeRows.count() <= d->m_payeeRow) {
461 if (auto item = dynamic_cast<KPayeeListItem*>(d->ui->m_payeesList->currentItem())) { // update ui if something is selected
462 d->m_payee = item->payee();
463 d->ui->addressEdit->setText(d->m_payee.address());
464 d->ui->payeecityEdit->setText(d->m_payee.city());
465 d->ui->payeestateEdit->setText(d->m_payee.state());
466 d->ui->postcodeEdit->setText(d->m_payee.postcode());
467 d->ui->telephoneEdit->setText(d->m_payee.telephone());
468 }
469 d->m_payeeRows.clear(); // that means end of sync
470 d->m_payeeRow = 0;
471 return;
472 }
473
474 if (auto item = dynamic_cast<KPayeeListItem*>(d->ui->m_payeesList->item(d->m_payeeRows.at(d->m_payeeRow))))
475 d->m_payee = item->payee();
476 ++d->m_payeeRow;
477
478 d->m_contact->fetchContact(d->m_payee.email()); // search for payee's data in addressbook and receive it in slotContactFetched
479 }
480
slotContactFetched(const ContactData & identity)481 void KPayeesView::slotContactFetched(const ContactData &identity)
482 {
483 Q_D(KPayeesView);
484 if (!identity.email.isEmpty()) { // empty e-mail means no identity fetched
485 QString txt;
486 if (!identity.street.isEmpty())
487 txt.append(identity.street + '\n');
488 if (!identity.locality.isEmpty()) {
489 txt.append(identity.locality);
490 if (!identity.postalCode.isEmpty())
491 txt.append(' ' + identity.postalCode + '\n');
492 else
493 txt.append('\n');
494 }
495 if (!identity.country.isEmpty())
496 txt.append(identity.country + '\n');
497
498 if (!txt.isEmpty() && d->m_payee.address().compare(txt) != 0)
499 d->m_payee.setAddress(txt);
500
501 if (!identity.city.isEmpty() && d->m_payee.city().compare(identity.city) != 0)
502 d->m_payee.setCity(identity.city);
503
504 if (!identity.state.isEmpty() && d->m_payee.state().compare(identity.state) != 0)
505 d->m_payee.setState(identity.state);
506
507 if (!identity.postalCode.isEmpty() && d->m_payee.postcode().compare(identity.postalCode) != 0)
508 d->m_payee.setPostcode(identity.postalCode);
509
510 if (!identity.phoneNumber.isEmpty() && d->m_payee.telephone().compare(identity.phoneNumber) != 0)
511 d->m_payee.setTelephone(identity.phoneNumber);
512
513 MyMoneyFileTransaction ft;
514 try {
515 MyMoneyFile::instance()->modifyPayee(d->m_payee);
516 ft.commit();
517 } catch (const MyMoneyException &e) {
518 KMessageBox::detailedSorry(this, i18n("Unable to modify payee"), QString::fromLatin1(e.what()));
519 }
520 }
521
522 slotSyncAddressBook(); // process next payee
523 }
524
slotSendMail()525 void KPayeesView::slotSendMail()
526 {
527 Q_D(KPayeesView);
528 QRegularExpression re(".+@.+");
529 if (re.match(d->m_payee.email()).hasMatch())
530 QDesktopServices::openUrl(QUrl(QStringLiteral("mailto:?to=") + d->m_payee.email(), QUrl::TolerantMode));
531 }
532
executeCustomAction(eView::Action action)533 void KPayeesView::executeCustomAction(eView::Action action)
534 {
535 switch(action) {
536 case eView::Action::Refresh:
537 refresh();
538 break;
539
540 case eView::Action::SetDefaultFocus:
541 {
542 Q_D(KPayeesView);
543 QTimer::singleShot(0, d->m_searchWidget, SLOT(setFocus()));
544 }
545 break;
546
547 case eView::Action::ClosePayeeIdentifierSource:
548 slotClosePayeeIdentifierSource();
549 break;
550
551 default:
552 break;
553 }
554 }
555
refresh()556 void KPayeesView::refresh()
557 {
558 Q_D(KPayeesView);
559 if (isVisible()) {
560 if (d->m_inSelection) {
561 QTimer::singleShot(0, this, SLOT(refresh()));
562 } else {
563 d->loadPayees();
564 d->m_needsRefresh = false;
565 }
566 } else {
567 d->m_needsRefresh = true;
568 }
569 }
570
showEvent(QShowEvent * event)571 void KPayeesView::showEvent(QShowEvent* event)
572 {
573 if (MyMoneyFile::instance()->storageAttached()) {
574 Q_D(KPayeesView);
575 if (d->m_needLoad)
576 d->init();
577
578 emit customActionRequested(View::Payees, eView::Action::AboutToShow);
579
580 if (d->m_needsRefresh)
581 refresh();
582
583 QList<MyMoneyPayee> list;
584 d->selectedPayees(list);
585 emit selectObjects(list);
586 }
587
588 // don't forget base class implementation
589 QWidget::showEvent(event);
590 }
591
updatePayeeActions(const QList<MyMoneyPayee> & payees)592 void KPayeesView::updatePayeeActions(const QList<MyMoneyPayee> &payees)
593 {
594 pActions[eMenu::Action::NewPayee]->setEnabled(true);
595 const auto payeesCount = payees.count();
596 auto b = payeesCount == 1 ? true : false;
597 pActions[eMenu::Action::RenamePayee]->setEnabled(b);
598 b = payeesCount > 1 ? true : false;
599 pActions[eMenu::Action::MergePayee]->setEnabled(b);
600 b = payeesCount == 0 ? false : true;
601 pActions[eMenu::Action::DeletePayee]->setEnabled(b);
602 }
603
slotSelectTransaction()604 void KPayeesView::slotSelectTransaction()
605 {
606 Q_D(KPayeesView);
607 auto list = d->ui->m_register->selectedItems();
608 if (!list.isEmpty()) {
609 const auto t = dynamic_cast<KMyMoneyRegister::Transaction*>(list[0]);
610 if (t)
611 emit selectByVariant(QVariantList {QVariant(t->split().accountId()), QVariant(t->transaction().id()) }, eView::Intent::ShowTransaction);
612 }
613 }
614
slotSelectPayeeAndTransaction(const QString & payeeId,const QString & accountId,const QString & transactionId)615 void KPayeesView::slotSelectPayeeAndTransaction(const QString& payeeId, const QString& accountId, const QString& transactionId)
616 {
617 Q_D(KPayeesView);
618 if (!isVisible())
619 return;
620
621 try {
622 // clear filter
623 d->m_searchWidget->clear();
624 d->m_searchWidget->updateSearch();
625
626 // deselect all other selected items
627 QList<QListWidgetItem *> selectedItems = d->ui->m_payeesList->selectedItems();
628 QList<QListWidgetItem *>::const_iterator payeesIt = selectedItems.constBegin();
629 while (payeesIt != selectedItems.constEnd()) {
630 if (auto item = dynamic_cast<KPayeeListItem*>(*payeesIt))
631 item->setSelected(false);
632 ++payeesIt;
633 }
634
635 // find the payee in the list
636 QListWidgetItem* it;
637 for (int i = 0; i < d->ui->m_payeesList->count(); ++i) {
638 it = d->ui->m_payeesList->item(i);
639 auto item = dynamic_cast<KPayeeListItem *>(it);
640 if (item && item->payee().id() == payeeId) {
641 d->ui->m_payeesList->scrollToItem(it, QAbstractItemView::PositionAtCenter);
642
643 d->ui->m_payeesList->setCurrentItem(it); // active item and deselect all others
644 d->ui->m_payeesList->setCurrentRow(i, QItemSelectionModel::ClearAndSelect); // and select it
645
646 //make sure the payee selection is updated and transactions are updated accordingly
647 slotSelectPayee();
648
649 KMyMoneyRegister::RegisterItem *registerItem = 0;
650 for (i = 0; i < d->ui->m_register->rowCount(); ++i) {
651 registerItem = d->ui->m_register->itemAtRow(i);
652 if (auto t = dynamic_cast<KMyMoneyRegister::Transaction*>(registerItem)) {
653 if (t->transaction().id() == transactionId && t->transaction().accountReferenced(accountId)) {
654 d->ui->m_register->selectItem(registerItem);
655 d->ui->m_register->ensureItemVisible(registerItem);
656 break;
657 }
658 }
659 }
660 // quit out of outer for() loop
661 break;
662 }
663 }
664 } catch (const MyMoneyException &e) {
665 qWarning("Unexpected exception in KPayeesView::slotSelectPayeeAndTransaction %s", e.what());
666 }
667 }
668
slotShowPayeesMenu(const QPoint &)669 void KPayeesView::slotShowPayeesMenu(const QPoint& /*p*/)
670 {
671 Q_D(KPayeesView);
672 if (dynamic_cast<KPayeeListItem*>(d->ui->m_payeesList->currentItem())) {
673 slotSelectPayee();
674 pMenus[eMenu::Menu::Payee]->exec(QCursor::pos());
675 }
676 }
677
slotHelp()678 void KPayeesView::slotHelp()
679 {
680 KHelpClient::invokeHelp("details.payees");
681 }
682
slotChangeFilter(int index)683 void KPayeesView::slotChangeFilter(int index)
684 {
685 Q_D(KPayeesView);
686 //update the filter type then reload the payees list
687 d->m_payeeFilterType = index;
688 d->loadPayees();
689 }
690
slotNewPayee()691 void KPayeesView::slotNewPayee()
692 {
693 QString id;
694 KMyMoneyUtils::newPayee(i18n("New Payee"), id);
695 slotSelectPayeeAndTransaction(id);
696 }
697
slotRenamePayee()698 void KPayeesView::slotRenamePayee()
699 {
700 Q_D(KPayeesView);
701 if (d->ui->m_payeesList->currentItem() && d->ui->m_payeesList->selectedItems().count() == 1) {
702 slotStartRename(d->ui->m_payeesList->currentItem());
703 }
704 }
705
slotDeletePayee()706 void KPayeesView::slotDeletePayee()
707 {
708 Q_D(KPayeesView);
709 if (d->m_selectedPayeesList.isEmpty())
710 return; // shouldn't happen
711
712 // get confirmation from user
713 QString prompt;
714 if (d->m_selectedPayeesList.size() == 1)
715 prompt = i18n("<p>Do you really want to remove the payee <b>%1</b>?</p>", d->m_selectedPayeesList.front().name());
716 else
717 prompt = i18n("Do you really want to remove all selected payees?");
718
719 if (KMessageBox::questionYesNo(this, prompt, i18n("Remove Payee")) == KMessageBox::No)
720 return;
721
722 d->payeeReassign(KPayeeReassignDlg::TypeDelete);
723 }
724
slotMergePayee()725 void KPayeesView::slotMergePayee()
726 {
727 Q_D(KPayeesView);
728 if (d->m_selectedPayeesList.size() < 1)
729 return; // shouldn't happen
730
731 if (KMessageBox::questionYesNo(this, i18n("<p>Do you really want to merge the selected payees?"),
732 i18n("Merge Payees")) == KMessageBox::No)
733 return;
734
735 if (d->payeeReassign(KPayeeReassignDlg::TypeMerge))
736 // clean selection since we just deleted the selected payees
737 d->m_selectedPayeesList.clear();
738 }
739