/*************************************************************************** * Copyright (C) 2006, 2007 by Niklas Knutsson * * nq@altern.org * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifdef HAVE_CONFIG_H # include #endif #include "editsplitdialog.h" #include "transactioneditwidget.h" #include "budget.h" #include #include #include #include #include #include #include "kdateedit.h" #include #include #include #include #include #include #include class SplitListViewItem : public KListViewItem { protected: Transaction *o_trans; public: SplitListViewItem(Transaction *trans, QListView *parent, QString, QString=QString::null, QString=QString::null, QString=QString::null, QString=QString::null, QString=QString::null, QString=QString::null, QString=QString::null); int compare(QListViewItem *i, int col, bool ascending) const; Transaction *transaction() const; }; SplitListViewItem::SplitListViewItem(Transaction *trans, QListView *parent, QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7, QString s8) : KListViewItem(parent, s1, s2, s3, s4, s5, s6, s7, s8), o_trans(trans) {} int SplitListViewItem::compare(QListViewItem *i, int col, bool ascending) const { return QListViewItem::compare(i, col, ascending); } Transaction *SplitListViewItem::transaction() const { return o_trans; } EditSplitDialog::EditSplitDialog(Budget *budg, QWidget *parent, AssetsAccount *default_account, bool extra_parameters) : KDialogBase(parent, 0, true, i18n("Split Transaction"), Ok | Cancel, Ok, true), budget(budg), b_extra(extra_parameters) { setMainWidget(new QWidget(this)); QVBoxLayout *box1 = new QVBoxLayout(mainWidget(), 0, spacingHint()); QGridLayout *grid = new QGridLayout(box1, 3, 2); grid->addWidget(new QLabel(i18n("Description:"), mainWidget()), 0, 0); descriptionEdit = new KLineEdit(mainWidget()); grid->addWidget(descriptionEdit, 0, 1); descriptionEdit->setFocus(); grid->addWidget(new QLabel(i18n("Date:"), mainWidget()), 1, 0); dateEdit = new KDateEdit(mainWidget()); grid->addWidget(dateEdit, 1, 1); grid->addWidget(new QLabel(i18n("Account:"), mainWidget()), 2, 0); accountCombo = new KComboBox(mainWidget()); accountCombo->setEditable(false); int i = 0; AssetsAccount *account = budget->assetsAccounts.first(); while(account) { if(account != budget->balancingAccount && account->accountType() != ASSETS_TYPE_SECURITIES) { accountCombo->insertItem(account->name()); if(account == default_account) accountCombo->setCurrentItem(i); i++; } account = budget->assetsAccounts.next(); } grid->addWidget(accountCombo, 2, 1); box1->addWidget(new QLabel(i18n("Transactions:"), mainWidget())); QHBoxLayout *box2 = new QHBoxLayout(box1); transactionsView = new KListView(mainWidget()); transactionsView->addColumn(i18n("Type")); transactionsView->addColumn(i18n("Description")); transactionsView->addColumn(i18n("Account/Category")); transactionsView->addColumn(i18n("Payment")); transactionsView->addColumn(i18n("Deposit")); transactionsView->setRootIsDecorated(false); transactionsView->setAllColumnsShowFocus(true); transactionsView->setSorting(0); transactionsView->setColumnAlignment(3, Qt::AlignRight); transactionsView->setColumnAlignment(4, Qt::AlignRight); box2->addWidget(transactionsView); KButtonBox *buttons = new KButtonBox(mainWidget(), KButtonBox::Vertical); QPushButton *newButton = buttons->addButton(i18n("New")); QPopupMenu *newMenu = new QPopupMenu(this); newButton->setPopup(newMenu); newMenu->insertItem(kapp->iconLoader()->loadIconSet("filenew", KIcon::Small), i18n("New Expense..."), this, SLOT(newExpense())); newMenu->insertItem(kapp->iconLoader()->loadIconSet("filenew", KIcon::Small), i18n("New Income..."), this, SLOT(newIncome())); newMenu->insertItem(kapp->iconLoader()->loadIconSet("filenew", KIcon::Small), i18n("New Deposit..."), this, SLOT(newTransferTo())); newMenu->insertItem(kapp->iconLoader()->loadIconSet("filenew", KIcon::Small), i18n("New Withdrawal..."), this, SLOT(newTransferFrom())); newMenu->insertItem(kapp->iconLoader()->loadIconSet("filenew", KIcon::Small), i18n("Security Shares Bought..."), this, SLOT(newSecurityBuy())); newMenu->insertItem(kapp->iconLoader()->loadIconSet("filenew", KIcon::Small), i18n("Security Shares Sold..."), this, SLOT(newSecuritySell())); newMenu->insertItem(kapp->iconLoader()->loadIconSet("filenew", KIcon::Small), i18n("New Dividend..."), this, SLOT(newDividend())); editButton = buttons->addButton(i18n("Edit...")); editButton->setEnabled(false); #if KDE_VERSION_MAJOR > 3 || KDE_VERSION_MINOR >= 3 removeButton = buttons->addButton(KStdGuiItem::guiItem(KStdGuiItem::Delete)); #else removeButton = buttons->addButton(i18n("Delete")); #endif removeButton->setEnabled(false); box2->addWidget(buttons); buttons->addStretch(); buttons->layout(); totalLabel = new QLabel(mainWidget()); updateTotalValue(); box1->addWidget(totalLabel); connect(transactionsView, SIGNAL(selectionChanged()), this, SLOT(transactionSelectionChanged())); connect(transactionsView, SIGNAL(doubleClicked(QListViewItem*, const QPoint&, int)), this, SLOT(edit(QListViewItem*))); connect(removeButton, SIGNAL(clicked()), this, SLOT(remove())); connect(editButton, SIGNAL(clicked()), this, SLOT(edit())); } EditSplitDialog::~EditSplitDialog() {} void EditSplitDialog::updateTotalValue() { double total_value = 0.0; QListViewItem *i = transactionsView->firstChild(); while(i) { Transaction *trans = ((SplitListViewItem*) i)->transaction(); if(trans) { if(trans->fromAccount()) total_value += trans->value(); else total_value -= trans->value(); } i = i->nextSibling(); } totalLabel->setText(QString("
%1 %2
").arg(i18n("Total value:")).arg(KGlobal::locale()->formatMoney(total_value))); } AssetsAccount *EditSplitDialog::selectedAccount() { int index = 0; int cur_index = accountCombo->currentItem(); AssetsAccount *account = budget->assetsAccounts.first(); while(account) { if(account != budget->balancingAccount && account->accountType() != ASSETS_TYPE_SECURITIES) { if(index == cur_index) { break; } index++; } account = budget->assetsAccounts.next(); } return account; } void EditSplitDialog::transactionSelectionChanged() { SplitListViewItem *i = (SplitListViewItem*) transactionsView->selectedItem(); editButton->setEnabled(i && i->transaction()); removeButton->setEnabled(i && i->transaction()); } void EditSplitDialog::newTransaction(int transtype, bool select_security, bool transfer_to, Account *exclude_account) { TransactionEditDialog *dialog = new TransactionEditDialog(b_extra, transtype, true, transfer_to, NULL, SECURITY_ALL_VALUES, select_security, budget, this); dialog->editWidget->updateAccounts(exclude_account); if(dialog->editWidget->checkAccounts() && dialog->exec() == QDialog::Accepted) { Transaction *trans = dialog->editWidget->createTransaction(); if(trans) { appendTransaction(trans, (trans->toAccount() == NULL)); } updateTotalValue(); } dialog->deleteLater(); } void EditSplitDialog::newExpense() { newTransaction(TRANSACTION_TYPE_EXPENSE); } void EditSplitDialog::newDividend() { newTransaction(TRANSACTION_TYPE_INCOME, true); } void EditSplitDialog::newSecurityBuy() { newTransaction(TRANSACTION_TYPE_SECURITY_BUY, true); } void EditSplitDialog::newSecuritySell() { newTransaction(TRANSACTION_TYPE_SECURITY_SELL, true); } void EditSplitDialog::newIncome() { newTransaction(TRANSACTION_TYPE_INCOME); } void EditSplitDialog::newTransferFrom() { newTransaction(TRANSACTION_TYPE_TRANSFER, false, false, selectedAccount()); } void EditSplitDialog::newTransferTo() { newTransaction(TRANSACTION_TYPE_TRANSFER, false, true, selectedAccount()); } void EditSplitDialog::remove() { SplitListViewItem *i = (SplitListViewItem*) transactionsView->selectedItem(); if(i == NULL) return; if(i->transaction()) { delete i->transaction(); } delete i; updateTotalValue(); } void EditSplitDialog::edit() { edit(transactionsView->selectedItem()); } void EditSplitDialog::edit(QListViewItem *i_pre) { if(i_pre == NULL) return; SplitListViewItem *i = (SplitListViewItem*) i_pre; Transaction *trans = i->transaction(); if(trans) { AssetsAccount *account = selectedAccount(); Security *security = NULL; if(trans->type() == TRANSACTION_TYPE_SECURITY_BUY || trans->type() == TRANSACTION_TYPE_SECURITY_SELL) { security = ((SecurityTransaction*) trans)->security(); } else if(trans->type() == TRANSACTION_TYPE_INCOME && ((Income*) trans)->security()) { security = ((Income*) trans)->security(); } TransactionEditDialog *dialog = new TransactionEditDialog(b_extra, trans->type(), true, trans->toAccount() == NULL, security, SECURITY_ALL_VALUES, security != NULL, budget, this); dialog->editWidget->updateAccounts(account); dialog->editWidget->setTransaction(trans); if(dialog->exec() == QDialog::Accepted) { if(dialog->editWidget->modifyTransaction(trans)) { double value = trans->value(); bool deposit = (trans->toAccount() == NULL); i->setText(1, trans->description()); i->setText(2, deposit ? trans->fromAccount()->name() : trans->toAccount()->name()); i->setText(3, (deposit && value >= 0.0) ? QString::null : KGlobal::locale()->formatMoney(value < 0.0 ? -value : value)); i->setText(4, (deposit && value >= 0.0) ? KGlobal::locale()->formatMoney(value < 0.0 ? -value : value) : QString::null); if(trans->type() == TRANSACTION_TYPE_INCOME) { if(((Income*) trans)->security()) i->setText(0, i18n("Dividend")); else if(value >= 0) i->setText(0, i18n("Income")); else i->setText(0, i18n("Repayment")); } else if(trans->type() == TRANSACTION_TYPE_EXPENSE) { if(value >= 0) i->setText(0, i18n("Expense")); else i->setText(0, i18n("Refund")); } else if(trans->type() == TRANSACTION_TYPE_SECURITY_BUY) { i->setText(0, i18n("Security Buy")); } else if(trans->type() == TRANSACTION_TYPE_SECURITY_SELL) { i->setText(0, i18n("Security Sell")); } else if(trans->toAccount() == budget->balancingAccount || trans->fromAccount() == budget->balancingAccount) { i->setText(0, i18n("Balancing")); } else { i->setText(0, i18n("Transfer")); } } updateTotalValue(); } dialog->deleteLater(); } } SplitTransaction *EditSplitDialog::createSplitTransaction() { if(!validValues()) return NULL; AssetsAccount *account = selectedAccount(); SplitTransaction *split = new SplitTransaction(budget, dateEdit->date(), account, descriptionEdit->text()); QListViewItem *i = transactionsView->firstChild(); while(i) { Transaction *trans = ((SplitListViewItem*) i)->transaction(); if(trans) split->addTransaction(trans); i = i->nextSibling(); } return split; } void EditSplitDialog::setSplitTransaction(SplitTransaction *split) { descriptionEdit->setText(split->description()); dateEdit->setDate(split->date()); int index = 0; AssetsAccount *account = budget->assetsAccounts.first(); while(account) { if(account != budget->balancingAccount && account->accountType() != ASSETS_TYPE_SECURITIES) { if(account == split->account()) { accountCombo->setCurrentItem(index); break; } index++; } account = budget->assetsAccounts.next(); } transactionsView->clear(); QValueVector::size_type c = split->splits.count(); for(QValueVector::size_type i = 0; i < c; i++) { Transaction *trans = split->splits[i]->copy(); trans->setDate(QDate()); appendTransaction(trans, (trans->toAccount() == split->account())); switch(trans->type()) { case TRANSACTION_TYPE_EXPENSE: { ((Expense*) trans)->setFrom(NULL); break; } case TRANSACTION_TYPE_INCOME: { ((Income*) trans)->setTo(NULL); break; } case TRANSACTION_TYPE_TRANSFER: { if(((Transfer*) trans)->from() == split->account()) { ((Transfer*) trans)->setFrom(NULL); } else { ((Transfer*) trans)->setTo(NULL); } break; } case TRANSACTION_TYPE_SECURITY_BUY: {} case TRANSACTION_TYPE_SECURITY_SELL: { ((SecurityTransaction*) trans)->setAccount(NULL); break; } } } updateTotalValue(); } void EditSplitDialog::appendTransaction(Transaction *trans, bool deposit) { double value = trans->value(); SplitListViewItem *i = new SplitListViewItem(trans, transactionsView, QString::null, trans->description(), deposit ? trans->fromAccount()->name() : trans->toAccount()->name(), (deposit && value >= 0.0) ? QString::null : KGlobal::locale()->formatMoney(value < 0.0 ? -value : value), (deposit && value >= 0.0) ? KGlobal::locale()->formatMoney(value < 0.0 ? -value : value) : QString::null); if(trans->type() == TRANSACTION_TYPE_INCOME) { if(((Income*) trans)->security()) i->setText(0, i18n("Dividend")); else if(value >= 0) i->setText(0, i18n("Income")); else i->setText(0, i18n("Repayment")); } else if(trans->type() == TRANSACTION_TYPE_EXPENSE) { if(value >= 0) i->setText(0, i18n("Expense")); else i->setText(0, i18n("Refund")); } else if(trans->type() == TRANSACTION_TYPE_SECURITY_BUY) { i->setText(0, i18n("Security Buy")); } else if(trans->type() == TRANSACTION_TYPE_SECURITY_SELL) { i->setText(0, i18n("Security Sell")); } else if(trans->toAccount() == budget->balancingAccount || trans->fromAccount() == budget->balancingAccount) { i->setText(0, i18n("Balancing")); } else { i->setText(0, i18n("Transfer")); } } void EditSplitDialog::slotOk() { if(validValues()) { KDialogBase::slotOk(); } } void EditSplitDialog::slotCancel() { QListViewItem *i = transactionsView->firstChild(); while(i) { Transaction *trans = ((SplitListViewItem*) i)->transaction(); if(trans) delete trans; i = i->nextSibling(); } KDialogBase::slotCancel(); } bool EditSplitDialog::checkAccounts() { if(accountCombo->count() == 0) { KMessageBox::error(this, i18n("No suitable account available.")); return false; } return true; } bool EditSplitDialog::validValues() { if(!checkAccounts()) return false; if(!dateEdit->date().isValid()) { KMessageBox::error(this, i18n("Invalid date.")); return false; } if(dateEdit->date() > QDate::currentDate()) { KMessageBox::error(this, i18n("Future dates is not allowed.")); return false; } if(transactionsView->childCount() < 2) { KMessageBox::error(this, i18n("A split must contain at least two transactions.")); return false; } AssetsAccount *account = selectedAccount(); QListViewItem *i = transactionsView->firstChild(); while(i) { Transaction *trans = ((SplitListViewItem*) i)->transaction(); if(trans && (trans->fromAccount() == account || trans->toAccount() == account)) { KMessageBox::error(this, i18n("Cannot transfer money to and from the same account.")); return false; } i = i->nextSibling(); } return true; } #include "editsplitdialog.moc"