|
|
|
/***************************************************************************
|
|
|
|
mymoneyreport.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 <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// TQt Includes
|
|
|
|
|
|
|
|
#include <tqstring.h>
|
|
|
|
#include <tqdom.h>
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// TDE Includes
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Project Includes
|
|
|
|
|
|
|
|
#include "mymoneyfile.h"
|
|
|
|
#include "mymoneyreport.h"
|
|
|
|
|
|
|
|
const TQStringList MyMoneyReport::kRowTypeText = TQStringList::split ( ",", "none,assetliability,expenseincome,category,topcategory,account,payee,month,week,topaccount,topaccount-account,equitytype,accounttype,institution,budget,budgetactual,schedule,accountinfo,accountloaninfo,accountreconcile,cashflow", true );
|
|
|
|
const TQStringList MyMoneyReport::kColumnTypeText = TQStringList::split ( ",", "none,months,bimonths,quarters,4,5,6,weeks,8,9,10,11,years", true );
|
|
|
|
|
|
|
|
// if you add names here, don't forget to update the bitmap for EQueryColumns
|
|
|
|
// and shift the bit for eTQCend one position to the left
|
|
|
|
const TQStringList MyMoneyReport::kQueryColumnsText = TQStringList::split ( ",", "none,number,payee,category,memo,account,reconcileflag,action,shares,price,performance,loan,balance", true );
|
|
|
|
|
|
|
|
const MyMoneyReport::EReportType MyMoneyReport::kTypeArray[] = { eNoReport, ePivotTable, ePivotTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, eQueryTable, ePivotTable, ePivotTable, eInfoTable, eInfoTable, eInfoTable, eQueryTable, eQueryTable, eNoReport };
|
|
|
|
const TQStringList MyMoneyReport::kDetailLevelText = TQStringList::split ( ",", "none,all,top,group,total,invalid", true );
|
|
|
|
const TQStringList MyMoneyReport::kChartTypeText = TQStringList::split ( ",", "none,line,bar,pie,ring,stackedbar,invalid", true );
|
|
|
|
|
|
|
|
// This should live in mymoney/mymoneytransactionfilter.h
|
|
|
|
static const TQStringList kTypeText = TQStringList::split ( ",", "all,payments,deposits,transfers,none" );
|
|
|
|
static const TQStringList kStateText = TQStringList::split ( ",", "all,notreconciled,cleared,reconciled,frozen,none" );
|
|
|
|
static const TQStringList kDateLockText = TQStringList::split ( ",", "alldates,untiltoday,currentmonth,currentyear,monthtodate,yeartodate,yeartomonth,lastmonth,lastyear,last7days,last30days,last3months,last6months,last12months,next7days,next30days,next3months,next6months,next12months,userdefined,last3tonext3months,last11Months,currentQuarter,lastQuarter,nextQuarter,currentFiscalYear,lastFiscalYear,today" );
|
|
|
|
static const TQStringList kAccountTypeText = TQStringList::split ( ",", "unknown,checkings,savings,cash,creditcard,loan,certificatedep,investment,moneymarket,asset,liability,currency,income,expense,assetloan,stock,equity,invalid" );
|
|
|
|
|
|
|
|
MyMoneyReport::MyMoneyReport() :
|
|
|
|
m_name ( "Unconfigured Pivot Table Report" ),
|
|
|
|
m_detailLevel ( eDetailNone ),
|
|
|
|
m_convertCurrency ( true ),
|
|
|
|
m_favorite ( false ),
|
|
|
|
m_tax ( false ),
|
|
|
|
m_investments ( false ),
|
|
|
|
m_loans ( false ),
|
|
|
|
m_reportType ( kTypeArray[eExpenseIncome] ),
|
|
|
|
m_rowType ( eExpenseIncome ),
|
|
|
|
m_columnType ( eMonths ),
|
|
|
|
m_columnsAreDays ( false ),
|
|
|
|
m_queryColumns ( eTQCnone ),
|
|
|
|
m_dateLock ( userDefined ),
|
|
|
|
m_accountGroupFilter ( false ),
|
|
|
|
m_chartType ( eChartLine ),
|
|
|
|
m_chartDataLabels ( true ),
|
|
|
|
m_chartGridLines ( true ),
|
|
|
|
m_chartByDefault ( false ),
|
|
|
|
m_chartLineWidth ( 2 ),
|
|
|
|
m_includeSchedules ( false ),
|
|
|
|
m_includeTransfers ( false ),
|
|
|
|
m_includeBudgetActuals ( false ),
|
|
|
|
m_includeUnusedAccounts ( false ),
|
|
|
|
m_showRowTotals ( false ),
|
|
|
|
m_includeForecast ( false ),
|
|
|
|
m_includeMovingAverage ( false ),
|
|
|
|
m_includePrice ( false ),
|
|
|
|
m_includeAveragePrice ( false )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
MyMoneyReport::MyMoneyReport ( const TQString& id, const MyMoneyReport& right ) :
|
|
|
|
MyMoneyObject ( id )
|
|
|
|
{
|
|
|
|
*this = right;
|
|
|
|
setId ( id );
|
|
|
|
}
|
|
|
|
|
|
|
|
MyMoneyReport::MyMoneyReport ( ERowType _rt, unsigned _ct, dateOptionE _dl, EDetailLevel _ss, const TQString& _name, const TQString& _comment ) :
|
|
|
|
m_name ( _name ),
|
|
|
|
m_comment ( _comment ),
|
|
|
|
m_detailLevel ( _ss ),
|
|
|
|
m_convertCurrency ( true ),
|
|
|
|
m_favorite ( false ),
|
|
|
|
m_tax ( false ),
|
|
|
|
m_investments ( false ),
|
|
|
|
m_loans ( false ),
|
|
|
|
m_reportType ( kTypeArray[_rt] ),
|
|
|
|
m_rowType ( _rt ),
|
|
|
|
m_columnsAreDays ( false ),
|
|
|
|
m_dateLock ( _dl ),
|
|
|
|
m_accountGroupFilter ( false ),
|
|
|
|
m_chartType ( eChartLine ),
|
|
|
|
m_chartDataLabels ( true ),
|
|
|
|
m_chartGridLines ( true ),
|
|
|
|
m_chartByDefault ( false ),
|
|
|
|
m_chartLineWidth ( 2 ),
|
|
|
|
m_includeSchedules ( false ),
|
|
|
|
m_includeTransfers ( false ),
|
|
|
|
m_includeBudgetActuals ( false ),
|
|
|
|
m_includeUnusedAccounts ( false ),
|
|
|
|
m_showRowTotals ( false ),
|
|
|
|
m_includeForecast ( false ),
|
|
|
|
m_includeMovingAverage ( false ),
|
|
|
|
m_includePrice ( false ),
|
|
|
|
m_includeAveragePrice ( false )
|
|
|
|
{
|
|
|
|
if ( m_reportType == ePivotTable )
|
|
|
|
m_columnType = static_cast<EColumnType> ( _ct );
|
|
|
|
if ( m_reportType == eQueryTable )
|
|
|
|
m_queryColumns = static_cast<EQueryColumns> ( _ct );
|
|
|
|
setDateFilter ( _dl );
|
|
|
|
|
|
|
|
if ( ( _rt > static_cast<ERowType> ( sizeof ( kTypeArray ) / sizeof ( kTypeArray[0] ) ) )
|
|
|
|
|| ( m_reportType == eNoReport ) )
|
|
|
|
throw new MYMONEYEXCEPTION ( "Invalid report type" );
|
|
|
|
|
|
|
|
if ( _rt == MyMoneyReport::eAssetLiability )
|
|
|
|
{
|
|
|
|
addAccountGroup ( MyMoneyAccount::Asset );
|
|
|
|
addAccountGroup ( MyMoneyAccount::Liability );
|
|
|
|
m_showRowTotals = true;
|
|
|
|
}
|
|
|
|
if ( _rt == MyMoneyReport::eExpenseIncome )
|
|
|
|
{
|
|
|
|
addAccountGroup ( MyMoneyAccount::Expense );
|
|
|
|
addAccountGroup ( MyMoneyAccount::Income );
|
|
|
|
m_showRowTotals = true;
|
|
|
|
}
|
|
|
|
//FIXME take this out once we have sorted out all issues regarding budget of assets and liabilities -- asoliverez@gmail.com
|
|
|
|
if ( _rt == MyMoneyReport::eBudget || _rt == MyMoneyReport::eBudgetActual )
|
|
|
|
{
|
|
|
|
addAccountGroup ( MyMoneyAccount::Expense );
|
|
|
|
addAccountGroup ( MyMoneyAccount::Income );
|
|
|
|
}
|
|
|
|
if ( _rt == MyMoneyReport::eAccountInfo )
|
|
|
|
{
|
|
|
|
addAccountGroup ( MyMoneyAccount::Asset );
|
|
|
|
addAccountGroup ( MyMoneyAccount::Liability );
|
|
|
|
}
|
|
|
|
//cash flow reports show splits for all account groups
|
|
|
|
if ( _rt == MyMoneyReport::eCashFlow )
|
|
|
|
{
|
|
|
|
addAccountGroup ( MyMoneyAccount::Expense );
|
|
|
|
addAccountGroup ( MyMoneyAccount::Income );
|
|
|
|
addAccountGroup ( MyMoneyAccount::Asset );
|
|
|
|
addAccountGroup ( MyMoneyAccount::Liability );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MyMoneyReport::MyMoneyReport ( const TQDomElement& node ) :
|
|
|
|
MyMoneyObject ( node )
|
|
|
|
{
|
|
|
|
if ( !read ( node ) )
|
|
|
|
clearId();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MyMoneyReport::clear ( void )
|
|
|
|
{
|
|
|
|
m_accountGroupFilter = false;
|
|
|
|
m_accountGroups.clear();
|
|
|
|
|
|
|
|
MyMoneyTransactionFilter::clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MyMoneyReport::validDateRange ( TQDate& _db, TQDate& _de )
|
|
|
|
{
|
|
|
|
_db = fromDate();
|
|
|
|
_de = toDate();
|
|
|
|
|
|
|
|
// if either begin or end date are invalid we have one of the following
|
|
|
|
// possible date filters:
|
|
|
|
//
|
|
|
|
// a) begin date not set - first transaction until given end date
|
|
|
|
// b) end date not set - from given date until last transaction
|
|
|
|
// c) both not set - first transaction until last transaction
|
|
|
|
//
|
|
|
|
// If there is no transaction in the engine at all, we use the current
|
|
|
|
// year as the filter criteria.
|
|
|
|
|
|
|
|
if ( !_db.isValid() || !_de.isValid() ) {
|
|
|
|
TQValueList<MyMoneyTransaction> list = MyMoneyFile::instance()->transactionList ( *this );
|
|
|
|
TQDate tmpBegin, tmpEnd;
|
|
|
|
|
|
|
|
if ( !list.isEmpty() ) {
|
|
|
|
qHeapSort ( list );
|
|
|
|
tmpBegin = list.front().postDate();
|
|
|
|
tmpEnd = list.back().postDate();
|
|
|
|
} else {
|
|
|
|
tmpBegin = TQDate ( TQDate::currentDate().year(), 1, 1 ); // the first date in the file
|
|
|
|
tmpEnd = TQDate ( TQDate::currentDate().year(), 12, 31 );// the last date in the file
|
|
|
|
}
|
|
|
|
if ( !_db.isValid() )
|
|
|
|
_db = tmpBegin;
|
|
|
|
if ( !_de.isValid() )
|
|
|
|
_de = tmpEnd;
|
|
|
|
}
|
|
|
|
if ( _db > _de )
|
|
|
|
_db = _de;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MyMoneyReport::setRowType ( ERowType _rt )
|
|
|
|
{
|
|
|
|
m_rowType = _rt;
|
|
|
|
m_reportType = kTypeArray[_rt];
|
|
|
|
|
|
|
|
m_accountGroupFilter = false;
|
|
|
|
m_accountGroups.clear();
|
|
|
|
|
|
|
|
if ( _rt == MyMoneyReport::eAssetLiability )
|
|
|
|
{
|
|
|
|
addAccountGroup ( MyMoneyAccount::Asset );
|
|
|
|
addAccountGroup ( MyMoneyAccount::Liability );
|
|
|
|
}
|
|
|
|
if ( _rt == MyMoneyReport::eExpenseIncome )
|
|
|
|
{
|
|
|
|
addAccountGroup ( MyMoneyAccount::Expense );
|
|
|
|
addAccountGroup ( MyMoneyAccount::Income );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MyMoneyReport::accountGroups(TQValueList<MyMoneyAccount::accountTypeE>& list) const
|
|
|
|
|
|
|
|
{
|
|
|
|
bool result = m_accountGroupFilter;
|
|
|
|
|
|
|
|
if ( result )
|
|
|
|
{
|
|
|
|
TQValueList<MyMoneyAccount::accountTypeE>::const_iterator it_group = m_accountGroups.begin();
|
|
|
|
while ( it_group != m_accountGroups.end() )
|
|
|
|
{
|
|
|
|
list += ( *it_group );
|
|
|
|
++it_group;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MyMoneyReport::addAccountGroup ( MyMoneyAccount::accountTypeE type )
|
|
|
|
{
|
|
|
|
if ( !m_accountGroups.isEmpty() && type != MyMoneyAccount::UnknownAccountType ) {
|
|
|
|
if ( m_accountGroups.contains ( type ) )
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_accountGroupFilter = true;
|
|
|
|
if ( type != MyMoneyAccount::UnknownAccountType )
|
|
|
|
m_accountGroups.push_back ( type );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MyMoneyReport::includesAccountGroup( MyMoneyAccount::accountTypeE type ) const
|
|
|
|
{
|
|
|
|
bool result = ( ! m_accountGroupFilter )
|
|
|
|
|| ( isIncludingTransfers() && m_rowType == MyMoneyReport::eExpenseIncome )
|
|
|
|
|| m_accountGroups.contains ( type );
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MyMoneyReport::includes( const MyMoneyAccount& acc ) const
|
|
|
|
{
|
|
|
|
bool result = false;
|
|
|
|
|
|
|
|
if ( includesAccountGroup ( acc.accountGroup() ) )
|
|
|
|
{
|
|
|
|
switch ( acc.accountGroup() )
|
|
|
|
{
|
|
|
|
case MyMoneyAccount::Income:
|
|
|
|
case MyMoneyAccount::Expense:
|
|
|
|
if ( isTax() )
|
|
|
|
result = ( acc.value ( "Tax" ) == "Yes" ) && includesCategory ( acc.id() );
|
|
|
|
else
|
|
|
|
result = includesCategory ( acc.id() );
|
|
|
|
break;
|
|
|
|
case MyMoneyAccount::Asset:
|
|
|
|
case MyMoneyAccount::Liability:
|
|
|
|
if ( isLoansOnly() )
|
|
|
|
result = acc.isLoan() && includesAccount ( acc.id() );
|
|
|
|
else if ( isInvestmentsOnly() )
|
|
|
|
result = acc.isInvest() && includesAccount ( acc.id() );
|
|
|
|
else if ( isIncludingTransfers() && m_rowType == MyMoneyReport::eExpenseIncome )
|
|
|
|
// If transfers are included, ONLY include this account if it is NOT
|
|
|
|
// included in the report itself!!
|
|
|
|
result = ! includesAccount ( acc.id() );
|
|
|
|
else
|
|
|
|
result = includesAccount ( acc.id() );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
result = includesAccount ( acc.id() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MyMoneyReport::write ( TQDomElement& e, TQDomDocument *doc, bool anonymous ) const
|
|
|
|
{
|
|
|
|
// No matter what changes, be sure to have a 'type' attribute. Only change
|
|
|
|
// the major type if it becomes impossible to maintain compatability with
|
|
|
|
// older versions of the program as new features are added to the reports.
|
|
|
|
// Feel free to change the minor type every time a change is made here.
|
|
|
|
|
|
|
|
writeBaseXML ( *doc, e );
|
|
|
|
|
|
|
|
if ( anonymous )
|
|
|
|
{
|
|
|
|
e.setAttribute ( "name", m_id );
|
|
|
|
e.setAttribute ( "comment", TQString ( m_comment ).fill ( 'x' ) );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
e.setAttribute ( "name", m_name );
|
|
|
|
e.setAttribute ( "comment", m_comment );
|
|
|
|
}
|
|
|
|
e.setAttribute ( "group", m_group );
|
|
|
|
e.setAttribute ( "convertcurrency", m_convertCurrency );
|
|
|
|
e.setAttribute ( "favorite", m_favorite );
|
|
|
|
e.setAttribute ( "tax", m_tax );
|
|
|
|
e.setAttribute ( "investments", m_investments );
|
|
|
|
e.setAttribute ( "loans", m_loans );
|
|
|
|
e.setAttribute ( "rowtype", kRowTypeText[m_rowType] );
|
|
|
|
e.setAttribute ( "datelock", kDateLockText[m_dateLock] );
|
|
|
|
e.setAttribute ( "includeschedules", m_includeSchedules );
|
|
|
|
e.setAttribute ( "columnsaredays", m_columnsAreDays );
|
|
|
|
e.setAttribute ( "includestransfers", m_includeTransfers );
|
|
|
|
if ( !m_budgetId.isEmpty() )
|
|
|
|
e.setAttribute ( "budget", m_budgetId );
|
|
|
|
e.setAttribute ( "includesactuals", m_includeBudgetActuals );
|
|
|
|
e.setAttribute ( "includeunused", m_includeUnusedAccounts );
|
|
|
|
e.setAttribute ( "includesforecast", m_includeForecast );
|
|
|
|
e.setAttribute ( "includesprice", m_includePrice );
|
|
|
|
e.setAttribute ( "includesaverageprice", m_includeAveragePrice );
|
|
|
|
e.setAttribute ( "includesmovingaverage", m_includeMovingAverage );
|
|
|
|
if( m_includeMovingAverage )
|
|
|
|
e.setAttribute ( "movingaveragedays", m_movingAverageDays );
|
|
|
|
|
|
|
|
e.setAttribute ( "charttype", kChartTypeText[m_chartType] );
|
|
|
|
e.setAttribute ( "chartdatalabels", m_chartDataLabels );
|
|
|
|
e.setAttribute ( "chartgridlines", m_chartGridLines );
|
|
|
|
e.setAttribute ( "chartbydefault", m_chartByDefault );
|
|
|
|
e.setAttribute ( "chartlinewidth", m_chartLineWidth );
|
|
|
|
|
|
|
|
if ( m_reportType == ePivotTable )
|
|
|
|
{
|
|
|
|
e.setAttribute ( "type", "pivottable 1.15" );
|
|
|
|
e.setAttribute ( "detail", kDetailLevelText[m_detailLevel] );
|
|
|
|
e.setAttribute ( "columntype", kColumnTypeText[m_columnType] );
|
|
|
|
e.setAttribute ( "showrowtotals", m_showRowTotals );
|
|
|
|
}
|
|
|
|
else if ( m_reportType == eQueryTable )
|
|
|
|
{
|
|
|
|
e.setAttribute ( "type", "querytable 1.14" );
|
|
|
|
|
|
|
|
TQStringList columns;
|
|
|
|
unsigned qc = m_queryColumns;
|
|
|
|
unsigned it_qc = eTQCbegin;
|
|
|
|
unsigned index = 1;
|
|
|
|
while ( it_qc != eTQCend )
|
|
|
|
{
|
|
|
|
if ( qc & it_qc )
|
|
|
|
columns += kQueryColumnsText[index];
|
|
|
|
it_qc *= 2;
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
e.setAttribute ( "querycolumns", columns.join ( "," ) );
|
|
|
|
}
|
|
|
|
else if ( m_reportType == eInfoTable )
|
|
|
|
{
|
|
|
|
e.setAttribute ( "type", "infotable 1.0" );
|
|
|
|
e.setAttribute ( "detail", kDetailLevelText[m_detailLevel] );
|
|
|
|
e.setAttribute ( "showrowtotals", m_showRowTotals );
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Text Filter
|
|
|
|
//
|
|
|
|
|
|
|
|
TQRegExp textfilter;
|
|
|
|
if ( textFilter ( textfilter ) )
|
|
|
|
{
|
|
|
|
TQDomElement f = doc->createElement ( "TEXT" );
|
|
|
|
f.setAttribute ( "pattern", textfilter.pattern() );
|
|
|
|
f.setAttribute ( "casesensitive", textfilter.caseSensitive() );
|
|
|
|
f.setAttribute ( "regex", !textfilter.wildcard() );
|
|
|
|
f.setAttribute ( "inverttext", m_invertText );
|
|
|
|
e.appendChild ( f );
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Type & State Filters
|
|
|
|
//
|
|
|
|
TQValueList<int> typelist;
|
|
|
|
if ( types ( typelist ) && ! typelist.empty() )
|
|
|
|
{
|
|
|
|
// iterate over payees, and add each one
|
|
|
|
TQValueList<int>::const_iterator it_type = typelist.begin();
|
|
|
|
while ( it_type != typelist.end() )
|
|
|
|
{
|
|
|
|
TQDomElement p = doc->createElement ( "TYPE" );
|
|
|
|
p.setAttribute ( "type", kTypeText[*it_type] );
|
|
|
|
e.appendChild ( p );
|
|
|
|
|
|
|
|
++it_type;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQValueList<int> statelist;
|
|
|
|
if ( states ( statelist ) && ! statelist.empty() )
|
|
|
|
{
|
|
|
|
// iterate over payees, and add each one
|
|
|
|
TQValueList<int>::const_iterator it_state = statelist.begin();
|
|
|
|
while ( it_state != statelist.end() )
|
|
|
|
{
|
|
|
|
TQDomElement p = doc->createElement ( "STATE" );
|
|
|
|
p.setAttribute ( "state", kStateText[*it_state] );
|
|
|
|
e.appendChild ( p );
|
|
|
|
|
|
|
|
++it_state;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// Number Filter
|
|
|
|
//
|
|
|
|
|
|
|
|
TQString nrFrom, nrTo;
|
|
|
|
if ( numberFilter ( nrFrom, nrTo ) )
|
|
|
|
{
|
|
|
|
TQDomElement f = doc->createElement ( "NUMBER" );
|
|
|
|
f.setAttribute ( "from", nrFrom );
|
|
|
|
f.setAttribute ( "to", nrTo );
|
|
|
|
e.appendChild ( f );
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Amount Filter
|
|
|
|
//
|
|
|
|
|
|
|
|
MyMoneyMoney from, to;
|
|
|
|
if ( amountFilter ( from, to ) ) // bool getAmountFilter(MyMoneyMoney&,MyMoneyMoney&);
|
|
|
|
{
|
|
|
|
TQDomElement f = doc->createElement ( "AMOUNT" );
|
|
|
|
f.setAttribute ( "from", from.toString() );
|
|
|
|
f.setAttribute ( "to", to.toString() );
|
|
|
|
e.appendChild ( f );
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Payees Filter
|
|
|
|
//
|
|
|
|
|
|
|
|
TQStringList payeelist;
|
|
|
|
if ( payees ( payeelist ) )
|
|
|
|
{
|
|
|
|
if ( payeelist.empty() )
|
|
|
|
{
|
|
|
|
TQDomElement p = doc->createElement ( "PAYEE" );
|
|
|
|
e.appendChild ( p );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// iterate over payees, and add each one
|
|
|
|
TQStringList::const_iterator it_payee = payeelist.begin();
|
|
|
|
while ( it_payee != payeelist.end() )
|
|
|
|
{
|
|
|
|
TQDomElement p = doc->createElement ( "PAYEE" );
|
|
|
|
p.setAttribute ( "id", *it_payee );
|
|
|
|
e.appendChild ( p );
|
|
|
|
|
|
|
|
++it_payee;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Account Groups Filter
|
|
|
|
//
|
|
|
|
|
|
|
|
TQValueList<MyMoneyAccount::accountTypeE> accountgrouplist;
|
|
|
|
if ( accountGroups ( accountgrouplist ) )
|
|
|
|
{
|
|
|
|
// iterate over accounts, and add each one
|
|
|
|
TQValueList<MyMoneyAccount::accountTypeE>::const_iterator it_group = accountgrouplist.begin();
|
|
|
|
while ( it_group != accountgrouplist.end() )
|
|
|
|
{
|
|
|
|
TQDomElement p = doc->createElement ( "ACCOUNTGROUP" );
|
|
|
|
p.setAttribute ( "group", kAccountTypeText[*it_group] );
|
|
|
|
e.appendChild ( p );
|
|
|
|
|
|
|
|
++it_group;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Accounts Filter
|
|
|
|
//
|
|
|
|
|
|
|
|
TQStringList accountlist;
|
|
|
|
if ( accounts ( accountlist ) )
|
|
|
|
{
|
|
|
|
// iterate over accounts, and add each one
|
|
|
|
TQStringList::const_iterator it_account = accountlist.begin();
|
|
|
|
while ( it_account != accountlist.end() )
|
|
|
|
{
|
|
|
|
TQDomElement p = doc->createElement ( "ACCOUNT" );
|
|
|
|
p.setAttribute ( "id", *it_account );
|
|
|
|
e.appendChild ( p );
|
|
|
|
|
|
|
|
++it_account;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Categories Filter
|
|
|
|
//
|
|
|
|
|
|
|
|
accountlist.clear();
|
|
|
|
if ( categories ( accountlist ) )
|
|
|
|
{
|
|
|
|
// iterate over accounts, and add each one
|
|
|
|
TQStringList::const_iterator it_account = accountlist.begin();
|
|
|
|
while ( it_account != accountlist.end() )
|
|
|
|
{
|
|
|
|
TQDomElement p = doc->createElement ( "CATEGORY" );
|
|
|
|
p.setAttribute ( "id", *it_account );
|
|
|
|
e.appendChild ( p );
|
|
|
|
|
|
|
|
++it_account;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Date Filter
|
|
|
|
//
|
|
|
|
|
|
|
|
if ( m_dateLock == userDefined )
|
|
|
|
{
|
|
|
|
TQDate dateFrom, dateTo;
|
|
|
|
if ( dateFilter ( dateFrom, dateTo ) )
|
|
|
|
{
|
|
|
|
TQDomElement f = doc->createElement ( "DATES" );
|
|
|
|
if ( dateFrom.isValid() )
|
|
|
|
f.setAttribute ( "from", dateFrom.toString ( TQt::ISODate ) );
|
|
|
|
if ( dateTo.isValid() )
|
|
|
|
f.setAttribute ( "to", dateTo.toString ( TQt::ISODate ) );
|
|
|
|
e.appendChild ( f );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MyMoneyReport::read ( const TQDomElement& e )
|
|
|
|
{
|
|
|
|
// The goal of this reading method is 100% backward AND 100% forward
|
|
|
|
// compatability. Any report ever created with any version of KMyMoney
|
|
|
|
// should be able to be loaded by this method (as long as it's one of the
|
|
|
|
// report types supported in this version, of course)
|
|
|
|
|
|
|
|
bool result = false;
|
|
|
|
|
|
|
|
if (
|
|
|
|
"REPORT" == e.tagName()
|
|
|
|
&&
|
|
|
|
(
|
|
|
|
( e.attribute ( "type" ).find ( "pivottable 1." ) == 0 )
|
|
|
|
||
|
|
|
|
( e.attribute ( "type" ).find ( "querytable 1." ) == 0 )
|
|
|
|
||
|
|
|
|
( e.attribute ( "type" ).find ( "infotable 1." ) == 0 )
|
|
|
|
)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
result = true;
|
|
|
|
clear();
|
|
|
|
|
|
|
|
int i;
|
|
|
|
m_name = e.attribute ( "name" );
|
|
|
|
m_comment = e.attribute ( "comment", "Extremely old report" );
|
|
|
|
|
|
|
|
//set report type
|
|
|
|
if(!e.attribute ( "type" ).find ( "pivottable" )) {
|
|
|
|
m_reportType = MyMoneyReport::ePivotTable;
|
|
|
|
} else if(!e.attribute ( "type" ).find ( "querytable" )) {
|
|
|
|
m_reportType = MyMoneyReport::eQueryTable;
|
|
|
|
} else if(!e.attribute ( "type" ).find ( "infotable" )) {
|
|
|
|
m_reportType = MyMoneyReport::eInfoTable;
|
|
|
|
} else {
|
|
|
|
m_reportType = MyMoneyReport::eNoReport;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Removed the line that screened out loading reports that are called
|
|
|
|
// "Default Report". It's possible for the user to change the comment
|
|
|
|
// to this, and we'd hate for it to break as a result.
|
|
|
|
m_group = e.attribute ( "group" );
|
|
|
|
m_id = e.attribute ( "id" );
|
|
|
|
|
|
|
|
//check for reports with older settings which didn't have the detail attribute
|
|
|
|
if ( e.hasAttribute ( "detail" ) )
|
|
|
|
{
|
|
|
|
i = kDetailLevelText.findIndex ( e.attribute ( "detail", "all" ) );
|
|
|
|
if ( i != -1 )
|
|
|
|
m_detailLevel = static_cast<EDetailLevel> ( i );
|
|
|
|
} else if ( e.attribute ( "showsubaccounts", "0" ).toUInt() ) {
|
|
|
|
//set to show all accounts
|
|
|
|
m_detailLevel = eDetailAll;
|
|
|
|
} else {
|
|
|
|
//set to show the top level account instead
|
|
|
|
m_detailLevel = eDetailTop;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_convertCurrency = e.attribute ( "convertcurrency", "1" ).toUInt();
|
|
|
|
m_favorite = e.attribute ( "favorite", "0" ).toUInt();
|
|
|
|
m_tax = e.attribute ( "tax", "0" ).toUInt();
|
|
|
|
m_investments = e.attribute ( "investments", "0" ).toUInt();
|
|
|
|
m_loans = e.attribute ( "loans", "0" ).toUInt();
|
|
|
|
m_includeSchedules = e.attribute ( "includeschedules", "0" ).toUInt();
|
|
|
|
m_columnsAreDays = e.attribute ( "columnsaredays", "0" ).toUInt();
|
|
|
|
m_includeTransfers = e.attribute ( "includestransfers", "0" ).toUInt();
|
|
|
|
if ( e.hasAttribute ( "budget" ) )
|
|
|
|
m_budgetId = e.attribute ( "budget" );
|
|
|
|
m_includeBudgetActuals = e.attribute ( "includesactuals", "0" ).toUInt();
|
|
|
|
m_includeUnusedAccounts = e.attribute ( "includeunused", "0" ).toUInt();
|
|
|
|
m_includeForecast = e.attribute ( "includesforecast", "0" ).toUInt();
|
|
|
|
m_includePrice = e.attribute ( "includesprice", "0" ).toUInt();
|
|
|
|
m_includeAveragePrice = e.attribute ( "includesaverageprice", "0" ).toUInt();
|
|
|
|
m_includeMovingAverage = e.attribute ( "includesmovingaverage", "0" ).toUInt();
|
|
|
|
if( m_includeMovingAverage )
|
|
|
|
m_movingAverageDays = e.attribute ( "movingaveragedays", "1" ).toUInt();
|
|
|
|
|
|
|
|
//only load chart data if it is a pivot table
|
|
|
|
if ( m_reportType == ePivotTable ) {
|
|
|
|
i = kChartTypeText.findIndex ( e.attribute ( "charttype" ) );
|
|
|
|
|
|
|
|
if ( i != -1 )
|
|
|
|
m_chartType = static_cast<EChartType> ( i );
|
|
|
|
|
|
|
|
//if it is invalid, set to first type
|
|
|
|
if (m_chartType == eChartEnd)
|
|
|
|
m_chartType = eChartLine;
|
|
|
|
|
|
|
|
m_chartDataLabels = e.attribute ( "chartdatalabels", "1" ).toUInt();
|
|
|
|
m_chartGridLines = e.attribute ( "chartgridlines", "1" ).toUInt();
|
|
|
|
m_chartByDefault = e.attribute ( "chartbydefault", "0" ).toUInt();
|
|
|
|
m_chartLineWidth = e.attribute ( "chartlinewidth", "2" ).toUInt();
|
|
|
|
} else {
|
|
|
|
m_chartType = static_cast<EChartType> ( 0 );
|
|
|
|
m_chartDataLabels = true;
|
|
|
|
m_chartGridLines = true;
|
|
|
|
m_chartByDefault = false;
|
|
|
|
m_chartLineWidth = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString datelockstr = e.attribute ( "datelock", "userdefined" );
|
|
|
|
// Handle the pivot 1.2/query 1.1 case where the values were saved as
|
|
|
|
// numbers
|
|
|
|
bool ok = false;
|
|
|
|
i = datelockstr.toUInt ( &ok );
|
|
|
|
if ( !ok )
|
|
|
|
{
|
|
|
|
i = kDateLockText.findIndex ( datelockstr );
|
|
|
|
if ( i == -1 )
|
|
|
|
i = userDefined;
|
|
|
|
}
|
|
|
|
setDateFilter ( static_cast<dateOptionE> ( i ) );
|
|
|
|
|
|
|
|
i = kRowTypeText.findIndex ( e.attribute ( "rowtype", "expenseincome" ) );
|
|
|
|
if ( i != -1 )
|
|
|
|
{
|
|
|
|
setRowType ( static_cast<ERowType> ( i ) );
|
|
|
|
// recent versions of KMyMoney always showed a total column for
|
|
|
|
// income/expense reports. We turn it on for backward compatability
|
|
|
|
// here. If the total column is turned off, the flag will be reset
|
|
|
|
// in the next step
|
|
|
|
if ( i == eExpenseIncome )
|
|
|
|
m_showRowTotals = true;
|
|
|
|
}
|
|
|
|
if ( e.hasAttribute ( "showrowtotals" ) )
|
|
|
|
m_showRowTotals = e.attribute ( "showrowtotals" ).toUInt();
|
|
|
|
|
|
|
|
i = kColumnTypeText.findIndex ( e.attribute ( "columntype", "months" ) );
|
|
|
|
if ( i != -1 )
|
|
|
|
setColumnType ( static_cast<EColumnType> ( i ) );
|
|
|
|
|
|
|
|
unsigned qc = 0;
|
|
|
|
TQStringList columns = TQStringList::split ( ",", e.attribute ( "querycolumns", "none" ) );
|
|
|
|
TQStringList::const_iterator it_column = columns.begin();
|
|
|
|
while ( it_column != columns.end() )
|
|
|
|
{
|
|
|
|
i = kQueryColumnsText.findIndex ( *it_column );
|
|
|
|
if ( i > 0 )
|
|
|
|
qc |= ( 1 << ( i - 1 ) );
|
|
|
|
|
|
|
|
++it_column;
|
|
|
|
}
|
|
|
|
setQueryColumns ( static_cast<EQueryColumns> ( qc ) );
|
|
|
|
|
|
|
|
TQDomNode child = e.firstChild();
|
|
|
|
while ( !child.isNull() && child.isElement() )
|
|
|
|
{
|
|
|
|
TQDomElement c = child.toElement();
|
|
|
|
if ( "TEXT" == c.tagName() && c.hasAttribute ( "pattern" ) )
|
|
|
|
{
|
|
|
|
setTextFilter ( TQRegExp ( c.attribute ( "pattern" ), c.attribute ( "casesensitive", "1" ).toUInt(), !c.attribute ( "regex", "1" ).toUInt() ), c.attribute ( "inverttext", "0" ).toUInt() );
|
|
|
|
}
|
|
|
|
if ( "TYPE" == c.tagName() && c.hasAttribute ( "type" ) )
|
|
|
|
{
|
|
|
|
i = kTypeText.findIndex ( c.attribute ( "type" ) );
|
|
|
|
if ( i != -1 )
|
|
|
|
addType ( i );
|
|
|
|
}
|
|
|
|
if ( "STATE" == c.tagName() && c.hasAttribute ( "state" ) )
|
|
|
|
{
|
|
|
|
i = kStateText.findIndex ( c.attribute ( "state" ) );
|
|
|
|
if ( i != -1 )
|
|
|
|
addState ( i );
|
|
|
|
}
|
|
|
|
if ( "NUMBER" == c.tagName() )
|
|
|
|
{
|
|
|
|
setNumberFilter ( c.attribute ( "from" ), c.attribute ( "to" ) );
|
|
|
|
}
|
|
|
|
if ( "AMOUNT" == c.tagName() )
|
|
|
|
{
|
|
|
|
setAmountFilter ( MyMoneyMoney ( c.attribute ( "from", "0/100" ) ), MyMoneyMoney ( c.attribute ( "to", "0/100" ) ) );
|
|
|
|
}
|
|
|
|
if ( "DATES" == c.tagName() )
|
|
|
|
{
|
|
|
|
TQDate from, to;
|
|
|
|
if ( c.hasAttribute ( "from" ) )
|
|
|
|
from = TQDate::fromString ( c.attribute ( "from" ), TQt::ISODate );
|
|
|
|
if ( c.hasAttribute ( "to" ) )
|
|
|
|
to = TQDate::fromString ( c.attribute ( "to" ), TQt::ISODate );
|
|
|
|
MyMoneyTransactionFilter::setDateFilter ( from, to );
|
|
|
|
}
|
|
|
|
if ( "PAYEE" == c.tagName() )
|
|
|
|
{
|
|
|
|
addPayee ( c.attribute ( "id" ) );
|
|
|
|
}
|
|
|
|
if ( "CATEGORY" == c.tagName() && c.hasAttribute ( "id" ) )
|
|
|
|
{
|
|
|
|
addCategory ( c.attribute ( "id" ) );
|
|
|
|
}
|
|
|
|
if ( "ACCOUNT" == c.tagName() && c.hasAttribute ( "id" ) )
|
|
|
|
{
|
|
|
|
addAccount ( c.attribute ( "id" ) );
|
|
|
|
}
|
|
|
|
if ( "ACCOUNTGROUP" == c.tagName() && c.hasAttribute ( "group" ) )
|
|
|
|
{
|
|
|
|
i = kAccountTypeText.findIndex ( c.attribute ( "group" ) );
|
|
|
|
if ( i != -1 )
|
|
|
|
addAccountGroup ( static_cast<MyMoneyAccount::accountTypeE> ( i ) );
|
|
|
|
}
|
|
|
|
child = child.nextSibling();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MyMoneyReport::writeXML ( TQDomDocument& document, TQDomElement& parent ) const
|
|
|
|
{
|
|
|
|
TQDomElement el = document.createElement ( "REPORT" );
|
|
|
|
write ( el, &document, false );
|
|
|
|
parent.appendChild ( el );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MyMoneyReport::hasReferenceTo ( const TQString& id ) const
|
|
|
|
{
|
|
|
|
TQStringList list;
|
|
|
|
|
|
|
|
// collect all ids
|
|
|
|
accounts ( list );
|
|
|
|
categories ( list );
|
|
|
|
payees ( list );
|
|
|
|
|
|
|
|
return ( list.contains ( id ) > 0 );
|
|
|
|
}
|