/*************************************************************************** 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 *tqparent, const char *name ) : KCategoriesViewDecl(tqparent, name), m_incomeItem(0), m_expenseItem(0), m_needReload(false) { // create the searchline widget // and insert it into the existing tqlayout m_searchWidget = new KListViewSearchLineWidget(m_accountTree, m_accountTree->tqparentWidget()); TQVBoxLayout* tqlayout = dynamic_cast<TQVBoxLayout*>(m_accountTree->tqparentWidget()->tqlayout()); if(tqlayout) { tqlayout->insertWidget(0, m_searchWidget); } // setup icons for collapse and expand button KIconLoader *ic = KGlobal::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.tqfind(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->tqrepaintContents(); // 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* tqparent, 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(tqparent, 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.tqreplace(TQString(" "), TQString(" ")); if(profit.isNegative()) { s += "<b><font color=\"red\">"; } const MyMoneySecurity& sec = MyMoneyFile::instance()->baseCurrency(); TQString v(profit.abs().formatMoney(sec)); s += v.tqreplace(TQString(" "), TQString(" ")); if(profit.isNegative()) { s += "</font></b>"; } m_totalProfitsLabel->setFont(KMyMoneyGlobalSettings::listCellFont()); m_totalProfitsLabel->setText(s); } #include "kcategoriesview.moc"