|
|
|
/***************************************************************************
|
|
|
|
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. *
|
|
|
|
* *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// 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 <kglobal.h>
|
|
|
|
#include <kconfig.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kmessagebox.h>
|
|
|
|
#include <kpushbutton.h>
|
|
|
|
#include <kactivelabel.h>
|
|
|
|
#include <kstdguiitem.h>
|
|
|
|
#include <kapplication.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
|
|
|
|
KIconLoader *il = KGlobal::iconLoader();
|
|
|
|
|
|
|
|
KGuiItem clearButtenItem( i18n( "Clear &All" ),
|
|
|
|
TQIconSet(il->loadIcon("edittrash", KIcon::Small, KIcon::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", KIcon::Small, KIcon::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(tqminimumSizeHint()) );
|
|
|
|
|
|
|
|
// 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.")
|
|
|
|
.tqarg(total)
|
|
|
|
.tqarg(sums)
|
|
|
|
.tqarg(diff);
|
|
|
|
corrDlg->explanation->setText(q);
|
|
|
|
|
|
|
|
q = i18n("Change &total amount of transaction to %1.").tqarg(sums);
|
|
|
|
corrDlg->changeBtn->setText(q);
|
|
|
|
|
|
|
|
q = i18n("&Distribute difference of %1 among all splits.").tqarg(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.").tqarg(total);
|
|
|
|
} else {
|
|
|
|
q = i18n("&Leave %1 unassigned.").tqarg(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
|
|
|
|
qDebug("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"
|