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/views/kpayeesview.cpp

1109 lines
36 KiB

/***************************************************************************
kpayeesview.cpp
---------------
begin : Thu Jan 24 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>
Andreas Nicolai <Andreas.Nicolai@gmx.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 <tqcombobox.h>
#include <tqlineedit.h>
#include <tqlabel.h>
#include <tqlayout.h>
#include <tqmultilineedit.h>
#include <tqpixmap.h>
#include <tqtabwidget.h>
#include <tqcursor.h>
#include <tqcheckbox.h>
#include <tqradiobutton.h>
#include <tqpainter.h>
#include <tqheader.h>
#include <tqbuttongroup.h>
#include <tqsplitter.h>
#include <tqmap.h>
// ----------------------------------------------------------------------------
// KDE Includes
#include <kglobal.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kpushbutton.h>
#include <kiconloader.h>
#include <kguiitem.h>
#include <kstandarddirs.h>
#include <kdebug.h>
#include <kapplication.h>
#include <keditlistbox.h>
// ----------------------------------------------------------------------------
// Project Includes
#include <kmymoney/mymoneyfile.h>
#include <kmymoney/kmymoneyaccounttree.h>
#include <kmymoney/kmymoneyglobalsettings.h>
#include "../widgets/klistviewsearchline.h"
#include "kpayeesview.h"
/* -------------------------------------------------------------------------------*/
/* KTransactionPtrVector */
/* -------------------------------------------------------------------------------*/
int KTransactionPtrVector::compareItems(const TQString& s1, const TQString& s2) const
{
if(s1 == s2)
return 0;
if(s1 < s2)
return -1;
return 1;
}
int KTransactionPtrVector::compareItems(KTransactionPtrVector::Item d1, KTransactionPtrVector::Item d2)
{
int rc = 0;
MyMoneyTransaction* t1 = static_cast<MyMoneyTransaction*>(d1);
MyMoneyTransaction* t2 = static_cast<MyMoneyTransaction*>(d2);
MyMoneyMoney tmp;
try {
MyMoneySplit s1;
MyMoneySplit s2;
switch(m_idMode) {
case AccountMode:
s1 = t1->splitByAccount(m_id);
s2 = t2->splitByAccount(m_id);
break;
case PayeeMode:
s1 = t1->splitByPayee(m_id);
s2 = t2->splitByPayee(m_id);
break;
}
TQString p1, p2;
switch(m_sortType) {
case SortValue:
rc = 1;
tmp = s2.value() - s1.value();
if(tmp.isZero()) {
// same value? Sort by date
rc = t2->postDate().daysTo(t1->postDate());
if(rc == 0) {
// same date? Sort by id
rc = compareItems(t1->id(), t2->id());
}
} else if(tmp.isNegative()) {
rc = -1;
}
break;
case SortEntryDate:
rc = t2->entryDate().daysTo(t1->entryDate());
if(rc == 0) {
// on same day, lower check numbers show up first
rc = compareItems(s1.number(), s2.number());
if(rc == 0) {
// same number (e.g. empty)? larger amounts show up first
rc = 1;
tmp = s2.value() - s1.value();
if(tmp.isZero()) {
// same value? Sort by id
rc = compareItems(t1->id(), t2->id());
} else if(tmp.isNegative()) {
rc = -1;
}
}
}
break;
case SortEntryOrder:
// sort by id
rc = compareItems(t1->id(), t2->id());
break;
case SortTypeNr:
rc = compareItems(s1.action(), s2.action());
if(rc == 0) {
// same action? Sort by nr
rc = compareItems(s1.number(), s2.number());
if(rc == 0) {
// same number? Sort by date
rc = t2->postDate().daysTo(t1->postDate());
if(rc == 0) {
// same date? Sort by value
rc = 1;
tmp = s2.value() - s1.value();
if(tmp.isZero()) {
// same value? sort by id
rc = compareItems(t1->id(), t2->id());
} else if(tmp.isNegative()) {
rc = -1;
}
}
}
}
break;
case SortReceiver:
if(!s2.payeeId().isEmpty()) {
p2 = MyMoneyFile::instance()->payee(s2.payeeId()).name();
}
if(!s1.payeeId().isEmpty()) {
p1 = MyMoneyFile::instance()->payee(s1.payeeId()).name();
}
rc = compareItems(p1, p2);
if(rc == 0) {
// same payee? Sort by date
rc = t2->postDate().daysTo(t1->postDate());
if(rc == 0) {
// same date? Sort by value
rc = 1;
tmp = s2.value() - s1.value();
if(tmp.isZero()) {
// same value? sort by id
rc = compareItems(t1->id(), t2->id());
} else if(tmp.isNegative()) {
rc = -1;
}
}
}
break;
case SortNr:
rc = compareItems(s1.number(), s2.number());
if(rc == 0) {
// same number? Sort by date
rc = t2->postDate().daysTo(t1->postDate());
if(rc == 0) {
// same date? Sort by value
rc = 1;
tmp = s2.value() - s1.value();
if(tmp.isZero()) {
// same value? sort by id
rc = compareItems(t1->id(), t2->id());
} else if(tmp.isNegative()) {
rc = -1;
}
}
}
break;
case SortPostDate:
// tricky fall through here!
default:
// sort by post date
rc = t2->postDate().daysTo(t1->postDate());
if(rc == 0) {
// on same day, lower check numbers show up first
rc = compareItems(s1.number(), s2.number());
if(rc == 0) {
// same number (e.g. empty)? larger amounts show up first
rc = 1;
tmp = s2.value() - s1.value();
if(tmp.isZero()) {
// same value? Sort by id
rc = compareItems(t1->id(), t2->id());
} else if(tmp.isNegative()) {
rc = -1;
}
}
}
break;
}
} catch (MyMoneyException *e) {
delete e;
}
return rc;
}
void KTransactionPtrVector::setSortType(const TransactionSortE type)
{
m_sortType = type;
sort();
}
void KTransactionPtrVector::setAccountId(const TQString& id)
{
m_id = id;
m_idMode = AccountMode;
}
void KTransactionPtrVector::setPayeeId(const TQString& id)
{
m_id = id;
m_idMode = PayeeMode;
}
// *** KPayeeListItem Implementation ***
KPayeeListItem::KPayeeListItem(KListView *parent, const MyMoneyPayee& payee) :
KListViewItem(parent),
m_payee(payee)
{
setText(0, payee.name());
// allow in column rename
setRenameEnabled(0, true);
}
KPayeeListItem::~KPayeeListItem()
{
}
void KPayeeListItem::paintCell(TQPainter *p, const TQColorGroup & cg, int column, int width, int align)
{
TQColorGroup cg2(cg);
if(isAlternate())
cg2.setColor(TQColorGroup::Base, KMyMoneyGlobalSettings::listColor());
else
cg2.setColor(TQColorGroup::Base, KMyMoneyGlobalSettings::listBGColor());
p->setFont(KMyMoneyGlobalSettings::listCellFont());
TQListViewItem::paintCell(p, cg2, column, width, align);
}
KTransactionListItem::KTransactionListItem(KListView* view, KTransactionListItem* parent, const TQString& accountId, const TQString& transactionId) :
KListViewItem(view, parent)
{
m_accountId = accountId;
m_transactionId = transactionId;
}
KTransactionListItem::~KTransactionListItem()
{
}
void KTransactionListItem::paintCell(TQPainter *p, const TQColorGroup &cg, int column, int width, int alignment)
{
TQColorGroup _cg = cg;
_cg.setColor(TQColorGroup::Base, backgroundColor());
TQListViewItem::paintCell(p, _cg, column, width, alignment);
}
const TQColor KTransactionListItem::backgroundColor(void)
{
return isAlternate() ? KMyMoneyGlobalSettings::listBGColor() : KMyMoneyGlobalSettings::listColor();
}
// *** KPayeesView Implementation ***
KPayeesView::KPayeesView(TQWidget *parent, const char *name ) :
KPayeesViewDecl(parent,name),
m_needReload(false),
m_needConnection(true),
m_updatesQueued(0),
m_inSelection(false)
{
// create the searchline widget
// and insert it into the existing layout
m_searchWidget = new KListViewSearchLineWidget(m_payeesList, this);
m_searchWidget->setSizePolicy(TQSizePolicy(TQSizePolicy::Preferred, TQSizePolicy::Fixed));
KPayeesViewDeclLayout->insertWidget(0, m_searchWidget);
m_splitter = new TQSplitter(this);
m_payeesList->reparent(m_splitter, TQPoint(0,0), true);
m_tabWidget->reparent(m_splitter, TQPoint(0, 0), true);
m_splitter->setResizeMode(m_tabWidget, TQSplitter::Stretch);
m_splitter->setOpaqueResize();
layout10->addWidget(m_splitter);
// use the size settings of the last run (if any)
KConfig *config = KGlobal::config();
config->setGroup("Last Use Settings");
TQValueList<int> sizes = config->readIntListEntry("KPayeesViewSplitterSize");
if(sizes.size() == 2) {
if(!sizes[0] || !sizes[1]) {
sizes[0] = 1;
sizes[1] = 2;
}
m_splitter->setSizes(sizes);
}
m_transactionView->setSorting(-1);
m_transactionView->setColumnWidthMode(2, TQListView::Manual);
m_transactionView->setColumnAlignment(3, TQt::AlignRight);
// never show horizontal scroll bars
m_transactionView->setHScrollBarMode(TQScrollView::AlwaysOff);
m_payeesList->addColumn(i18n("Name"));
m_updateButton->setEnabled(false);
radioNoMatch->setChecked(true);
checkMatchIgnoreCase->setEnabled(false);
checkEnableDefaultAccount->setChecked(false);
labelDefaultAccount->setEnabled(false);
comboDefaultAccount->setEnabled(false);
KIconLoader* il = KGlobal::iconLoader();
KGuiItem updateButtenItem( i18n("Update"),
TQIconSet(il->loadIcon("button_ok", KIcon::Small, KIcon::SizeSmall)),
i18n("Accepts the entered data and stores it"),
i18n("Use this to accept the modified data."));
m_updateButton->setGuiItem(updateButtenItem);
connect(m_payeesList, TQT_SIGNAL(selectionChanged()), this, TQT_SLOT(slotSelectPayee()));
connect(m_payeesList, TQT_SIGNAL(itemRenamed(TQListViewItem*,int,const TQString&)), this, TQT_SLOT(slotRenamePayee(TQListViewItem*,int,const TQString&)));
connect(addressEdit, TQT_SIGNAL(textChanged()), this, TQT_SLOT(slotPayeeDataChanged()));
connect(postcodeEdit, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(slotPayeeDataChanged()));
connect(telephoneEdit, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(slotPayeeDataChanged()));
connect(emailEdit, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(slotPayeeDataChanged()));
connect(notesEdit, TQT_SIGNAL(textChanged()), this, TQT_SLOT(slotPayeeDataChanged()));
connect(matchKeyEditList, TQT_SIGNAL(changed()), this, TQT_SLOT(slotKeyListChanged()));
connect(radioNoMatch, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotPayeeDataChanged()));
connect(radioNameMatch, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotPayeeDataChanged()));
connect(radioKeyMatch, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotPayeeDataChanged()));
connect(checkMatchIgnoreCase, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotPayeeDataChanged()));
connect(checkEnableDefaultAccount, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotPayeeDataChanged()));
connect(comboDefaultAccount, TQT_SIGNAL(accountSelected(const TQString&)), this, TQT_SLOT(slotPayeeDataChanged()));
connect(buttonSelectMyAccount, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotChooseDefaultAccount()));
connect(m_updateButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotUpdatePayee()));
connect(m_helpButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotHelp()));
connect(m_payeesList, TQT_SIGNAL(contextMenu(KListView*, TQListViewItem*, const TQPoint&)), this, TQT_SLOT(slotOpenContextMenu(KListView*, TQListViewItem*, const TQPoint&)));
// connect(m_payeesList, TQT_SIGNAL(rightButtonClicked(TQListViewItem* , const TQPoint&, int)),
// this, TQT_SLOT(slotOpenContextMenu(TQListViewItem*)));
connect(m_transactionView, TQT_SIGNAL(doubleClicked(TQListViewItem*)),
this, TQT_SLOT(slotTransactionDoubleClicked(TQListViewItem*)));
connect(m_tabWidget, TQT_SIGNAL(currentChanged(TQWidget*)), this, TQT_SLOT(rearrange(void)));
connect(MyMoneyFile::instance(), TQT_SIGNAL(dataChanged()), this, TQT_SLOT(slotLoadPayees()));
}
KPayeesView::~KPayeesView()
{
// remember the splitter settings for startup
KConfig *config = KGlobal::config();
config->setGroup("Last Use Settings");
config->writeEntry("KPayeesViewSplitterSize", m_splitter->sizes());
}
void KPayeesView::slotQueueUpdate(void)
{
m_updatesQueued++;
// The KListViewSearchLineWidget has an internal timer for update purposes
// of 200 ms, so we should be safe with 250 ms here
TQTimer::singleShot(250, this, TQT_SLOT(slotActivateUpdate()));
}
void KPayeesView::slotActivateUpdate(void)
{
--m_updatesQueued;
if(m_updatesQueued == 0)
slotSelectPayee();
}
void KPayeesView::slotChooseDefaultAccount(void)
{
MyMoneyFile* file = MyMoneyFile::instance();
TQMap<TQString,int> account_count;
for (int i = 0; i < m_transactionPtrVector.size(); ++i) {
KMyMoneyTransaction* t = m_transactionPtrVector[i];
MyMoneySplit s = t->splitById(t->splitId());
const MyMoneyAccount& acc = file->account(s.accountId());
TQString txt;
if (s.action() != MyMoneySplit::ActionAmortization
&& acc.accountType() != MyMoneyAccount::AssetLoan
&& !file->isTransfer(*t)
&& t->splitCount() == 2) {
MyMoneySplit s0 = t->splitByAccount(s.accountId(), false);
if (account_count.contains(s0.accountId())) {
account_count[s0.accountId()]++;
}
else {
account_count[s0.accountId()] = 1;
}
}
}
TQMapIterator<TQString,int> most_frequent, iter;
most_frequent = account_count.end();
for (iter = account_count.begin(); iter != account_count.end(); iter++) {
if (iter.data() > most_frequent.data()) {
most_frequent = iter;
}
}
if (most_frequent != account_count.end()) {
checkEnableDefaultAccount->setChecked(true);
comboDefaultAccount->setSelected(most_frequent.key());
}
}
void KPayeesView::slotStartRename(void)
{
TQListViewItemIterator it_l(m_payeesList, TQListViewItemIterator::Selected);
TQListViewItem* it_v;
if((it_v = it_l.current()) != 0) {
it_v->startRename(0);
}
}
// This variant is only called when a single payee is selected and renamed.
void KPayeesView::slotRenamePayee(TQListViewItem* p , int /* col */, const TQString& txt)
{
//kdDebug() << "[KPayeesView::slotRenamePayee]" << endl;
// create a copy of the new name without appended whitespaces
TQString new_name = txt.stripWhiteSpace();
if (m_payee.name() != new_name) {
MyMoneyFileTransaction ft;
try {
// check if we already have a payee with the new name
try {
// this function call will throw an exception, if the payee
// hasn't been found.
MyMoneyFile::instance()->payeeByName(new_name);
// the name already exists, ask the user whether he's sure to keep the name
if (KMessageBox::questionYesNo(this,
i18n("A payee with the name '%1' already exists. It is not advisable to have "
"multiple payees with the same identification name. Are you sure you would like "
"to rename the payee?").arg(new_name)) != KMessageBox::Yes)
{
p->setText(0,m_payee.name());
return;
}
} catch(MyMoneyException *e) {
// all ok, the name is unique
delete e;
}
m_payee.setName(new_name);
m_newName = new_name;
MyMoneyFile::instance()->modifyPayee(m_payee);
// the above call to modifyPayee will reload the view so
// all references and pointers to the view have to be
// re-established.
// make sure, that the record is visible even if it moved
// out of sight due to the rename operation
ensurePayeeVisible(m_payee.id());
ft.commit();
} catch(MyMoneyException *e) {
KMessageBox::detailedSorry(0, i18n("Unable to modify payee"),
(e->what() + " " + i18n("thrown in") + " " + e->file()+ ":%1").arg(e->line()));
delete e;
}
}
else {
p->setText(0, new_name);
}
}
void KPayeesView::ensurePayeeVisible(const TQString& id)
{
for (TQListViewItem * item = m_payeesList->firstChild(); item; item = item->itemBelow()) {
KPayeeListItem* p = dynamic_cast<KPayeeListItem*>(item);
if(p && p->payee().id() == id) {
if(p->itemAbove())
m_payeesList->ensureItemVisible(p->itemAbove());
if(p->itemBelow())
m_payeesList->ensureItemVisible(p->itemBelow());
m_payeesList->setCurrentItem(p); // active item and deselect all others
m_payeesList->setSelected(p, true); // and select it
m_payeesList->ensureItemVisible(p);
break;
}
}
}
void KPayeesView::selectedPayees(TQValueList<MyMoneyPayee>& payeesList) const
{
TQListViewItemIterator it_l(m_payeesList, TQListViewItemIterator::Selected | TQListViewItemIterator::Visible);
TQListViewItem* it_v;
while((it_v = it_l.current()) != 0) {
KPayeeListItem* item = dynamic_cast<KPayeeListItem*>(it_v);
if(item)
payeesList << item->payee();
++it_l;
}
}
void KPayeesView::slotSelectPayee(void)
{
// check if the content of a currently selected payee was modified
// and ask to store the data
if (m_updateButton->isEnabled()) {
if (KMessageBox::questionYesNo(this, TQString("<qt>%1</qt>").arg(
i18n("Do you want to save the changes for <b>%1</b>?").arg(m_newName)),
i18n("Save changes")) == KMessageBox::Yes) {
m_inSelection = true;
slotUpdatePayee();
m_inSelection = false;
}
}
// loop over all payees and count the number of payees, also
// optain last selected payee
TQValueList<MyMoneyPayee> payeesList;
selectedPayees(payeesList);
emit selectObjects(payeesList);
if (payeesList.count() == 0) {
m_tabWidget->setEnabled(false); // disable tab widget
clearItemData();
m_payee = MyMoneyPayee();
return; // make sure we don't access an undefined payee
}
// if we have multiple payees selected, clear and disable the payee informations
if (payeesList.count() > 1) {
m_tabWidget->setEnabled(false); // disable tab widget
clearItemData();
// disable renaming in all listviewitem
for (TQListViewItem * i = m_payeesList->firstChild(); i; i = i->itemBelow())
i->setRenameEnabled(0, false);
return;
}
// otherwise we have just one selected, enable payee information widget
m_tabWidget->setEnabled(true);
// enable renaming in all listviewitem
for (TQListViewItem * i = m_payeesList->firstChild(); i; i = i->itemBelow())
i->setRenameEnabled(0, true);
// as of now we are updating only the last selected payee, and until
// selection mode of the TQListView has been changed to Extended, this
// will also be the only selection and behave exactly as before - Andreas
try {
m_payee = payeesList[0];
m_newName = m_payee.name();
addressEdit->setEnabled(true);
addressEdit->setText(m_payee.address());
postcodeEdit->setEnabled(true);
postcodeEdit->setText(m_payee.postcode());
telephoneEdit->setEnabled(true);
telephoneEdit->setText(m_payee.telephone());
emailEdit->setEnabled(true);
emailEdit->setText(m_payee.email());
notesEdit->setText(m_payee.notes());
TQStringList keys;
bool ignorecase = false;
MyMoneyPayee::payeeMatchType type = m_payee.matchData(ignorecase, keys);
m_matchType->setButton(static_cast<int>(type));
matchKeyEditList->clear();
matchKeyEditList->insertStringList(keys);
checkMatchIgnoreCase->setChecked(ignorecase);
checkEnableDefaultAccount->setChecked(m_payee.defaultAccountEnabled());
comboDefaultAccount->setSelected(m_payee.defaultAccountId());
slotPayeeDataChanged();
showTransactions();
} catch(MyMoneyException *e) {
qDebug("exception during display of payee: %s at %s:%ld", e->what().latin1(), e->file().latin1(), e->line());
m_transactionView->clear();
m_payee = MyMoneyPayee();
delete e;
}
}
void KPayeesView::clearItemData(void)
{
addressEdit->setText(TQString());
postcodeEdit->setText(TQString());
telephoneEdit->setText(TQString());
emailEdit->setText(TQString());
notesEdit->setText(TQString());
showTransactions();
}
void KPayeesView::showTransactions(void)
{
MyMoneyFile* file = MyMoneyFile::instance();
MyMoneyMoney balance(0);
unsigned int i;
// clear the current transaction listview
m_transactionView->clear();
if(m_payee.id().isEmpty() || !m_tabWidget->isEnabled()) {
m_balanceLabel->setText(i18n("Balance: %1").arg(balance.formatMoney(MyMoneyFile::instance()->baseCurrency().smallestAccountFraction())));
return;
}
// setup the list and the pointer vector
MyMoneyTransactionFilter filter;
filter.addPayee(m_payee.id());
filter.setDateFilter(KMyMoneyGlobalSettings::startDate().date(), TQDate());
TQValueList<MyMoneyTransaction> list = file->transactionList(filter);
m_transactionList.clear();
m_transactionPtrVector.clear();
m_transactionPtrVector.resize(list.size());
m_transactionPtrVector.setPayeeId(m_payee.id());
m_transactionPtrVector.setSortType(KTransactionPtrVector::SortPostDate);
TQValueList<MyMoneyTransaction>::ConstIterator it_t;
TQString lastId;
int ofs = 0;
for(i = 0, it_t = list.begin(); it_t != list.end(); ++it_t) {
KMyMoneyTransaction k(*it_t);
filter.match(*it_t);
if(lastId != (*it_t).id()) {
ofs = 0;
lastId = (*it_t).id();
} else
ofs++;
k.setSplitId(filter.matchingSplits()[ofs].id());
MyMoneyAccount acc = MyMoneyFile::instance()->account(filter.matchingSplits()[ofs].accountId());
if(acc.accountGroup() == MyMoneyAccount::Asset
|| acc.accountGroup() == MyMoneyAccount::Liability) {
TQValueList<KMyMoneyTransaction>::ConstIterator it_k;
it_k = m_transactionList.append(k);
balance += k.splitById(k.splitId()).value();
m_transactionPtrVector.insert(i, &(*it_k));
++i;
}
}
m_transactionPtrVector.resize(i);
// sort the transactions
m_transactionPtrVector.sort();
// and fill the m_transactionView
KTransactionListItem *item = 0;
for(i = 0; i < m_transactionPtrVector.size(); ++i) {
KMyMoneyTransaction* t = m_transactionPtrVector[i];
MyMoneySplit s = t->splitById(t->splitId());
const MyMoneyAccount& acc = file->account(s.accountId());
item = new KTransactionListItem(m_transactionView, item, s.accountId(), t->id());
item->setText(0, s.number());
item->setText(1, KGlobal::locale()->formatDate(t->postDate(), true));
TQString txt;
if(s.action() == MyMoneySplit::ActionAmortization) {
if(acc.accountType() == MyMoneyAccount::Loan) {
if(s.value().isPositive()) {
txt = i18n("Amortization of %1").arg(acc.name());
} else {
txt = i18n("Payment to %1").arg(acc.name());
}
} else if(acc.accountType() == MyMoneyAccount::AssetLoan) {
if(s.value().isNegative()) {
txt = i18n("Amortization of %1").arg(acc.name());
} else {
txt = i18n("Payment to %1").arg(acc.name());
}
} else {
txt = i18n("Loan payment from %1").arg(acc.name());
}
} else if (file->isTransfer(*t)) {
if(!s.value().isNegative()) {
txt = i18n("Transfer to %1").arg(acc.name());
} else {
txt = i18n("Transfer from %1").arg(acc.name());
}
} else if(t->splitCount() > 2) {
txt = i18n("Split transaction (category replacement)", "Split transaction");
} else if(t->splitCount() == 2) {
MyMoneySplit s0 = t->splitByAccount(s.accountId(), false);
txt = MyMoneyFile::instance()->accountToCategory(s0.accountId());
}
item->setText(2, txt);
item->setText(3, s.value().formatMoney(acc.fraction()));
}
m_balanceLabel->setText(i18n("Balance: %1").arg(balance.formatMoney(MyMoneyFile::instance()->baseCurrency().smallestAccountFraction())));
// Trick: it seems, that the initial sizing of the view does
// not work correctly. At least, the columns do not get displayed
// correct. Reason: the return value of m_transactionView->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(50, this, TQT_SLOT(rearrange()));
}
void KPayeesView::slotKeyListChanged(void)
{
bool rc = false;
bool ignorecase = false;
TQStringList keys;
// J.Rodehueser: delete unused variable 'type'
// orig: MyMoneyPayee::payeeMatchType type = m_payee.matchData(ignorecase, keys);
m_payee.matchData(ignorecase, keys);
if(m_matchType->selectedId() == MyMoneyPayee::matchKey) {
rc |= (keys != matchKeyEditList->items());
}
m_updateButton->setEnabled(rc);
}
void KPayeesView::slotPayeeDataChanged(void)
{
kdDebug(2) << "KPayeesView::slotPayeeDataChanged(void)" << endl;
bool rc = false;
if(m_tabWidget->isEnabled()) {
rc |= ((m_payee.email().isEmpty() != emailEdit->text().isEmpty())
|| (!emailEdit->text().isEmpty() && m_payee.email() != emailEdit->text()));
rc |= ((m_payee.address().isEmpty() != addressEdit->text().isEmpty())
|| (!addressEdit->text().isEmpty() && m_payee.address() != addressEdit->text()));
rc |= ((m_payee.postcode().isEmpty() != postcodeEdit->text().isEmpty())
|| (!postcodeEdit->text().isEmpty() && m_payee.postcode() != postcodeEdit->text()));
rc |= ((m_payee.telephone().isEmpty() != telephoneEdit->text().isEmpty())
|| (!telephoneEdit->text().isEmpty() && m_payee.telephone() != telephoneEdit->text()));
rc |= ((m_payee.name().isEmpty() != m_newName.isEmpty())
|| (!m_newName.isEmpty() && m_payee.name() != m_newName));
rc |= ((m_payee.notes().isEmpty() != notesEdit->text().isEmpty())
|| (!notesEdit->text().isEmpty() && m_payee.notes() != notesEdit->text()));
bool ignorecase = false;
TQStringList keys;
MyMoneyPayee::payeeMatchType type = m_payee.matchData(ignorecase, keys);
rc |= (static_cast<int>(type) != m_matchType->selectedId());
checkMatchIgnoreCase->setEnabled(false);
matchKeyEditList->setEnabled(false);
if(m_matchType->selectedId() != MyMoneyPayee::matchDisabled) {
checkMatchIgnoreCase->setEnabled(true);
// if we turn matching on, we default to 'ignore case'
// TODO maybe make the default a user option
if(type == MyMoneyPayee::matchDisabled && m_matchType->selectedId() != MyMoneyPayee::matchDisabled)
checkMatchIgnoreCase->setChecked(true);
rc |= (ignorecase != checkMatchIgnoreCase->isChecked());
if(m_matchType->selectedId() == MyMoneyPayee::matchKey) {
matchKeyEditList->setEnabled(true);
rc |= (keys != matchKeyEditList->items());
}
}
rc |= (checkEnableDefaultAccount->isChecked() != m_payee.defaultAccountEnabled());
if (checkEnableDefaultAccount->isChecked()) {
comboDefaultAccount->setEnabled(true);
labelDefaultAccount->setEnabled(true);
// this is only going to understand the first in the list of selected accounts
if (comboDefaultAccount->selectedAccounts().empty()) {
rc |= !m_payee.defaultAccountId().isEmpty();
}
else {
TQString temp = comboDefaultAccount->selectedAccounts().front();
rc |= ( temp.isEmpty() != m_payee.defaultAccountId().isEmpty())
|| (!m_payee.defaultAccountId().isEmpty() && temp != m_payee.defaultAccountId());
}
}
else {
comboDefaultAccount->setEnabled(false);
labelDefaultAccount->setEnabled(false);
}
}
m_updateButton->setEnabled(rc);
}
void KPayeesView::slotUpdatePayee(void)
{
if(m_updateButton->isEnabled()) {
MyMoneyFileTransaction ft;
m_updateButton->setEnabled(false);
try {
m_payee.setName(m_newName);
m_payee.setAddress(addressEdit->text());
m_payee.setPostcode(postcodeEdit->text());
m_payee.setTelephone(telephoneEdit->text());
m_payee.setEmail(emailEdit->text());
m_payee.setNotes(notesEdit->text());
m_payee.setMatchData(static_cast<MyMoneyPayee::payeeMatchType>(m_matchType->selectedId()), checkMatchIgnoreCase->isChecked(), matchKeyEditList->items());
m_payee.setDefaultAccountId();
if (checkEnableDefaultAccount->isChecked()) {
TQString temp;
if (!comboDefaultAccount->selectedAccounts().empty()) {
temp = comboDefaultAccount->selectedAccounts().front();
m_payee.setDefaultAccountId(temp);
}
}
MyMoneyFile::instance()->modifyPayee(m_payee);
ft.commit();
} catch(MyMoneyException *e) {
KMessageBox::detailedSorry(0, i18n("Unable to modify payee"),
(e->what() + " " + i18n("thrown in") + " " + e->file()+ ":%1").arg(e->line()));
delete e;
}
}
}
void KPayeesView::readConfig(void)
{
m_transactionView->setFont(KMyMoneyGlobalSettings::listCellFont());
TQFontMetrics fm( KMyMoneyGlobalSettings::listHeaderFont() );
int height = fm.lineSpacing()+6;
m_transactionView->header()->setMinimumHeight(height);
m_transactionView->header()->setMaximumHeight(height);
m_transactionView->header()->setFont(KMyMoneyGlobalSettings::listHeaderFont());
m_payeesList->setDefaultRenameAction(
KMyMoneyGlobalSettings::focusChangeIsEnter() ? TQListView::Accept : TQListView::Reject);
//initialize the account list?
comboDefaultAccount->loadList((KMyMoneyUtils::categoryTypeE)(KMyMoneyUtils::asset | KMyMoneyUtils::liability | MyMoneyAccount::Income | MyMoneyAccount::Expense));
}
void KPayeesView::show(void)
{
// since we could not construct the connection in our own ctor,
// we set it up now. The widgets of the KListViewSearchLineWidget must exist by now.
// If you want to learn about the details, see the source of KListViewSearchLineWidget's
// constructor
if(m_needConnection) {
connect(m_searchWidget->searchLine(), TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(slotQueueUpdate(void)));
m_needConnection = false;
}
if(m_needReload) {
loadPayees();
m_needReload = false;
}
// fixup the layout
TQTimer::singleShot(0, this, TQT_SLOT(rearrange()));
// don't forget base class implementation
KPayeesViewDecl::show();
TQValueList<MyMoneyPayee> list;
selectedPayees(list);
emit selectObjects(list);
}
void KPayeesView::slotLoadPayees(void)
{
if(isVisible()) {
if(m_inSelection)
TQTimer::singleShot(0, this, TQT_SLOT(slotLoadPayees()));
else
loadPayees();
} else {
m_needReload = true;
}
}
void KPayeesView::loadPayees(void)
{
if(m_inSelection)
return;
TQMap<TQString, bool> isSelected;
TQString id;
::timetrace("Start KPayeesView::loadPayees");
readConfig();
// remember which items are selected in the list
TQListViewItemIterator it_l(m_payeesList, TQListViewItemIterator::Selected);
TQListViewItem* it_v;
while((it_v = it_l.current()) != 0) {
KPayeeListItem* item = dynamic_cast<KPayeeListItem*>(it_v);
if(item)
isSelected[item->payee().id()] = true;
++it_l;
}
// keep current selected item
KPayeeListItem *currentItem = static_cast<KPayeeListItem *>(m_payeesList->currentItem());
if(currentItem)
id = currentItem->payee().id();
// remember the upper left corner of the viewport
TQPoint startPoint = m_payeesList->viewportToContents(TQPoint(0, 0));
// turn off updates to avoid flickering during reload
m_payeesList->setUpdatesEnabled(false);
// clear the list
m_payeesList->clear();
m_transactionView->clear();
currentItem = 0;
TQValueList<MyMoneyPayee>list = MyMoneyFile::instance()->payeeList();
TQValueList<MyMoneyPayee>::ConstIterator it;
for (it = list.begin(); it != list.end(); ++it) {
KPayeeListItem* item = new KPayeeListItem(m_payeesList, *it);
if(item->payee().id() == id)
currentItem = item;
if(isSelected[item->payee().id()])
item->setSelected(true);
}
if (currentItem) {
m_payeesList->setCurrentItem(currentItem);
}
// reposition viewport
m_payeesList->setContentsPos(startPoint.x(), startPoint.y());
m_searchWidget->searchLine()->updateSearch(TQString());
// turn updates back on
m_payeesList->setUpdatesEnabled(true);
m_payeesList->repaintContents();
slotSelectPayee();
::timetrace("End KPayeesView::loadPayees");
}
void KPayeesView::rearrange(void)
{
resizeEvent(0);
}
void KPayeesView::resizeEvent(TQResizeEvent* ev)
{
// resize the register
int w = m_transactionView->visibleWidth();
w -= m_transactionView->columnWidth(0);
w -= m_transactionView->columnWidth(1);
w -= m_transactionView->columnWidth(3);
m_transactionView->setColumnWidth(2, w);
m_transactionView->resizeContents(
m_transactionView->visibleWidth(),
m_transactionView->contentsHeight());
m_payeesList->setColumnWidth(0, m_payeesList->visibleWidth());
KPayeesViewDecl::resizeEvent(ev);
}
void KPayeesView::slotTransactionDoubleClicked(TQListViewItem* i)
{
KTransactionListItem* item = static_cast<KTransactionListItem *>(i);
if (item)
emit transactionSelected(item->accountId(), item->transactionId());
}
void KPayeesView::slotSelectPayeeAndTransaction(const TQString& payeeId, const TQString& accountId, const TQString& transactionId)
{
if(!isVisible())
return;
try {
// clear filter
m_searchWidget->searchLine()->clear();
m_searchWidget->searchLine()->updateSearch();
// deselect all other selected items
TQListViewItemIterator it_l(m_payeesList, TQListViewItemIterator::Selected);
TQListViewItem* it_v;
while((it_v = it_l.current()) != 0) {
KPayeeListItem* item = dynamic_cast<KPayeeListItem*>(it_v);
if(item)
item->setSelected(false);
++it_l;
}
// find the payee in the list
TQListViewItem* it;
for(it = m_payeesList->firstChild(); it; it = it->itemBelow()) {
KPayeeListItem* item = dynamic_cast<KPayeeListItem *>(it);
if(item && item->payee().id() == payeeId) {
if(it->itemAbove())
m_payeesList->ensureItemVisible(it->itemAbove());
if(it->itemBelow())
m_payeesList->ensureItemVisible(it->itemBelow());
m_payeesList->setCurrentItem(it); // active item and deselect all others
m_payeesList->setSelected(it,true); // and select it
m_payeesList->ensureItemVisible(it);
KTransactionListItem* item = dynamic_cast<KTransactionListItem*> (m_transactionView->firstChild());
while(item != 0) {
if(item->accountId() == accountId && item->transactionId() == transactionId)
break;
item = dynamic_cast<KTransactionListItem*> (item->nextSibling());
}
if(!item) {
item = dynamic_cast<KTransactionListItem*> (m_transactionView->firstChild());
}
if(item) {
m_transactionView->setSelected(item, true);
m_transactionView->ensureItemVisible(item);
}
// quit out of for() loop
break;
}
}
} catch(MyMoneyException *e) {
qWarning("Unexpected exception in KPayeesView::slotSelectPayeeAndTransaction");
delete e;
}
}
void KPayeesView::slotOpenContextMenu(KListView* lv, TQListViewItem* i, const TQPoint& p)
{
Q_UNUSED(p);
if(lv == m_payeesList) {
KPayeeListItem* item = dynamic_cast<KPayeeListItem*>(i);
if(item) {
emit openContextMenu(item->payee());
}
}
}
void KPayeesView::slotHelp(void)
{
kapp->invokeHelp("details.payees.personalinformation");
}
#include "kpayeesview.moc"
// vim:cin:si:ai:et:ts=2:sw=2: