/*************************************************************************** mymoneybudget.cpp ------------------- begin : Sun July 4 2004 copyright : (C) 2004-2005 by Ace Jones email : acejones@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. * * * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif // ---------------------------------------------------------------------------- // TQt Includes #include #include // ---------------------------------------------------------------------------- // TDE Includes // ---------------------------------------------------------------------------- // Project Includes #include "mymoneybudget.h" const TQStringList MyMoneyBudget::AccountGroup::kBudgetLevelText = TQStringList::split(",","none,monthly,monthbymonth,yearly,invalid",true); const int BUDGET_VERSION = 2; bool MyMoneyBudget::AccountGroup::isZero(void) const { return (!m_budgetsubaccounts && m_budgetlevel == eMonthly && balance().isZero()); } void MyMoneyBudget::AccountGroup::convertToMonthly(void) { MyMoneyBudget::PeriodGroup period; switch(m_budgetlevel) { case eYearly: case eMonthByMonth: period = *(m_periods.begin()); // make him monthly period.setAmount(balance() / MyMoneyMoney(12,1)); clearPeriods(); addPeriod(period.startDate(), period); break; default: break; } m_budgetlevel = eMonthly; } void MyMoneyBudget::AccountGroup::convertToYearly(void) { MyMoneyBudget::PeriodGroup period; switch(m_budgetlevel) { case eMonthByMonth: case eMonthly: period = *(m_periods.begin()); // make him monthly period.setAmount(totalBalance()); clearPeriods(); addPeriod(period.startDate(), period); break; default: break; } m_budgetlevel = eYearly; } void MyMoneyBudget::AccountGroup::convertToMonthByMonth(void) { MyMoneyBudget::PeriodGroup period; TQDate date; switch(m_budgetlevel) { case eMonthByMonth: case eMonthly: period = *(m_periods.begin()); period.setAmount(totalBalance() / MyMoneyMoney(12,1)); clearPeriods(); date = period.startDate(); for(int i = 0; i < 12; ++i) { addPeriod(date, period); date = date.addMonths(1); period.setStartDate(date); } break; default: break; } m_budgetlevel = eYearly; } MyMoneyBudget::AccountGroup MyMoneyBudget::AccountGroup::operator += (const MyMoneyBudget::AccountGroup& _r) { MyMoneyBudget::AccountGroup r(_r); // make both operands based on the same budget level if(m_budgetlevel != r.m_budgetlevel) { if(m_budgetlevel == eMonthly) { // my budget is monthly if(r.m_budgetlevel == eYearly) { // his his yearly r.convertToMonthly(); } else if(r.m_budgetlevel == eMonthByMonth) { // his is month by month convertToMonthByMonth(); } } else if(m_budgetlevel == eYearly) { // my budget is yearly if(r.m_budgetlevel == eMonthly) { // his is monthly r.convertToYearly(); } else if(r.m_budgetlevel == eMonthByMonth) { // his is month by month convertToMonthByMonth(); } } else if(m_budgetlevel == eMonthByMonth) { // my budget is month by month r.convertToMonthByMonth(); } } // now both budgets should be of the same type and we simply need // to iterate over the period list and add the values TQMap periods = m_periods; TQMap rPeriods = r.m_periods; TQMap::const_iterator it_p; TQMap::const_iterator it_pr; m_periods.clear(); it_p = periods.begin(); it_pr = rPeriods.begin(); TQDate date = (*it_p).startDate(); while(it_p != periods.end()) { MyMoneyBudget::PeriodGroup period = *it_p; if(it_pr != rPeriods.end()) { period.setAmount(period.amount() + (*it_pr).amount()); ++it_pr; } addPeriod(date, period); date = date.addMonths(1); ++it_p; } return *this; } bool MyMoneyBudget::AccountGroup::operator == (const AccountGroup &r) const { return (m_id == r.m_id && m_budgetlevel == r.m_budgetlevel && m_budgetsubaccounts == r.m_budgetsubaccounts && m_periods.keys() == r.m_periods.keys() && m_periods.values() == r.m_periods.values()); } MyMoneyBudget::MyMoneyBudget(void) : m_name("Unconfigured Budget") { } MyMoneyBudget::MyMoneyBudget(const TQString& _name) : m_name(_name) { } MyMoneyBudget::MyMoneyBudget(const TQDomElement& node) : MyMoneyObject(node) { if(!read(node)) clearId(); } MyMoneyBudget::MyMoneyBudget(const TQString& id, const MyMoneyBudget& budget) { *this = budget; m_id = id; } MyMoneyBudget::~MyMoneyBudget() { } bool MyMoneyBudget::operator == (const MyMoneyBudget& right) const { return (MyMoneyObject::operator==(right) && (m_accounts.count() == right.m_accounts.count()) && (m_accounts.keys() == right.m_accounts.keys()) && (m_accounts.values() == right.m_accounts.values()) && (m_name == right.m_name) && (m_start == right.m_start) ); } void MyMoneyBudget::write(TQDomElement& e, TQDomDocument *doc) const { writeBaseXML(*doc, e); e.setAttribute("name", m_name); e.setAttribute("start", m_start.toString(TQt::ISODate) ); e.setAttribute("version", BUDGET_VERSION); TQMap::const_iterator it; for(it = m_accounts.begin(); it != m_accounts.end(); ++it) { // only add the account if there is a budget entered if(!(*it).balance().isZero()) { TQDomElement domAccount = doc->createElement("ACCOUNT"); domAccount.setAttribute("id", it.key()); domAccount.setAttribute("budgetlevel", AccountGroup::kBudgetLevelText[it.data().budgetLevel()]); domAccount.setAttribute("budgetsubaccounts", it.data().budgetSubaccounts()); const TQMap periods = it.data().getPeriods(); TQMap::const_iterator it_per; for(it_per = periods.begin(); it_per != periods.end(); ++it_per) { if(!(*it_per).amount().isZero()) { TQDomElement domPeriod = doc->createElement("PERIOD"); domPeriod.setAttribute("amount", (*it_per).amount().toString()); domPeriod.setAttribute("start", (*it_per).startDate().toString(TQt::ISODate)); domAccount.appendChild(domPeriod); } } e.appendChild(domAccount); } } } bool MyMoneyBudget::read(const TQDomElement& e) { // The goal of this reading method is 100% backward AND 100% forward // compatability. Any Budget ever created with any version of KMyMoney // should be able to be loaded by this method (as long as it's one of the // Budget types supported in this version, of course) bool result = false; if ("BUDGET" == e.tagName()) { result = true; m_name = e.attribute("name"); m_start = TQDate::fromString(e.attribute("start"), TQt::ISODate); m_id = e.attribute("id"); TQDomNode child = e.firstChild(); while(!child.isNull() && child.isElement()) { TQDomElement c = child.toElement(); AccountGroup account; if("ACCOUNT" == c.tagName()) { if(c.hasAttribute("id")) account.setId(c.attribute("id")); if(c.hasAttribute("budgetlevel")) { int i = AccountGroup::kBudgetLevelText.findIndex(c.attribute("budgetlevel")); if ( i != -1 ) account.setBudgetLevel(static_cast(i)); } if(c.hasAttribute("budgetsubaccounts")) account.setBudgetSubaccounts(c.attribute("budgetsubaccounts").toUInt()); } TQDomNode period = c.firstChild(); while(!period.isNull() && period.isElement()) { TQDomElement per = period.toElement(); PeriodGroup pGroup; if("PERIOD" == per.tagName() && per.hasAttribute("amount") && per.hasAttribute("start")) { pGroup.setAmount( MyMoneyMoney(per.attribute("amount")) ); pGroup.setStartDate( TQDate::fromString(per.attribute("start"), TQt::ISODate) ); account.addPeriod(pGroup.startDate(), pGroup); } period = period.nextSibling(); } m_accounts[account.id()] = account; child = child.nextSibling(); } } return result; } void MyMoneyBudget::writeXML(TQDomDocument& document, TQDomElement& parent) const { TQDomElement el = document.createElement("BUDGET"); write(el,&document); parent.appendChild(el); } bool MyMoneyBudget::hasReferenceTo(const TQString& id) const { // return true if we have an assignment for this id return (m_accounts.contains(id)); } void MyMoneyBudget::removeReference(const TQString& id) { if(m_accounts.contains(id)) { m_accounts.remove(id); } } void MyMoneyBudget::setAccount(const AccountGroup &_account, const TQString _id) { if(_account.isZero()) { m_accounts.remove(_id); } else { // make sure we store a correct id AccountGroup account(_account); if(account.id() != _id) account.setId(_id); m_accounts[_id] = account; } } const MyMoneyBudget::AccountGroup& MyMoneyBudget::account(const TQString _id) const { static AccountGroup empty; if ( m_accounts.contains(_id) ) return m_accounts[_id]; return empty; } void MyMoneyBudget::setBudgetStart(const TQDate& _start) { TQDate oldDate = TQDate(m_start.year(), m_start.month(), 1); m_start = TQDate(_start.year(), _start.month(), 1); if(oldDate.isValid()) { int adjust = ((m_start.year() - oldDate.year())*12) + (m_start.month() - oldDate.month()); TQMap::iterator it; for(it = m_accounts.begin(); it != m_accounts.end(); ++it) { const TQMap periods = (*it).getPeriods(); TQMap::const_iterator it_per; (*it).clearPeriods(); for(it_per = periods.begin(); it_per != periods.end(); ++it_per) { PeriodGroup pgroup = (*it_per); pgroup.setStartDate(pgroup.startDate().addMonths(adjust)); (*it).addPeriod(pgroup.startDate(), pgroup); } } } }