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/kcategoriesview.cpp

314 lines
11 KiB

/***************************************************************************
kcategoriesview.cpp - description
-------------------
begin : Sun Jan 20 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 <tqlabel.h>
#include <tqlayout.h>
// ----------------------------------------------------------------------------
// KDE Includes
#include <klocale.h>
#include <kdebug.h>
#include <kiconloader.h>
#include <kguiitem.h>
#include <kpushbutton.h>
// ----------------------------------------------------------------------------
// Project Includes
#include <kmymoney/mymoneyfile.h>
#include <kmymoney/kmymoneyaccounttree.h>
#include "kcategoriesview.h"
#include "../widgets/klistviewsearchline.h"
#include "../kmymoneyglobalsettings.h"
#include "../kmymoney2.h"
KCategoriesView::KCategoriesView(TQWidget *parent, const char *name ) :
KCategoriesViewDecl(parent, name),
m_incomeItem(0),
m_expenseItem(0),
m_needReload(false)
{
// create the searchline widget
// and insert it into the existing layout
m_searchWidget = new TDEListViewSearchLineWidget(m_accountTree, m_accountTree->parentWidget());
TQVBoxLayout* layout = dynamic_cast<TQVBoxLayout*>(m_accountTree->parentWidget()->layout());
if(layout) {
layout->insertWidget(0, m_searchWidget);
}
// setup icons for collapse and expand button
KIconLoader *ic = TDEGlobal::iconLoader();
KGuiItem collapseGuiItem("",
TQIconSet(ic->loadIcon("viewmag-", KIcon::Small, KIcon::SizeSmall)),
TQString(),
TQString());
KGuiItem expandGuiItem("",
TQIconSet(ic->loadIcon("viewmag+", KIcon::Small, KIcon::SizeSmall)),
TQString(),
TQString());
m_collapseButton->setGuiItem(collapseGuiItem);
m_expandButton->setGuiItem(expandGuiItem);
m_accountTree->setSectionHeader(i18n("Category"));
connect(m_accountTree, TQT_SIGNAL(selectObject(const MyMoneyObject&)), this, TQT_SIGNAL(selectObject(const MyMoneyObject&)));
connect(m_accountTree, TQT_SIGNAL(openContextMenu(const MyMoneyObject&)), this, TQT_SIGNAL(openContextMenu(const MyMoneyObject&)));
connect(m_accountTree, TQT_SIGNAL(valueChanged(void)), this, TQT_SLOT(slotUpdateProfit(void)));
connect(m_accountTree, TQT_SIGNAL(openObject(const MyMoneyObject&)), this, TQT_SIGNAL(openObject(const MyMoneyObject&)));
connect(m_accountTree, TQT_SIGNAL(reparent(const MyMoneyAccount&, const MyMoneyAccount&)), this, TQT_SIGNAL(reparent(const MyMoneyAccount&, const MyMoneyAccount&)));
connect(MyMoneyFile::instance(), TQT_SIGNAL(dataChanged()), this, TQT_SLOT(slotLoadAccounts()));
connect(m_collapseButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotExpandCollapse()));
connect(m_expandButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotExpandCollapse()));
}
KCategoriesView::~KCategoriesView()
{
}
void KCategoriesView::slotExpandCollapse(void)
{
if(sender()) {
KMyMoneyGlobalSettings::setShowAccountsExpanded(sender() == m_expandButton);
}
}
void KCategoriesView::show(void)
{
if(m_needReload) {
loadAccounts();
m_needReload = false;
}
// don't forget base class implementation
KCategoriesViewDecl::show();
// if we have a selected account, let the application know about it
KMyMoneyAccountTreeBaseItem *item = m_accountTree->selectedItem();
if(item) {
emit selectObject(item->itemObject());
}
}
void KCategoriesView::polish(void)
{
KCategoriesViewDecl::polish();
m_accountTree->setResizeMode(TQListView::LastColumn);
m_accountTree->restoreLayout("Category View Settings");
}
void KCategoriesView::slotLoadAccounts(void)
{
if(isVisible()) {
loadAccounts();
} else {
m_needReload = true;
}
}
void KCategoriesView::loadAccounts(void)
{
TQMap<TQString, bool> isOpen;
::timetrace("start load categories view");
// remember the id of the current selected item
KMyMoneyAccountTreeBaseItem *item = m_accountTree->selectedItem();
TQString selectedItemId = (item) ? item->id() : TQString();
// keep a map of all 'expanded' accounts
TQListViewItemIterator it_lvi(m_accountTree);
while(it_lvi.current()) {
item = dynamic_cast<KMyMoneyAccountTreeItem*>(it_lvi.current());
if(item && item->isOpen()) {
isOpen[item->id()] = true;
}
++it_lvi;
}
// remember the upper left corner of the viewport
TQPoint startPoint = m_accountTree->viewportToContents(TQPoint(0, 0));
// turn off updates to avoid flickering during reload
m_accountTree->setUpdatesEnabled(false);
// clear the current contents and recreate it
m_accountTree->clear();
m_securityMap.clear();
m_transactionCountMap.clear();
// make sure, the pointers are not pointing to some deleted object
m_incomeItem = m_expenseItem = 0;
MyMoneyFile* file = MyMoneyFile::instance();
TQValueList<MyMoneySecurity> slist = file->currencyList();
slist += file->securityList();
TQValueList<MyMoneySecurity>::const_iterator it_s;
for(it_s = slist.begin(); it_s != slist.end(); ++it_s) {
m_securityMap[(*it_s).id()] = *it_s;
}
m_transactionCountMap = file->transactionCountMap();
bool haveUnusedCategories = false;
// create the items
try {
const MyMoneySecurity& security = file->baseCurrency();
m_accountTree->setBaseCurrency(security);
const MyMoneyAccount& income = file->income();
m_incomeItem = new KMyMoneyAccountTreeItem(m_accountTree, income, security, i18n("Income"));
haveUnusedCategories |= loadSubAccounts(m_incomeItem, income.accountList());
const MyMoneyAccount& expense = file->expense();
m_expenseItem = new KMyMoneyAccountTreeItem(m_accountTree, expense, security, i18n("Expense"));
haveUnusedCategories |= loadSubAccounts(m_expenseItem, expense.accountList());
} catch(MyMoneyException *e) {
kdDebug(2) << "Problem in categoriesview: " << e->what() << endl;
delete e;
}
// scan through the list of accounts and re-expand those that were
// expanded and re-select the one that was probably selected before
it_lvi = TQListViewItemIterator(m_accountTree);
while(it_lvi.current()) {
item = dynamic_cast<KMyMoneyAccountTreeItem*>(it_lvi.current());
if(item) {
if(item->id() == selectedItemId)
m_accountTree->setSelected(item, true);
if(isOpen.find(item->id()) != isOpen.end())
item->setOpen(true);
}
++it_lvi;
}
// reposition viewport
m_accountTree->setContentsPos(startPoint.x(), startPoint.y());
m_searchWidget->searchLine()->updateSearch(TQString());
// turn updates back on
m_accountTree->setUpdatesEnabled(true);
m_accountTree->repaintContents();
// and in case we need to show things expanded, we'll do so
if(KMyMoneyGlobalSettings::showAccountsExpanded())
m_accountTree->slotExpandAll();
// update the hint if categories are hidden
m_hiddenCategories->setShown(haveUnusedCategories);
::timetrace("done load categories view");
}
bool KCategoriesView::loadSubAccounts(KMyMoneyAccountTreeItem* parent, const TQStringList& accountList)
{
MyMoneyFile* file = MyMoneyFile::instance();
bool unused = false;
TQStringList::const_iterator it_a;
for(it_a = accountList.begin(); it_a != accountList.end(); ++it_a) {
const MyMoneyAccount& acc = file->account(*it_a);
TQValueList<MyMoneyPrice> prices;
MyMoneySecurity security = file->baseCurrency();
try {
if(acc.isInvest()) {
security = m_securityMap[acc.currencyId()];
prices += file->price(acc.currencyId(), security.tradingCurrency());
if(security.tradingCurrency() != file->baseCurrency().id()) {
MyMoneySecurity sec = m_securityMap[security.tradingCurrency()];
prices += file->price(sec.id(), file->baseCurrency().id());
}
} else if(acc.currencyId() != file->baseCurrency().id()) {
if(acc.currencyId() != file->baseCurrency().id()) {
security = m_securityMap[acc.currencyId()];
prices += file->price(acc.currencyId(), file->baseCurrency().id());
}
}
} catch(MyMoneyException *e) {
kdDebug(2) << __PRETTY_FUNCTION__ << " caught exception while adding " << acc.name() << "[" << acc.id() << "]: " << e->what();
delete e;
}
KMyMoneyAccountTreeItem* item = new KMyMoneyAccountTreeItem(parent, acc, prices, security);
unused |= loadSubAccounts(item, acc.accountList());
// no child accounts and not transactions in this account means 'unused'
bool thisUnused = (!item->firstChild()) && (m_transactionCountMap[acc.id()] == 0);
// In case of a category which is unused and we are requested to suppress
// the display of those,
if(acc.accountGroup() == MyMoneyAccount::Income
|| acc.accountGroup() == MyMoneyAccount::Expense) {
if(KMyMoneyGlobalSettings::hideUnusedCategory() && thisUnused) {
unused = true;
delete item;
}
}
}
return unused;
}
void KCategoriesView::slotUpdateProfit(void)
{
if(!m_incomeItem || !m_expenseItem)
return;
MyMoneyMoney profit = m_incomeItem->totalValue() - m_expenseItem->totalValue();
TQString s(i18n("Profit: "));
if(profit.isNegative())
s = i18n("Loss: ");
// FIXME figure out how to deal with the approximate
// if(!(file->totalValueValid(assetAccount.id()) & file->totalValueValid(liabilityAccount.id())))
// s += "~ ";
s.replace(TQString(" "), TQString("&nbsp;"));
if(profit.isNegative()) {
s += "<b><font color=\"red\">";
}
const MyMoneySecurity& sec = MyMoneyFile::instance()->baseCurrency();
TQString v(profit.abs().formatMoney(sec));
s += v.replace(TQString(" "), TQString("&nbsp;"));
if(profit.isNegative()) {
s += "</font></b>";
}
m_totalProfitsLabel->setFont(KMyMoneyGlobalSettings::listCellFont());
m_totalProfitsLabel->setText(s);
}
#include "kcategoriesview.moc"