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.
1109 lines
36 KiB
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) {
|
|
tqDebug("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) {
|
|
tqWarning("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:
|