1 /*
2  * Copyright 2006-2018  Thomas Baumgart <tbaumgart@kde.org>
3  * Copyright 2017-2018  Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of
8  * the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "stdtransaction.h"
20 #include "stdtransaction_p.h"
21 
22 // ----------------------------------------------------------------------------
23 // QT Includes
24 
25 #include <QString>
26 #include <QPainter>
27 #include <QWidget>
28 #include <QList>
29 #include <QBoxLayout>
30 #include <QPushButton>
31 
32 // ----------------------------------------------------------------------------
33 // KDE Includes
34 
35 #include <KLocalizedString>
36 
37 // ----------------------------------------------------------------------------
38 // Project Includes
39 
40 #include "kmymoneypayeecombo.h"
41 #include "kmymoneycombo.h"
42 #include "kmymoneytagcombo.h"
43 #include "tabbar.h"
44 #include "ktagcontainer.h"
45 #include "mymoneytransaction.h"
46 #include "mymoneysplit.h"
47 #include "mymoneyexception.h"
48 #include "mymoneyfile.h"
49 #include "register.h"
50 #include "transactionform.h"
51 #include "kmymoneylineedit.h"
52 #include "kmymoneyutils.h"
53 #ifndef KMM_DESIGNER
54 #include "stdtransactioneditor.h"
55 #endif
56 
57 #include "kmymoneysettings.h"
58 #include "widgetenums.h"
59 #include "mymoneyenums.h"
60 
61 using namespace eWidgets;
62 using namespace KMyMoneyRegister;
63 using namespace KMyMoneyTransactionForm;
64 
StdTransaction(Register * parent,const MyMoneyTransaction & transaction,const MyMoneySplit & split,int uniqueId)65 StdTransaction::StdTransaction(Register *parent, const MyMoneyTransaction& transaction, const MyMoneySplit& split, int uniqueId) :
66   Transaction(*new StdTransactionPrivate, parent, transaction, split, uniqueId)
67 {
68   Q_D(StdTransaction);
69   d->m_showAccountRow = false;
70   try {
71     d->m_categoryHeader = i18n("Category");
72     switch (transaction.splitCount()) {
73       default:
74         d->m_category = i18nc("Split transaction (category replacement)", "Split transaction");
75         break;
76 
77       case 0: // the empty transaction
78       case 1:
79         break;
80 
81       case 2:
82         setupFormHeader(d->m_transaction.splitByAccount(d->m_split.accountId(), false).accountId());
83         break;
84     }
85   } catch (const MyMoneyException &e) {
86     qDebug() << "Problem determining the category for transaction '" << d->m_transaction.id() << "'. Reason: " << e.what()  << "\n";
87   }
88   d->m_rowsForm = 6;
89 
90   if (KMyMoneyUtils::transactionType(d->m_transaction) == KMyMoneyUtils::InvestmentTransaction) {
91     MyMoneySplit stockSplit = KMyMoneyUtils::stockSplit(d->m_transaction);
92     d->m_payee = MyMoneyFile::instance()->account(stockSplit.accountId()).name();
93     QString addon;
94     if (stockSplit.action() == MyMoneySplit::actionName(eMyMoney::Split::Action::BuyShares)) {
95       if (stockSplit.value().isNegative()) {
96         addon = i18n("Sell");
97       } else {
98         addon = i18n("Buy");
99       }
100     } else if (stockSplit.action() == MyMoneySplit::actionName(eMyMoney::Split::Action::Dividend)) {
101       addon = i18n("Dividend");
102     } else if (stockSplit.action() == MyMoneySplit::actionName(eMyMoney::Split::Action::Yield)) {
103       addon = i18n("Yield");
104     } else if (stockSplit.action() == MyMoneySplit::actionName(eMyMoney::Split::Action::InterestIncome)) {
105       addon = i18n("Interest Income");
106     }
107     if (!addon.isEmpty()) {
108       d->m_payee += QString(" (%1)").arg(addon);
109     }
110     d->m_payeeHeader = i18n("Activity");
111     d->m_category = i18n("Investment transaction");
112   }
113 
114   // setup initial size
115   setNumRowsRegister(numRowsRegister(KMyMoneySettings::showRegisterDetailed()));
116 
117   emit parent->itemAdded(this);
118 }
119 
~StdTransaction()120 StdTransaction::~StdTransaction()
121 {
122 }
123 
className()124 const char* StdTransaction::className()
125 {
126   return "StdTransaction";
127 }
128 
setupFormHeader(const QString & id)129 void StdTransaction::setupFormHeader(const QString& id)
130 {
131   Q_D(StdTransaction);
132   d->m_category = MyMoneyFile::instance()->accountToCategory(id);
133   switch (MyMoneyFile::instance()->account(id).accountGroup()) {
134     case eMyMoney::Account::Type::Asset:
135     case eMyMoney::Account::Type::Liability:
136       d->m_categoryHeader = d->m_split.shares().isNegative() ? i18n("Transfer to") : i18n("Transfer from");
137       break;
138 
139     default:
140       d->m_categoryHeader = i18n("Category");
141       break;
142   }
143 }
144 
actionType() const145 eRegister::Action StdTransaction::actionType() const
146 {
147   Q_D(const StdTransaction);
148   eRegister::Action action = eRegister::Action::None;
149 
150   // if at least one split is referencing an income or
151   // expense account, we will not call it a transfer
152 
153   auto found = false;
154   foreach (const auto split, d->m_transaction.splits()) {
155     if (split.accountId() == d->m_split.accountId())
156       continue;
157     auto acc = MyMoneyFile::instance()->account(split.accountId());
158     if (acc.accountGroup() == eMyMoney::Account::Type::Income
159         || acc.accountGroup() == eMyMoney::Account::Type::Expense) {
160       // otherwise, we have to determine between deposit and withdrawal
161       action = d->m_split.shares().isNegative() ? eRegister::Action::Withdrawal : eRegister::Action::Deposit;
162       found = true;
163       break;
164     }
165   }
166   // otherwise, it's a transfer
167   if (!found)
168     action = eRegister::Action::Transfer;
169 
170   return action;
171 }
172 
loadTab(TransactionForm * form)173 void StdTransaction::loadTab(TransactionForm* form)
174 {
175   Q_D(StdTransaction);
176   KMyMoneyTransactionForm::TabBar* bar = form->getTabBar();
177   bar->setSignalEmission(eTabBar::SignalEmission::Never);
178   for (auto i = 0; i < bar->count(); ++i) {
179     bar->setTabEnabled(i, true);
180   }
181 
182   if (d->m_transaction.splitCount() > 0) {
183     bar->setCurrentIndex((int)actionType());
184   }
185   bar->setSignalEmission(eTabBar::SignalEmission::Always);
186 }
187 
numColsForm() const188 int StdTransaction::numColsForm() const
189 {
190   return 4;
191 }
192 
setupForm(TransactionForm * form)193 void StdTransaction::setupForm(TransactionForm* form)
194 {
195   Transaction::setupForm(form);
196   form->setSpan(4, (int)eTransactionForm::Column::Value1, 3, 1);
197 }
198 
showRowInForm(int row) const199 bool StdTransaction::showRowInForm(int row) const
200 {
201   Q_D(const StdTransaction);
202   return row == 0 ? d->m_showAccountRow : true;
203 }
204 
setShowRowInForm(int row,bool show)205 void StdTransaction::setShowRowInForm(int row, bool show)
206 {
207   Q_D(StdTransaction);
208   if (row == 0)
209     d->m_showAccountRow = show;
210 }
211 
formCellText(QString & txt,Qt::Alignment & align,int row,int col,QPainter *)212 bool StdTransaction::formCellText(QString& txt, Qt::Alignment& align, int row, int col, QPainter* /* painter */)
213 {
214   Q_D(const StdTransaction);
215   // if(m_transaction != MyMoneyTransaction()) {
216   switch (row) {
217     case 0:
218       switch (col) {
219         case (int)eTransactionForm::Column::Label1:
220           align |= Qt::AlignLeft;
221           txt = i18n("Account");
222           break;
223       }
224       break;
225 
226     case 1:
227       switch (col) {
228         case (int)eTransactionForm::Column::Label1:
229           align |= Qt::AlignLeft;
230           txt = d->m_payeeHeader;
231           break;
232 
233         case (int)eTransactionForm::Column::Value1:
234           align |= Qt::AlignLeft;
235           txt = d->m_payee;
236           break;
237 
238         case (int)eTransactionForm::Column::Label2:
239           align |= Qt::AlignLeft;
240           if (haveNumberField())
241             txt = i18n("Number");
242           break;
243 
244         case (int)eTransactionForm::Column::Value2:
245           align |= Qt::AlignRight;
246           if (haveNumberField())
247             txt = d->m_split.number();
248           break;
249       }
250       break;
251 
252     case 2:
253       switch (col) {
254         case (int)eTransactionForm::Column::Label1:
255           align |= Qt::AlignLeft;
256           txt = d->m_categoryHeader;
257           break;
258 
259         case (int)eTransactionForm::Column::Value1:
260           align |= Qt::AlignLeft;
261           txt = d->m_category;
262           if (!d->m_transaction.id().isEmpty()) {
263             if (txt.isEmpty() && !d->m_split.value().isZero())
264               txt = i18n("*** UNASSIGNED ***");
265           }
266           break;
267 
268         case (int)eTransactionForm::Column::Label2:
269           align |= Qt::AlignLeft;
270           txt = i18n("Date");
271           break;
272 
273         case (int)eTransactionForm::Column::Value2:
274           align |= Qt::AlignRight;
275           if (!d->m_transaction.id().isEmpty())
276             txt = QLocale().toString(d->m_transaction.postDate(), QLocale::ShortFormat);
277           break;
278       }
279       break;
280 
281     case 3:
282       switch (col) {
283         case (int)eTransactionForm::Column::Label1:
284           align |= Qt::AlignLeft;
285           txt = i18n("Tags");
286           break;
287 
288         case (int)eTransactionForm::Column::Value1:
289           align |= Qt::AlignLeft;
290           if (!d->m_tagList.isEmpty()) {
291             for (auto i = 0; i < d->m_tagList.size() - 1; ++i)
292               txt += d->m_tagList[i] + ", ";
293             txt += d->m_tagList.last();
294           }
295           //if (m_transaction != MyMoneyTransaction())
296           //  txt = m_split.tagId();
297           break;
298 
299         case (int)eTransactionForm::Column::Label2:
300           align |= Qt::AlignLeft;
301           txt = i18n("Amount");
302           break;
303 
304         case (int)eTransactionForm::Column::Value2:
305           align |= Qt::AlignRight;
306           if (!d->m_transaction.id().isEmpty()) {
307             txt = (d->m_split.value(d->m_transaction.commodity(), d->m_splitCurrencyId).abs()).formatMoney(d->m_account.fraction());
308           }
309           break;
310       }
311       break;
312 
313     case 4:
314       switch (col) {
315         case (int)eTransactionForm::Column::Label1:
316           align |= Qt::AlignLeft;
317           txt = i18n("Memo");
318           break;
319 
320         case (int)eTransactionForm::Column::Value1:
321           align &= ~Qt::AlignVCenter;
322           align |= Qt::AlignTop;
323           align |= Qt::AlignLeft;
324           if (!d->m_transaction.id().isEmpty())
325             txt = d->m_split.memo().section('\n', 0, 2);
326           break;
327       }
328       break;
329 
330     case 5:
331       switch (col) {
332         case (int)eTransactionForm::Column::Label2:
333           align |= Qt::AlignLeft;
334           txt = i18n("Status");
335           break;
336 
337         case (int)eTransactionForm::Column::Value2:
338           align |= Qt::AlignRight;
339           txt = reconcileState();
340           break;
341       }
342   }
343 
344   // }
345   if (col == (int)eTransactionForm::Column::Value2 && row == 1) {
346     return haveNumberField();
347   }
348   return (col == (int)eTransactionForm::Column::Value1 && row < 5) || (col == (int)eTransactionForm::Column::Value2 && row > 0 && row != 4);
349 }
350 
registerCellText(QString & txt,Qt::Alignment & align,int row,int col,QPainter * painter)351 void StdTransaction::registerCellText(QString& txt, Qt::Alignment& align, int row, int col, QPainter* painter)
352 {
353   Q_D(const StdTransaction);
354   switch (row) {
355     case 0:
356       switch (col) {
357         case (int)eTransaction::Column::Number:
358           align |= Qt::AlignLeft;
359           if (haveNumberField())
360             txt = d->m_split.number();
361           break;
362 
363         case (int)eTransaction::Column::Date:
364           align |= Qt::AlignLeft;
365           txt = QLocale().toString(d->m_transaction.postDate(), QLocale::ShortFormat);
366           break;
367 
368         case (int)eTransaction::Column::Detail:
369           switch (d->m_parent->getDetailsColumnType()) {
370             case eRegister::DetailColumn::PayeeFirst:
371               txt = d->m_payee;
372               break;
373             case eRegister::DetailColumn::AccountFirst:
374               txt = d->m_category;
375               if (!d->m_tagList.isEmpty()) {
376                 txt += " ( ";
377                 for (auto i = 0; i < d->m_tagList.size() - 1; ++i) {
378                   txt += "<span style='color: " + d->m_tagColorList[i].name() + "'>&#x25CF;</span> " + d->m_tagList[i] + ", ";
379                 }
380                 txt += "<span style='color: " + d->m_tagColorList.last().name() + "'>&#x25CF;</span> " + d->m_tagList.last() + " )";
381               }
382               break;
383           }
384           align |= Qt::AlignLeft;
385           if (txt.isEmpty() && d->m_rowsRegister < 3) {
386             singleLineMemo(txt, d->m_split);
387           }
388           if (txt.isEmpty() && d->m_rowsRegister < 2) {
389             if (d->m_account.accountType() != eMyMoney::Account::Type::Income
390                 && d->m_account.accountType() != eMyMoney::Account::Type::Expense) {
391               txt = d->m_category;
392               if (txt.isEmpty() && !d->m_split.value().isZero()) {
393                 txt = i18n("*** UNASSIGNED ***");
394                 if (painter)
395                   painter->setPen(KMyMoneySettings::schemeColor(SchemeColor::TransactionErroneous));
396               }
397 
398               if (!d->m_tagList.isEmpty()) {
399                 txt += " ( ";
400                 for (auto i = 0; i < d->m_tagList.size() - 1; ++i) {
401                   txt += "<span style='color: " + d->m_tagColorList[i].name() + "'>&#x25CF;</span> " + d->m_tagList[i] + ", ";
402                 }
403                 txt += "<span style='color: " + d->m_tagColorList.last().name() + "'>&#x25CF;</span> " + d->m_tagList.last() + " )";
404               }
405             }
406           }
407           break;
408 
409         case (int)eTransaction::Column::ReconcileFlag:
410           align |= Qt::AlignHCenter;
411           txt = reconcileState(false);
412           break;
413 
414         case (int)eTransaction::Column::Payment:
415           align |= Qt::AlignRight;
416           if (d->m_split.value().isNegative()) {
417             txt = (-d->m_split.value(d->m_transaction.commodity(), d->m_splitCurrencyId)).formatMoney(d->m_account.fraction());
418           }
419           break;
420 
421         case (int)eTransaction::Column::Deposit:
422           align |= Qt::AlignRight;
423           if (!d->m_split.value().isNegative()) {
424             txt = d->m_split.value(d->m_transaction.commodity(), d->m_splitCurrencyId).formatMoney(d->m_account.fraction());
425           }
426           break;
427 
428         case (int)eTransaction::Column::Balance:
429           align |= Qt::AlignRight;
430           if (d->m_showBalance)
431             txt = d->m_balance.formatMoney(d->m_account.fraction());
432           else
433             txt = "----";
434           break;
435 
436         case (int)eTransaction::Column::Account:
437           // txt = m_objects->account(m_transaction.splits()[0].accountId()).name();
438           txt = MyMoneyFile::instance()->account(d->m_split.accountId()).name();
439           break;
440 
441         default:
442           break;
443       }
444       break;
445 
446     case 1:
447       switch (col) {
448         case (int)eTransaction::Column::Detail:
449           switch (d->m_parent->getDetailsColumnType()) {
450             case eRegister::DetailColumn::PayeeFirst:
451               txt = d->m_category;
452               if (txt.isEmpty() && !d->m_split.value().isZero()) {
453                 txt = i18n("*** UNASSIGNED ***");
454                 if (painter)
455                   painter->setPen(KMyMoneySettings::schemeColor(SchemeColor::TransactionErroneous));
456               }
457               if (!d->m_tagList.isEmpty()) {
458                 txt += " ( ";
459                 for (auto i = 0; i < d->m_tagList.size() - 1; ++i) {
460                   txt += "<span style='color: " + d->m_tagColorList[i].name() + "'>&#x25CF;</span> " + d->m_tagList[i] + ", ";
461                 }
462                 txt += "<span style='color: " + d->m_tagColorList.last().name() + "'>&#x25CF;</span> " + d->m_tagList.last() + " )";
463               }
464               break;
465             case eRegister::DetailColumn::AccountFirst:
466               txt = d->m_payee;
467               if (txt.isEmpty()) {
468                 singleLineMemo(txt, d->m_split);
469               }
470               break;
471           }
472           align |= Qt::AlignLeft;
473           break;
474 
475         default:
476           break;
477       }
478       break;
479 
480     case 2:
481       switch (col) {
482         case (int)eTransaction::Column::Detail:
483           align |= Qt::AlignLeft;
484           singleLineMemo(txt, d->m_split);
485           break;
486 
487         default:
488           break;
489       }
490       break;
491   }
492 }
493 
registerColWidth(int col,const QFontMetrics & cellFontMetrics)494 int StdTransaction::registerColWidth(int col, const QFontMetrics& cellFontMetrics)
495 {
496   QString txt;
497   int firstRow = 0, lastRow = numRowsRegister();
498 
499   int nw = 0;
500   for (int i = firstRow; i <= lastRow; ++i) {
501     Qt::Alignment align;
502     registerCellText(txt, align, i, col, 0);
503     int w = cellFontMetrics.width(txt + "   ");
504     if (w > nw)
505       nw = w;
506   }
507   return nw;
508 }
509 
arrangeWidgetsInForm(QMap<QString,QWidget * > & editWidgets)510 void StdTransaction::arrangeWidgetsInForm(QMap<QString, QWidget*>& editWidgets)
511 {
512   Q_D(StdTransaction);
513   if (!d->m_form || !d->m_parent)
514     return;
515 
516   setupFormPalette(editWidgets);
517 
518   arrangeWidget(d->m_form, 0, (int)eTransactionForm::Column::Label1, editWidgets["account-label"]);
519   arrangeWidget(d->m_form, 0, (int)eTransactionForm::Column::Value1, editWidgets["account"]);
520   arrangeWidget(d->m_form, 1, (int)eTransactionForm::Column::Label1, editWidgets["cashflow"]);
521   arrangeWidget(d->m_form, 1, (int)eTransactionForm::Column::Value1, editWidgets["payee"]);
522   arrangeWidget(d->m_form, 2, (int)eTransactionForm::Column::Label1, editWidgets["category-label"]);
523   arrangeWidget(d->m_form, 2, (int)eTransactionForm::Column::Value1, editWidgets["category"]->parentWidget());
524   arrangeWidget(d->m_form, 3, (int)eTransactionForm::Column::Label1, editWidgets["tag-label"]);
525   arrangeWidget(d->m_form, 3, (int)eTransactionForm::Column::Value1, editWidgets["tag"]);
526   arrangeWidget(d->m_form, 4, (int)eTransactionForm::Column::Label1, editWidgets["memo-label"]);
527   arrangeWidget(d->m_form, 4, (int)eTransactionForm::Column::Value1, editWidgets["memo"]);
528   if (haveNumberField()) {
529     arrangeWidget(d->m_form, 1, (int)eTransactionForm::Column::Label2, editWidgets["number-label"]);
530     arrangeWidget(d->m_form, 1, (int)eTransactionForm::Column::Value2, editWidgets["number"]);
531   }
532   arrangeWidget(d->m_form, 2, (int)eTransactionForm::Column::Label2, editWidgets["date-label"]);
533   arrangeWidget(d->m_form, 2, (int)eTransactionForm::Column::Value2, editWidgets["postdate"]);
534   arrangeWidget(d->m_form, 3, (int)eTransactionForm::Column::Label2, editWidgets["amount-label"]);
535   arrangeWidget(d->m_form, 3, (int)eTransactionForm::Column::Value2, editWidgets["amount"]);
536   arrangeWidget(d->m_form, 5, (int)eTransactionForm::Column::Label2, editWidgets["status-label"]);
537   arrangeWidget(d->m_form, 5, (int)eTransactionForm::Column::Value2, editWidgets["status"]);
538 
539   // get rid of the hints. we don't need them for the form
540   QMap<QString, QWidget*>::iterator it;
541   for (it = editWidgets.begin(); it != editWidgets.end(); ++it) {
542     KMyMoneyCombo* combo = dynamic_cast<KMyMoneyCombo*>(*it);
543     KMyMoneyLineEdit* edit = dynamic_cast<KMyMoneyLineEdit*>(*it);
544     KMyMoneyPayeeCombo* payee = dynamic_cast<KMyMoneyPayeeCombo*>(*it);
545     KTagContainer* tag = dynamic_cast<KTagContainer*>(*it);
546     if (combo)
547       combo->setPlaceholderText(QString());
548     if (edit)
549       edit->setPlaceholderText(QString());
550     if (payee)
551       payee->setPlaceholderText(QString());
552     if (tag)
553       tag->tagCombo()->setPlaceholderText(QString());
554   }
555 
556   auto form = dynamic_cast<KMyMoneyTransactionForm::TransactionForm*>(d->m_form);
557   auto w = dynamic_cast<KMyMoneyTransactionForm::TabBar*>(editWidgets["tabbar"]);
558   if (w && form) {
559     // insert the tabbar in the boxlayout so it will take the place of the original tabbar which was hidden
560     if (auto boxLayout = dynamic_cast<QBoxLayout*>(form->getTabBar()->parentWidget()->layout()))
561       boxLayout->insertWidget(0, w);
562   }
563 }
564 
tabOrderInForm(QWidgetList & tabOrderWidgets) const565 void StdTransaction::tabOrderInForm(QWidgetList& tabOrderWidgets) const
566 {
567   Q_D(const StdTransaction);
568   QStringList taborder = KMyMoneySettings::stdTransactionFormTabOrder().split(',', QString::SkipEmptyParts);
569   QStringList::const_iterator it_s = taborder.constBegin();
570   QWidget* w;
571   while (it_s != taborder.constEnd()) {
572     if (*it_s == "account") {
573       tabOrderWidgets.append(focusWidget(d->m_form->cellWidget(0, (int)eTransactionForm::Column::Value1)));
574     } else if (*it_s == "cashflow") {
575       tabOrderWidgets.append(focusWidget(d->m_form->cellWidget(1, (int)eTransactionForm::Column::Label1)));
576     } else if (*it_s == "payee") {
577       tabOrderWidgets.append(focusWidget(d->m_form->cellWidget(1, (int)eTransactionForm::Column::Value1)));
578     } else if (*it_s == "category") {
579       // make sure to have the category field and the split button as separate tab order widgets
580       // ok, we have to have some internal knowledge about the KMyMoneyCategory object, but
581       // it's one of our own widgets, so we actually don't care. Just make sure, that we don't
582       // go haywire when someone changes the KMyMoneyCategory object ...
583       w = d->m_form->cellWidget(2, (int)eTransactionForm::Column::Value1);
584       tabOrderWidgets.append(focusWidget(w));
585       w = w->findChild<QPushButton*>("splitButton");
586       if (w)
587         tabOrderWidgets.append(w);
588     } else if (*it_s == "tag") {
589       tabOrderWidgets.append(focusWidget(d->m_form->cellWidget(3, (int)eTransactionForm::Column::Value1)));
590     } else if (*it_s == "memo") {
591       tabOrderWidgets.append(focusWidget(d->m_form->cellWidget(4, (int)eTransactionForm::Column::Value1)));
592     } else if (*it_s == "number") {
593       if (haveNumberField()) {
594         if ((w = focusWidget(d->m_form->cellWidget(1, (int)eTransactionForm::Column::Value2))))
595           tabOrderWidgets.append(w);
596       }
597     } else if (*it_s == "date") {
598       tabOrderWidgets.append(focusWidget(d->m_form->cellWidget(2, (int)eTransactionForm::Column::Value2)));
599     } else if (*it_s == "amount") {
600       tabOrderWidgets.append(focusWidget(d->m_form->cellWidget(3, (int)eTransactionForm::Column::Value2)));
601     } else if (*it_s == "state") {
602       tabOrderWidgets.append(focusWidget(d->m_form->cellWidget(5, (int)eTransactionForm::Column::Value2)));
603     }
604     ++it_s;
605   }
606 }
607 
arrangeWidgetsInRegister(QMap<QString,QWidget * > & editWidgets)608 void StdTransaction::arrangeWidgetsInRegister(QMap<QString, QWidget*>& editWidgets)
609 {
610   Q_D(StdTransaction);
611   if (!d->m_parent)
612     return;
613 
614   setupRegisterPalette(editWidgets);
615 
616   if (haveNumberField())
617     arrangeWidget(d->m_parent, d->m_startRow + 0, (int)eTransaction::Column::Number, editWidgets["number"]);
618   arrangeWidget(d->m_parent, d->m_startRow + 0, (int)eTransaction::Column::Date, editWidgets["postdate"]);
619   arrangeWidget(d->m_parent, d->m_startRow + 1, (int)eTransaction::Column::Date, editWidgets["status"]);
620   arrangeWidget(d->m_parent, d->m_startRow + 0, (int)eTransaction::Column::Detail, editWidgets["payee"]);
621   arrangeWidget(d->m_parent, d->m_startRow + 1, (int)eTransaction::Column::Detail, editWidgets["category"]->parentWidget());
622   arrangeWidget(d->m_parent, d->m_startRow + 2, (int)eTransaction::Column::Detail, editWidgets["tag"]);
623   arrangeWidget(d->m_parent, d->m_startRow + 3, (int)eTransaction::Column::Detail, editWidgets["memo"]);
624   arrangeWidget(d->m_parent, d->m_startRow + 0, (int)eTransaction::Column::Payment, editWidgets["payment"]);
625   arrangeWidget(d->m_parent, d->m_startRow + 0, (int)eTransaction::Column::Deposit, editWidgets["deposit"]);
626 
627   // increase the height of the row containing the memo widget
628   d->m_parent->setRowHeight(d->m_startRow + 3, d->m_parent->rowHeightHint() * 3);
629 }
630 
tabOrderInRegister(QWidgetList & tabOrderWidgets) const631 void StdTransaction::tabOrderInRegister(QWidgetList& tabOrderWidgets) const
632 {
633   Q_D(const StdTransaction);
634   QStringList taborder = KMyMoneySettings::stdTransactionRegisterTabOrder().split(',', QString::SkipEmptyParts);
635   QStringList::const_iterator it_s = taborder.constBegin();
636   QWidget* w;
637   while (it_s != taborder.constEnd()) {
638     if (*it_s == "number") {
639       if (haveNumberField()) {
640         if ((w = focusWidget(d->m_parent->cellWidget(d->m_startRow + 0, (int)eTransaction::Column::Number))))
641           tabOrderWidgets.append(w);
642       }
643     } else if (*it_s == "date") {
644       tabOrderWidgets.append(focusWidget(d->m_parent->cellWidget(d->m_startRow + 0, (int)eTransaction::Column::Date)));
645     } else if (*it_s == "payee") {
646       tabOrderWidgets.append(focusWidget(d->m_parent->cellWidget(d->m_startRow + 0, (int)eTransaction::Column::Detail)));
647     } else if (*it_s == "category") {
648       // make sure to have the category field and the split button as separate tab order widgets
649       // ok, we have to have some internal knowledge about the KMyMoneyCategory object, but
650       // it's one of our own widgets, so we actually don't care. Just make sure, that we don't
651       // go haywire when someone changes the KMyMoneyCategory object ...
652       w = d->m_parent->cellWidget(d->m_startRow + 1, (int)eTransaction::Column::Detail);
653       tabOrderWidgets.append(focusWidget(w));
654       w = w->findChild<QPushButton*>("splitButton");
655       if (w)
656         tabOrderWidgets.append(w);
657     } else if (*it_s == "tag") {
658       tabOrderWidgets.append(focusWidget(d->m_parent->cellWidget(d->m_startRow + 2, (int)eTransaction::Column::Detail)));
659     } else if (*it_s == "memo") {
660       tabOrderWidgets.append(focusWidget(d->m_parent->cellWidget(d->m_startRow + 3, (int)eTransaction::Column::Detail)));
661     } else if (*it_s == "payment") {
662       tabOrderWidgets.append(focusWidget(d->m_parent->cellWidget(d->m_startRow + 0, (int)eTransaction::Column::Payment)));
663     } else if (*it_s == "deposit") {
664       tabOrderWidgets.append(focusWidget(d->m_parent->cellWidget(d->m_startRow + 0, (int)eTransaction::Column::Deposit)));
665     } else if (*it_s == "state") {
666       tabOrderWidgets.append(focusWidget(d->m_parent->cellWidget(d->m_startRow + 1, (int)eTransaction::Column::Date)));
667     }
668     ++it_s;
669   }
670 }
671 
numRowsRegister(bool expanded) const672 int StdTransaction::numRowsRegister(bool expanded) const
673 {
674   Q_D(const StdTransaction);
675   int numRows = 1;
676   if (expanded) {
677     numRows = 4;
678     if (!d->m_inEdit) {
679       //When not in edit Tags haven't a separate row;
680       numRows--;
681       if (d->m_payee.isEmpty()) {
682         numRows--;
683       }
684       if (d->m_split.memo().isEmpty()) {
685         numRows--;
686       }
687       // For income and expense accounts that only have
688       // two splits we only show one line, because the
689       // account name is already contained in the account column.
690       if (d->m_account.accountType() == eMyMoney::Account::Type::Income
691           || d->m_account.accountType() == eMyMoney::Account::Type::Expense) {
692         if (numRows > 2 && d->m_transaction.splitCount() == 2)
693           numRows = 1;
694       }
695     }
696   }
697   return numRows;
698 }
699 
numRowsRegister() const700 int StdTransaction::numRowsRegister() const
701 {
702   return RegisterItem::numRowsRegister();
703 }
704 
createEditor(TransactionEditorContainer * regForm,const KMyMoneyRegister::SelectedTransactions & list,const QDate & lastPostDate)705 TransactionEditor* StdTransaction::createEditor(TransactionEditorContainer* regForm, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate)
706 {
707 #ifndef KMM_DESIGNER
708   Q_D(StdTransaction);
709   d->m_inRegisterEdit = regForm == d->m_parent;
710   return new StdTransactionEditor(regForm, this, list, lastPostDate);
711 #else
712   return NULL;
713 #endif
714 }
715