You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kmymoney/kmymoney2/dialogs/ksplittransactiondlg.cpp

454 lines
15 KiB

/***************************************************************************
ksplittransactiondlg.cpp - description
-------------------
begin : Thu Jan 10 2002
copyright : (C) 2000-2002 by Michael Edwardes
email : mte@users.sourceforge.net
Javier Campos Morales <javi_c@users.sourceforge.net>
Felix Rodriguez <frodriguez@users.sourceforge.net>
John C <thetacoturtle@users.sourceforge.net>
Thomas Baumgart <ipwizard@users.sourceforge.net>
Kevin Tambascio <ktambascio@users.sourceforge.net>
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
// ----------------------------------------------------------------------------
// QT Includes
#include <tqpushbutton.h>
#include <tqlabel.h>
#include <tqtable.h>
#include <tqtimer.h>
#include <tqptrlist.h>
#include <tqbuttongroup.h>
#include <tqradiobutton.h>
#include <tqcursor.h>
// ----------------------------------------------------------------------------
// KDE Includes
#include <tdeglobal.h>
#include <tdeconfig.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <kpushbutton.h>
#include <kactivelabel.h>
#include <kstdguiitem.h>
#include <tdeapplication.h>
// ----------------------------------------------------------------------------
// Project Includes
#include "ksplittransactiondlg.h"
#include <kmymoney/kmymoneyedit.h>
#include <kmymoney/kmymoneylineedit.h>
#include <kmymoney/mymoneyfile.h>
#include "kmymoneysplittable.h"
#include "../dialogs/ksplitcorrectiondlg.h"
KSplitTransactionDlg::KSplitTransactionDlg(const MyMoneyTransaction& t,
const MyMoneySplit& s,
const MyMoneyAccount& acc,
const bool amountValid,
const bool deposit,
const MyMoneyMoney& calculatedValue,
const TQMap<TQString, MyMoneyMoney>& priceInfo,
TQWidget* parent, const char* name) :
KSplitTransactionDlgDecl(parent, name, true),
m_account(acc),
m_split(s),
m_precision(2),
m_amountValid(amountValid),
m_isDeposit(deposit),
m_calculatedValue(calculatedValue)
{
// add icons to buttons
TDEIconLoader *il = TDEGlobal::iconLoader();
KGuiItem clearButtenItem( i18n( "Clear &All" ),
TQIconSet(il->loadIcon("edittrash", TDEIcon::Small, TDEIcon::SizeSmall)),
i18n("Clear all splits"),
i18n("Use this to clear all splits of this transaction"));
clearAllBtn->setGuiItem(clearButtenItem);
KGuiItem mergeButtenItem( i18n( "&Merge" ),
TQIconSet(il->loadIcon("math_sum", TDEIcon::Small, TDEIcon::SizeSmall)),
"", "");
mergeBtn->setGuiItem(mergeButtenItem);
// make finish the default
finishBtn->setDefault(true);
// setup the focus
cancelBtn->setFocusPolicy(TQ_NoFocus);
finishBtn->setFocusPolicy(TQ_NoFocus);
clearAllBtn->setFocusPolicy(TQ_NoFocus);
// connect signals with slots
connect(transactionsTable, TQT_SIGNAL(transactionChanged(const MyMoneyTransaction&)),
this, TQT_SLOT(slotSetTransaction(const MyMoneyTransaction&)));
connect(transactionsTable, TQT_SIGNAL(createCategory(const TQString&, TQString&)), this, TQT_SLOT(slotCreateCategory(const TQString&, TQString&)));
connect(transactionsTable, TQT_SIGNAL(objectCreation(bool)), this, TQT_SIGNAL(objectCreation(bool)));
connect(transactionsTable, TQT_SIGNAL(returnPressed()), this, TQT_SLOT(accept()));
connect(transactionsTable, TQT_SIGNAL(escapePressed()), this, TQT_SLOT(reject()));
connect(cancelBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(reject()));
connect(finishBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(accept()));
connect(clearAllBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotClearAllSplits()));
connect(mergeBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotMergeSplits()));
connect(clearZeroBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotClearUnusedSplits()));
// setup the precision
try {
MyMoneySecurity currency = MyMoneyFile::instance()->currency(t.commodity());
m_precision = MyMoneyMoney::denomToPrec(m_account.fraction(currency));
} catch(MyMoneyException *e) {
delete e;
}
slotSetTransaction(t);
// pass on those vars
transactionsTable->setup(priceInfo);
TQSize size(width(), height());
kapp->config()->setGroup("SplitTransactionEditor");
size = kapp->config()->readSizeEntry("Geometry", &size);
size.setHeight(size.height()-1);
TQDialog::resize( size.expandedTo(minimumSizeHint()) );
// Trick: it seems, that the initial sizing of the dialog does
// not work correctly. At least, the columns do not get displayed
// correct. Reason: the return value of transactionsTable->visibleWidth()
// is incorrect. If the widget is visible, resizing works correctly.
// So, we let the dialog show up and resize it then. It's not really
// clean, but the only way I got the damned thing working.
TQTimer::singleShot( 10, this, TQT_SLOT(initSize()) );
}
KSplitTransactionDlg::~KSplitTransactionDlg()
{
kapp->config()->setGroup("SplitTransactionEditor");
kapp->config()->writeEntry("Geometry", size());
}
int KSplitTransactionDlg::exec(void)
{
// for deposits, we invert the sign of all splits.
// don't forget to revert when we're done ;-)
if(m_isDeposit) {
for(unsigned i = 0; i < m_transaction.splits().count(); ++i) {
MyMoneySplit split = m_transaction.splits()[i];
split.setValue(-split.value());
split.setShares(-split.shares());
m_transaction.modifySplit(split);
}
}
int rc;
do {
transactionsTable->setFocus();
// initialize the display
transactionsTable->setTransaction(m_transaction, m_split, m_account);
updateSums();
rc = KSplitTransactionDlgDecl::exec();
if(rc == TQDialog::Accepted) {
if(!diffAmount().isZero()) {
KSplitCorrectionDlgDecl* corrDlg = new KSplitCorrectionDlgDecl(this, 0, true);
// add icons to buttons
corrDlg->okBtn->setGuiItem(KStdGuiItem::ok());
corrDlg->cancelBtn->setGuiItem(KStdGuiItem::cancel());
MyMoneySplit split = m_transaction.splits()[0];
TQString total = (-split.value()).formatMoney("", m_precision);
TQString sums = splitsValue().formatMoney("", m_precision);
TQString diff = diffAmount().formatMoney("", m_precision);
// now modify the text items of the dialog to contain the correct values
TQString q = i18n("The total amount of this transaction is %1 while "
"the sum of the splits is %2. The remaining %3 are "
"unassigned.")
.arg(total)
.arg(sums)
.arg(diff);
corrDlg->explanation->setText(q);
q = i18n("Change &total amount of transaction to %1.").arg(sums);
corrDlg->changeBtn->setText(q);
q = i18n("&Distribute difference of %1 among all splits.").arg(diff);
corrDlg->distributeBtn->setText(q);
// FIXME remove the following line once distribution among
// all splits is implemented
corrDlg->distributeBtn->hide();
// if we have only two splits left, we don't allow leaving sth. unassigned.
if(m_transaction.splitCount() < 3) {
q = i18n("&Leave total amount of transaction at %1.").arg(total);
} else {
q = i18n("&Leave %1 unassigned.").arg(diff);
}
corrDlg->leaveBtn->setText(q);
if((rc = corrDlg->exec()) == TQDialog::Accepted) {
TQButton* button = corrDlg->buttonGroup->selected();
if(button != 0) {
switch(corrDlg->buttonGroup->id(button)) {
case 0: // continue to edit
rc = TQDialog::Rejected;
break;
case 1: // modify total
split.setValue(-splitsValue());
split.setShares(-splitsValue());
m_transaction.modifySplit(split);
break;
case 2: // distribute difference
tqDebug("distribution of difference not yet supported in KSplitTransactionDlg::slotFinishClicked()");
break;
case 3: // leave unassigned
break;
}
}
}
delete corrDlg;
}
} else
break;
} while(rc != TQDialog::Accepted);
// for deposits, we inverted the sign of all splits.
// now we revert it back, so that things are left correct
if(m_isDeposit) {
for(unsigned i = 0; i < m_transaction.splits().count(); ++i) {
MyMoneySplit split = m_transaction.splits()[i];
split.setValue(-split.value());
split.setShares(-split.shares());
m_transaction.modifySplit(split);
}
}
return rc;
}
void KSplitTransactionDlg::initSize(void)
{
TQDialog::resize(width(), height()+1);
}
void KSplitTransactionDlg::accept()
{
transactionsTable->slotCancelEdit();
KSplitTransactionDlgDecl::accept();
}
void KSplitTransactionDlg::reject()
{
// cancel any edit activity in the split register
transactionsTable->slotCancelEdit();
KSplitTransactionDlgDecl::reject();
}
void KSplitTransactionDlg::slotClearAllSplits(void)
{
transactionsTable->slotEndEdit();
int answer;
answer = KMessageBox::warningContinueCancel (this,
i18n("You are about to delete all splits of this transaction. "
"Do you really want to continue?"),
i18n("KMyMoney"),
i18n("Continue")
);
if(answer == KMessageBox::Continue) {
transactionsTable->slotCancelEdit();
TQValueList<MyMoneySplit> list = transactionsTable->getSplits(m_transaction);
TQValueList<MyMoneySplit>::ConstIterator it;
// clear all but the one referencing the account
for(it = list.begin(); it != list.end(); ++it) {
m_transaction.removeSplit(*it);
}
transactionsTable->setTransaction(m_transaction, m_split, m_account);
slotSetTransaction(m_transaction);
}
}
void KSplitTransactionDlg::slotClearUnusedSplits(void)
{
transactionsTable->slotEndEdit();
TQValueList<MyMoneySplit> list = transactionsTable->getSplits(m_transaction);
TQValueList<MyMoneySplit>::ConstIterator it;
try {
// remove all splits that don't have a value assigned
for(it = list.begin(); it != list.end(); ++it) {
if((*it).shares().isZero()) {
m_transaction.removeSplit(*it);
}
}
transactionsTable->setTransaction(m_transaction, m_split, m_account);
slotSetTransaction(m_transaction);
} catch(MyMoneyException* e) {
delete e;
}
}
void KSplitTransactionDlg::slotMergeSplits(void)
{
transactionsTable->slotEndEdit();
TQValueList<MyMoneySplit> list = transactionsTable->getSplits(m_transaction);
TQValueList<MyMoneySplit>::ConstIterator it;
try {
// collect all splits, merge them if needed and remove from transaction
TQValueList<MyMoneySplit> splits;
for(it = list.begin(); it != list.end(); ++it) {
TQValueList<MyMoneySplit>::iterator it_s;
for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
if((*it_s).accountId() == (*it).accountId()
&& (*it_s).memo().isEmpty() && (*it).memo().isEmpty())
break;
}
if(it_s != splits.end()) {
(*it_s).setShares((*it).shares() + (*it_s).shares());
(*it_s).setValue((*it).value() + (*it_s).value());
} else {
splits << *it;
}
m_transaction.removeSplit(*it);
}
// now add them back to the transaction
TQValueList<MyMoneySplit>::iterator it_s;
for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
(*it_s).clearId();
m_transaction.addSplit(*it_s);
}
transactionsTable->setTransaction(m_transaction, m_split, m_account);
slotSetTransaction(m_transaction);
} catch(MyMoneyException* e) {
delete e;
}
}
void KSplitTransactionDlg::slotSetTransaction(const MyMoneyTransaction& t)
{
transactionsTable->slotCancelEdit();
m_transaction = t;
TQValueList<MyMoneySplit> list = transactionsTable->getSplits(m_transaction);
TQValueList<MyMoneySplit>::ConstIterator it;
// check if we can merge splits or not, have zero splits or not
TQMap<TQString, int> splits;
bool haveZeroSplit = false;
for(it = list.begin(); it != list.end(); ++it) {
splits[(*it).accountId()]++;
if(((*it).id() != m_split.id()) && ((*it).shares().isZero()))
haveZeroSplit = true;
}
TQMap<TQString, int>::const_iterator it_s;
for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
if((*it_s) > 1)
break;
}
mergeBtn->setDisabled(it_s == splits.end());
clearZeroBtn->setEnabled(haveZeroSplit);
updateSums();
}
void KSplitTransactionDlg::updateSums(void)
{
MyMoneyMoney splits(splitsValue());
if(m_amountValid == false) {
m_split.setValue(-splits);
m_transaction.modifySplit(m_split);
}
splitSum->setText("<b>" + splits.formatMoney("", m_precision) + " ");
splitUnassigned->setText("<b>" + diffAmount().formatMoney("", m_precision) + " ");
transactionAmount->setText("<b>" + (-m_split.value()).formatMoney("", m_precision) + " ");
}
MyMoneyMoney KSplitTransactionDlg::splitsValue(void)
{
MyMoneyMoney splitsValue(m_calculatedValue);
TQValueList<MyMoneySplit> list = transactionsTable->getSplits(m_transaction);
TQValueList<MyMoneySplit>::ConstIterator it;
// calculate the current sum of all split parts
for(it = list.begin(); it != list.end(); ++it) {
if((*it).value() != MyMoneyMoney::autoCalc)
splitsValue += (*it).value();
}
return splitsValue;
}
MyMoneyMoney KSplitTransactionDlg::diffAmount(void)
{
MyMoneyMoney diff(0);
// if there is an amount specified in the transaction, we need to calculate the
// difference, otherwise we display the difference as 0 and display the same sum.
if(m_amountValid) {
MyMoneySplit split = m_transaction.splits()[0];
diff = -(splitsValue() + split.value());
}
return diff;
}
void KSplitTransactionDlg::slotCreateCategory(const TQString& name, TQString& id)
{
MyMoneyAccount acc, parent;
acc.setName(name);
if(m_isDeposit)
parent = MyMoneyFile::instance()->income();
else
parent = MyMoneyFile::instance()->expense();
// TODO extract possible first part of a hierarchy and check if it is one
// of our top categories. If so, remove it and select the parent
// according to this information.
emit createCategory(acc, parent);
// return id
id = acc.id();
}
#include "ksplittransactiondlg.moc"