1085 lines
25 KiB
C++
1085 lines
25 KiB
C++
#ifndef _WALK_H
|
|
#define _WALK_H
|
|
|
|
#include "journal.h"
|
|
#include "account.h"
|
|
|
|
namespace ledger {
|
|
|
|
template <typename T>
|
|
struct item_handler : public noncopyable
|
|
{
|
|
shared_ptr<item_handler> handler;
|
|
|
|
public:
|
|
item_handler() {
|
|
TRACE_CTOR(item_handler, "");
|
|
}
|
|
item_handler(shared_ptr<item_handler> _handler) : handler(_handler) {
|
|
TRACE_CTOR(item_handler, "shared_ptr<item_handler>");
|
|
}
|
|
virtual ~item_handler() {
|
|
TRACE_DTOR(item_handler);
|
|
}
|
|
|
|
virtual void flush() {
|
|
if (handler.get())
|
|
handler->flush();
|
|
}
|
|
virtual void operator()(T& item) {
|
|
if (handler.get())
|
|
(*handler.get())(item);
|
|
}
|
|
};
|
|
|
|
typedef shared_ptr<item_handler<xact_t> > xact_handler_ptr;
|
|
|
|
template <typename T>
|
|
class compare_items
|
|
{
|
|
expr_t sort_order;
|
|
|
|
compare_items();
|
|
|
|
public:
|
|
compare_items(const compare_items& other) : sort_order(other.sort_order) {
|
|
TRACE_CTOR(compare_items, "copy");
|
|
}
|
|
compare_items(const expr_t& _sort_order) : sort_order(_sort_order) {
|
|
TRACE_CTOR(compare_items, "const value_expr&");
|
|
}
|
|
~compare_items() throw() {
|
|
TRACE_DTOR(compare_items);
|
|
}
|
|
bool operator()(const T * left, const T * right);
|
|
};
|
|
|
|
template <typename T>
|
|
bool compare_items<T>::operator()(const T * left, const T * right)
|
|
{
|
|
assert(left);
|
|
assert(right);
|
|
|
|
value_t left_result;
|
|
value_t right_result;
|
|
#if 0
|
|
sort_order.compute(left_result, details_t(*left));
|
|
sort_order.compute(right_result, details_t(*right));
|
|
#endif
|
|
|
|
return left_result < right_result;
|
|
}
|
|
|
|
template <>
|
|
bool compare_items<xact_t>::operator()(const xact_t * left,
|
|
const xact_t * right);
|
|
template <>
|
|
bool compare_items<account_t>::operator()(const account_t * left,
|
|
const account_t * right);
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Xact handlers
|
|
//
|
|
|
|
#define XACT_RECEIVED 0x0001
|
|
#define XACT_HANDLED 0x0002
|
|
#define XACT_TO_DISPLAY 0x0004
|
|
#define XACT_DISPLAYED 0x0008
|
|
#define XACT_NO_TOTAL 0x0010
|
|
#define XACT_SORT_CALC 0x0020
|
|
#define XACT_COMPOUND 0x0040
|
|
#define XACT_MATCHES 0x0080
|
|
|
|
struct xact_xdata_t : public noncopyable
|
|
{
|
|
value_t total;
|
|
value_t sort_value;
|
|
value_t value;
|
|
unsigned int index;
|
|
unsigned short dflags;
|
|
datetime_t date;
|
|
account_t * account;
|
|
void * ptr;
|
|
|
|
xacts_list * component_xacts;
|
|
|
|
xact_xdata_t()
|
|
: index(0), dflags(0),
|
|
account(NULL), ptr(NULL), component_xacts(NULL) {
|
|
TRACE_CTOR(xact_xdata_t, "");
|
|
}
|
|
~xact_xdata_t() {
|
|
TRACE_DTOR(xact_xdata_t);
|
|
if (component_xacts)
|
|
checked_delete(component_xacts);
|
|
}
|
|
|
|
void remember_xact(xact_t& xact) {
|
|
if (! component_xacts)
|
|
component_xacts = new xacts_list;
|
|
component_xacts->push_back(&xact);
|
|
}
|
|
|
|
bool have_component_xacts() const {
|
|
return component_xacts != NULL && ! component_xacts->empty();
|
|
}
|
|
|
|
void copy_component_xacts(xacts_list& xacts) {
|
|
for (xacts_list::const_iterator i = xacts.begin();
|
|
i != xacts.end();
|
|
i++)
|
|
remember_xact(**i);
|
|
}
|
|
|
|
void walk_component_xacts(item_handler<xact_t>& handler) const {
|
|
for (xacts_list::const_iterator i = component_xacts->begin();
|
|
i != component_xacts->end();
|
|
i++)
|
|
handler(**i);
|
|
}
|
|
};
|
|
|
|
inline bool xact_has_xdata(const xact_t& xact) {
|
|
return xact.data != NULL;
|
|
}
|
|
|
|
inline xact_xdata_t& xact_xdata_(const xact_t& xact) {
|
|
return *((xact_xdata_t *) xact.data);
|
|
}
|
|
|
|
xact_xdata_t& xact_xdata(const xact_t& xact);
|
|
void add_xact_to(const xact_t& xact, value_t& value);
|
|
|
|
inline account_t * xact_account(xact_t& xact) {
|
|
if (xact.data) {
|
|
account_t * account = xact_xdata(xact).account;
|
|
if (account)
|
|
return account;
|
|
}
|
|
return xact.account;
|
|
}
|
|
|
|
inline const account_t * xact_account(const xact_t& xact) {
|
|
return xact_account(const_cast<xact_t&>(xact));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
class entries_iterator : public noncopyable
|
|
{
|
|
ptr_list<journal_t>::iterator journals_i;
|
|
ptr_list<journal_t>::iterator journals_end;
|
|
|
|
bool journals_uninitialized;
|
|
|
|
entries_list::iterator entries_i;
|
|
entries_list::iterator entries_end;
|
|
|
|
bool entries_uninitialized;
|
|
|
|
public:
|
|
entries_iterator()
|
|
: journals_uninitialized(true), entries_uninitialized(true) {
|
|
TRACE_CTOR(entries_iterator, "");
|
|
}
|
|
entries_iterator(session_t& session)
|
|
: journals_uninitialized(true), entries_uninitialized(true) {
|
|
TRACE_CTOR(entries_iterator, "session_t&");
|
|
reset(session);
|
|
}
|
|
~entries_iterator() throw() {
|
|
TRACE_DTOR(entries_iterator);
|
|
}
|
|
|
|
void reset(session_t& session);
|
|
|
|
entry_t * operator()();
|
|
};
|
|
|
|
class xacts_iterator : public noncopyable
|
|
{
|
|
public:
|
|
virtual xact_t * operator()() = 0;
|
|
};
|
|
|
|
class entry_xacts_iterator : public xacts_iterator
|
|
{
|
|
xacts_list::iterator xacts_i;
|
|
xacts_list::iterator xacts_end;
|
|
|
|
bool xacts_uninitialized;
|
|
|
|
public:
|
|
entry_xacts_iterator() : xacts_uninitialized(true) {
|
|
TRACE_CTOR(entry_xacts_iterator, "");
|
|
}
|
|
entry_xacts_iterator(entry_t& entry)
|
|
: xacts_uninitialized(true) {
|
|
TRACE_CTOR(entry_xacts_iterator, "entry_t&");
|
|
reset(entry);
|
|
}
|
|
virtual ~entry_xacts_iterator() throw() {
|
|
TRACE_DTOR(entry_xacts_iterator);
|
|
}
|
|
|
|
void reset(entry_t& entry) {
|
|
xacts_i = entry.xacts.begin();
|
|
xacts_end = entry.xacts.end();
|
|
|
|
xacts_uninitialized = false;
|
|
}
|
|
|
|
virtual xact_t * operator()() {
|
|
if (xacts_i == xacts_end || xacts_uninitialized)
|
|
return NULL;
|
|
return *xacts_i++;
|
|
}
|
|
};
|
|
|
|
class session_xacts_iterator : public xacts_iterator
|
|
{
|
|
entries_iterator entries;
|
|
entry_xacts_iterator xacts;
|
|
|
|
public:
|
|
session_xacts_iterator() {
|
|
TRACE_CTOR(session_xacts_iterator, "");
|
|
}
|
|
session_xacts_iterator(session_t& session) {
|
|
TRACE_CTOR(session_xacts_iterator, "session_t&");
|
|
reset(session);
|
|
}
|
|
virtual ~session_xacts_iterator() throw() {
|
|
TRACE_DTOR(session_xacts_iterator);
|
|
}
|
|
|
|
void reset(session_t& session);
|
|
|
|
virtual xact_t * operator()();
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
class ignore_xacts : public item_handler<xact_t>
|
|
{
|
|
public:
|
|
virtual void operator()(xact_t& xact) {}
|
|
};
|
|
|
|
class clear_xact_xdata : public item_handler<xact_t>
|
|
{
|
|
public:
|
|
virtual void operator()(xact_t& xact) {
|
|
if (xact.data) {
|
|
checked_delete((xact_xdata_t *) xact.data);
|
|
xact.data = NULL;
|
|
}
|
|
}
|
|
};
|
|
|
|
class pass_down_xacts : public item_handler<xact_t>
|
|
{
|
|
pass_down_xacts();
|
|
|
|
public:
|
|
pass_down_xacts(xact_handler_ptr handler,
|
|
xacts_iterator& iter)
|
|
: item_handler<xact_t>(handler) {
|
|
TRACE_CTOR(pass_down_xacts,
|
|
"xact_handler_ptr, xacts_iterator");
|
|
for (xact_t * xact = iter(); xact; xact = iter())
|
|
item_handler<xact_t>::operator()(*xact);
|
|
}
|
|
|
|
virtual ~pass_down_xacts() {
|
|
TRACE_DTOR(pass_down_xacts);
|
|
}
|
|
};
|
|
|
|
class truncate_entries : public item_handler<xact_t>
|
|
{
|
|
int head_count;
|
|
int tail_count;
|
|
|
|
xacts_list xacts;
|
|
|
|
truncate_entries();
|
|
|
|
public:
|
|
truncate_entries(xact_handler_ptr handler,
|
|
int _head_count, int _tail_count)
|
|
: item_handler<xact_t>(handler),
|
|
head_count(_head_count), tail_count(_tail_count) {
|
|
TRACE_CTOR(truncate_entries, "xact_handler_ptr, int, int");
|
|
}
|
|
virtual ~truncate_entries() {
|
|
TRACE_DTOR(truncate_entries);
|
|
}
|
|
|
|
virtual void flush();
|
|
virtual void operator()(xact_t& xact) {
|
|
xacts.push_back(&xact);
|
|
}
|
|
};
|
|
|
|
class set_account_value : public item_handler<xact_t>
|
|
{
|
|
public:
|
|
set_account_value(xact_handler_ptr handler = xact_handler_ptr())
|
|
: item_handler<xact_t>(handler) {}
|
|
|
|
virtual void operator()(xact_t& xact);
|
|
};
|
|
|
|
class push_to_xacts_list : public item_handler<xact_t>
|
|
{
|
|
push_to_xacts_list();
|
|
|
|
public:
|
|
xacts_list& xact_list;
|
|
|
|
push_to_xacts_list(xacts_list& _xact_list)
|
|
: xact_list(_xact_list) {
|
|
TRACE_CTOR(push_to_xacts_list, "xacts_list&");
|
|
}
|
|
virtual ~push_to_xacts_list() {
|
|
TRACE_DTOR(push_to_xacts_list);
|
|
}
|
|
|
|
virtual void operator()(xact_t& xact) {
|
|
xact_list.push_back(&xact);
|
|
}
|
|
};
|
|
|
|
class sort_xacts : public item_handler<xact_t>
|
|
{
|
|
typedef std::deque<xact_t *> xacts_deque;
|
|
|
|
xacts_deque xacts;
|
|
const expr_t sort_order;
|
|
|
|
sort_xacts();
|
|
|
|
public:
|
|
sort_xacts(xact_handler_ptr handler,
|
|
const expr_t& _sort_order)
|
|
: item_handler<xact_t>(handler),
|
|
sort_order(_sort_order) {
|
|
TRACE_CTOR(sort_xacts,
|
|
"xact_handler_ptr, const value_expr&");
|
|
}
|
|
sort_xacts(xact_handler_ptr handler,
|
|
const string& _sort_order)
|
|
: item_handler<xact_t>(handler),
|
|
sort_order(_sort_order) {
|
|
TRACE_CTOR(sort_xacts,
|
|
"xact_handler_ptr, const string&");
|
|
}
|
|
virtual ~sort_xacts() {
|
|
TRACE_DTOR(sort_xacts);
|
|
}
|
|
|
|
virtual void post_accumulated_xacts();
|
|
|
|
virtual void flush() {
|
|
post_accumulated_xacts();
|
|
item_handler<xact_t>::flush();
|
|
}
|
|
|
|
virtual void operator()(xact_t& xact) {
|
|
xacts.push_back(&xact);
|
|
}
|
|
};
|
|
|
|
class sort_entries : public item_handler<xact_t>
|
|
{
|
|
sort_xacts sorter;
|
|
entry_t * last_entry;
|
|
|
|
sort_entries();
|
|
|
|
public:
|
|
sort_entries(xact_handler_ptr handler,
|
|
const expr_t& _sort_order)
|
|
: sorter(handler, _sort_order) {
|
|
TRACE_CTOR(sort_entries,
|
|
"xact_handler_ptr, const value_expr&");
|
|
}
|
|
sort_entries(xact_handler_ptr handler,
|
|
const string& _sort_order)
|
|
: sorter(handler, _sort_order) {
|
|
TRACE_CTOR(sort_entries,
|
|
"xact_handler_ptr, const string&");
|
|
}
|
|
virtual ~sort_entries() {
|
|
TRACE_DTOR(sort_entries);
|
|
}
|
|
|
|
virtual void flush() {
|
|
sorter.flush();
|
|
item_handler<xact_t>::flush();
|
|
}
|
|
|
|
virtual void operator()(xact_t& xact) {
|
|
if (last_entry && xact.entry != last_entry)
|
|
sorter.post_accumulated_xacts();
|
|
|
|
sorter(xact);
|
|
|
|
last_entry = xact.entry;
|
|
}
|
|
};
|
|
|
|
class filter_xacts : public item_handler<xact_t>
|
|
{
|
|
item_predicate<xact_t> pred;
|
|
|
|
filter_xacts();
|
|
|
|
public:
|
|
filter_xacts(xact_handler_ptr handler,
|
|
const expr_t& predicate)
|
|
: item_handler<xact_t>(handler), pred(predicate) {
|
|
TRACE_CTOR(filter_xacts,
|
|
"xact_handler_ptr, const value_expr&");
|
|
}
|
|
|
|
filter_xacts(xact_handler_ptr handler,
|
|
const string& predicate)
|
|
: item_handler<xact_t>(handler), pred(predicate) {
|
|
TRACE_CTOR(filter_xacts,
|
|
"xact_handler_ptr, const string&");
|
|
}
|
|
virtual ~filter_xacts() {
|
|
TRACE_DTOR(filter_xacts);
|
|
}
|
|
|
|
virtual void operator()(xact_t& xact) {
|
|
if (pred(xact)) {
|
|
xact_xdata(xact).dflags |= XACT_MATCHES;
|
|
(*handler)(xact);
|
|
}
|
|
}
|
|
};
|
|
|
|
class calc_xacts : public item_handler<xact_t>
|
|
{
|
|
xact_t * last_xact;
|
|
|
|
calc_xacts();
|
|
|
|
public:
|
|
calc_xacts(xact_handler_ptr handler)
|
|
: item_handler<xact_t>(handler), last_xact(NULL) {
|
|
TRACE_CTOR(calc_xacts, "xact_handler_ptr");
|
|
}
|
|
virtual ~calc_xacts() {
|
|
TRACE_DTOR(calc_xacts);
|
|
}
|
|
|
|
virtual void operator()(xact_t& xact);
|
|
};
|
|
|
|
class invert_xacts : public item_handler<xact_t>
|
|
{
|
|
invert_xacts();
|
|
|
|
public:
|
|
invert_xacts(xact_handler_ptr handler)
|
|
: item_handler<xact_t>(handler) {}
|
|
|
|
virtual void operator()(xact_t& xact);
|
|
};
|
|
|
|
inline void clear_entries_xacts(std::list<entry_t>& entries_list) {
|
|
for (std::list<entry_t>::iterator i = entries_list.begin();
|
|
i != entries_list.end();
|
|
i++)
|
|
(*i).xacts.clear();
|
|
}
|
|
|
|
class collapse_xacts : public item_handler<xact_t>
|
|
{
|
|
value_t subtotal;
|
|
unsigned int count;
|
|
entry_t * last_entry;
|
|
xact_t * last_xact;
|
|
account_t totals_account;
|
|
|
|
std::list<entry_t> entry_temps;
|
|
std::list<xact_t> xact_temps;
|
|
|
|
collapse_xacts();
|
|
|
|
public:
|
|
collapse_xacts(xact_handler_ptr handler)
|
|
: item_handler<xact_t>(handler), count(0),
|
|
last_entry(NULL), last_xact(NULL),
|
|
totals_account(NULL, "<Total>") {
|
|
TRACE_CTOR(collapse_xacts, "xact_handler_ptr");
|
|
}
|
|
virtual ~collapse_xacts() {
|
|
TRACE_DTOR(collapse_xacts);
|
|
clear_entries_xacts(entry_temps);
|
|
}
|
|
|
|
virtual void flush() {
|
|
if (subtotal)
|
|
report_subtotal();
|
|
item_handler<xact_t>::flush();
|
|
}
|
|
|
|
void report_subtotal();
|
|
|
|
virtual void operator()(xact_t& xact);
|
|
};
|
|
|
|
class component_xacts : public item_handler<xact_t>
|
|
{
|
|
item_predicate<xact_t> pred;
|
|
|
|
component_xacts();
|
|
|
|
public:
|
|
component_xacts(xact_handler_ptr handler,
|
|
const expr_t& predicate)
|
|
: item_handler<xact_t>(handler), pred(predicate) {
|
|
TRACE_CTOR(component_xacts,
|
|
"xact_handler_ptr, const value_expr&");
|
|
}
|
|
component_xacts(xact_handler_ptr handler,
|
|
const string& predicate)
|
|
: item_handler<xact_t>(handler), pred(predicate) {
|
|
TRACE_CTOR(component_xacts,
|
|
"xact_handler_ptr, const string&");
|
|
}
|
|
virtual ~component_xacts() throw() {
|
|
TRACE_DTOR(component_xacts);
|
|
}
|
|
|
|
virtual void operator()(xact_t& xact);
|
|
};
|
|
|
|
class related_xacts : public item_handler<xact_t>
|
|
{
|
|
xacts_list xacts;
|
|
bool also_matching;
|
|
|
|
related_xacts();
|
|
|
|
public:
|
|
related_xacts(xact_handler_ptr handler,
|
|
const bool _also_matching = false)
|
|
: item_handler<xact_t>(handler),
|
|
also_matching(_also_matching) {
|
|
TRACE_CTOR(related_xacts,
|
|
"xact_handler_ptr, const bool");
|
|
}
|
|
virtual ~related_xacts() throw() {
|
|
TRACE_DTOR(related_xacts);
|
|
}
|
|
|
|
virtual void flush();
|
|
virtual void operator()(xact_t& xact) {
|
|
xact_xdata(xact).dflags |= XACT_RECEIVED;
|
|
xacts.push_back(&xact);
|
|
}
|
|
};
|
|
|
|
class changed_value_xacts : public item_handler<xact_t>
|
|
{
|
|
// This filter requires that calc_xacts be used at some point
|
|
// later in the chain.
|
|
|
|
bool changed_values_only;
|
|
xact_t * last_xact;
|
|
value_t last_balance;
|
|
|
|
std::list<entry_t> entry_temps;
|
|
std::list<xact_t> xact_temps;
|
|
|
|
changed_value_xacts();
|
|
|
|
public:
|
|
changed_value_xacts(xact_handler_ptr handler,
|
|
bool _changed_values_only)
|
|
: item_handler<xact_t>(handler),
|
|
changed_values_only(_changed_values_only), last_xact(NULL) {
|
|
TRACE_CTOR(changed_value_xacts,
|
|
"xact_handler_ptr, bool");
|
|
}
|
|
virtual ~changed_value_xacts() {
|
|
TRACE_DTOR(changed_value_xacts);
|
|
clear_entries_xacts(entry_temps);
|
|
}
|
|
|
|
virtual void flush() {
|
|
if (last_xact) {
|
|
output_diff(current_moment);
|
|
last_xact = NULL;
|
|
}
|
|
item_handler<xact_t>::flush();
|
|
}
|
|
|
|
void output_diff(const datetime_t& current);
|
|
|
|
virtual void operator()(xact_t& xact);
|
|
};
|
|
|
|
class subtotal_xacts : public item_handler<xact_t>
|
|
{
|
|
class acct_value_t
|
|
{
|
|
acct_value_t();
|
|
|
|
public:
|
|
account_t * account;
|
|
value_t value;
|
|
|
|
xacts_list components;
|
|
|
|
acct_value_t(account_t * a) : account(a) {
|
|
TRACE_CTOR(acct_value_t, "acount_t *");
|
|
}
|
|
acct_value_t(account_t * a, value_t& v) : account(a), value(v) {
|
|
TRACE_CTOR(acct_value_t, "acount_t *, value_t&");
|
|
}
|
|
acct_value_t(const acct_value_t& av)
|
|
: account(av.account), value(av.value),
|
|
components(av.components) {
|
|
TRACE_CTOR(acct_value_t, "copy");
|
|
}
|
|
~acct_value_t() throw() {
|
|
TRACE_DTOR(acct_value_t);
|
|
}
|
|
};
|
|
|
|
typedef std::map<string, acct_value_t> values_map;
|
|
typedef std::pair<string, acct_value_t> values_pair;
|
|
|
|
subtotal_xacts();
|
|
|
|
protected:
|
|
values_map values;
|
|
bool remember_components;
|
|
|
|
std::list<entry_t> entry_temps;
|
|
std::list<xact_t> xact_temps;
|
|
|
|
public:
|
|
datetime_t start;
|
|
datetime_t finish;
|
|
|
|
subtotal_xacts(xact_handler_ptr handler,
|
|
bool _remember_components = false)
|
|
: item_handler<xact_t>(handler),
|
|
remember_components(_remember_components) {
|
|
TRACE_CTOR(subtotal_xacts,
|
|
"xact_handler_ptr, bool");
|
|
}
|
|
virtual ~subtotal_xacts() {
|
|
TRACE_DTOR(subtotal_xacts);
|
|
clear_entries_xacts(entry_temps);
|
|
}
|
|
|
|
void report_subtotal(const char * spec_fmt = NULL);
|
|
|
|
virtual void flush() {
|
|
if (values.size() > 0)
|
|
report_subtotal();
|
|
item_handler<xact_t>::flush();
|
|
}
|
|
virtual void operator()(xact_t& xact);
|
|
};
|
|
|
|
class interval_expr_error : public error {
|
|
public:
|
|
interval_expr_error(const string& reason,
|
|
error_context * ctxt = NULL) throw()
|
|
: error(reason, ctxt) {}
|
|
virtual ~interval_expr_error() throw() {}
|
|
};
|
|
|
|
class interval_xacts : public subtotal_xacts
|
|
{
|
|
interval_t interval;
|
|
xact_t * last_xact;
|
|
bool started;
|
|
|
|
interval_xacts();
|
|
|
|
public:
|
|
interval_xacts(xact_handler_ptr _handler,
|
|
const interval_t& _interval,
|
|
bool remember_components = false)
|
|
: subtotal_xacts(_handler, remember_components),
|
|
interval(_interval), last_xact(NULL), started(false) {
|
|
TRACE_CTOR(interval_xacts,
|
|
"xact_handler_ptr, const interval_t&, bool");
|
|
}
|
|
interval_xacts(xact_handler_ptr _handler,
|
|
const string& _interval,
|
|
bool remember_components = false)
|
|
: subtotal_xacts(_handler, remember_components),
|
|
interval(_interval), last_xact(NULL), started(false) {
|
|
TRACE_CTOR(interval_xacts,
|
|
"xact_handler_ptr, const string&, bool");
|
|
}
|
|
virtual ~interval_xacts() throw() {
|
|
TRACE_DTOR(interval_xacts);
|
|
}
|
|
|
|
void report_subtotal(const datetime_t& moment = datetime_t());
|
|
|
|
virtual void flush() {
|
|
if (last_xact)
|
|
report_subtotal();
|
|
subtotal_xacts::flush();
|
|
}
|
|
virtual void operator()(xact_t& xact);
|
|
};
|
|
|
|
class by_payee_xacts : public item_handler<xact_t>
|
|
{
|
|
typedef std::map<string, subtotal_xacts *> payee_subtotals_map;
|
|
typedef std::pair<string, subtotal_xacts *> payee_subtotals_pair;
|
|
|
|
payee_subtotals_map payee_subtotals;
|
|
bool remember_components;
|
|
|
|
by_payee_xacts();
|
|
|
|
public:
|
|
by_payee_xacts(xact_handler_ptr handler,
|
|
bool _remember_components = false)
|
|
: item_handler<xact_t>(handler),
|
|
remember_components(_remember_components) {
|
|
TRACE_CTOR(by_payee_xacts,
|
|
"xact_handler_ptr, bool");
|
|
}
|
|
virtual ~by_payee_xacts();
|
|
|
|
virtual void flush();
|
|
virtual void operator()(xact_t& xact);
|
|
};
|
|
|
|
class set_comm_as_payee : public item_handler<xact_t>
|
|
{
|
|
std::list<entry_t> entry_temps;
|
|
std::list<xact_t> xact_temps;
|
|
|
|
set_comm_as_payee();
|
|
|
|
public:
|
|
set_comm_as_payee(xact_handler_ptr handler)
|
|
: item_handler<xact_t>(handler) {
|
|
TRACE_CTOR(set_comm_as_payee, "xact_handler_ptr");
|
|
}
|
|
virtual ~set_comm_as_payee() {
|
|
TRACE_DTOR(set_comm_as_payee);
|
|
clear_entries_xacts(entry_temps);
|
|
}
|
|
|
|
virtual void operator()(xact_t& xact);
|
|
};
|
|
|
|
class set_code_as_payee : public item_handler<xact_t>
|
|
{
|
|
std::list<entry_t> entry_temps;
|
|
std::list<xact_t> xact_temps;
|
|
|
|
set_code_as_payee();
|
|
|
|
public:
|
|
set_code_as_payee(xact_handler_ptr handler)
|
|
: item_handler<xact_t>(handler) {
|
|
TRACE_CTOR(set_code_as_payee, "xact_handler_ptr");
|
|
}
|
|
virtual ~set_code_as_payee() {
|
|
TRACE_DTOR(set_code_as_payee);
|
|
clear_entries_xacts(entry_temps);
|
|
}
|
|
|
|
virtual void operator()(xact_t& xact);
|
|
};
|
|
|
|
class dow_xacts : public subtotal_xacts
|
|
{
|
|
xacts_list days_of_the_week[7];
|
|
|
|
dow_xacts();
|
|
|
|
public:
|
|
dow_xacts(xact_handler_ptr handler,
|
|
bool remember_components = false)
|
|
: subtotal_xacts(handler, remember_components) {
|
|
TRACE_CTOR(dow_xacts, "xact_handler_ptr, bool");
|
|
}
|
|
virtual ~dow_xacts() throw() {
|
|
TRACE_DTOR(dow_xacts);
|
|
}
|
|
|
|
virtual void flush();
|
|
virtual void operator()(xact_t& xact) {
|
|
days_of_the_week[xact.date().date().day_of_week()].push_back(&xact);
|
|
}
|
|
};
|
|
|
|
class generate_xacts : public item_handler<xact_t>
|
|
{
|
|
generate_xacts();
|
|
|
|
protected:
|
|
typedef std::pair<interval_t, xact_t *> pending_xacts_pair;
|
|
typedef std::list<pending_xacts_pair> pending_xacts_list;
|
|
|
|
pending_xacts_list pending_xacts;
|
|
std::list<entry_t> entry_temps;
|
|
std::list<xact_t> xact_temps;
|
|
|
|
public:
|
|
generate_xacts(xact_handler_ptr handler)
|
|
: item_handler<xact_t>(handler) {
|
|
TRACE_CTOR(dow_xacts, "xact_handler_ptr");
|
|
}
|
|
|
|
virtual ~generate_xacts() {
|
|
TRACE_DTOR(generate_xacts);
|
|
clear_entries_xacts(entry_temps);
|
|
}
|
|
|
|
void add_period_entries(period_entries_list& period_entries);
|
|
|
|
virtual void add_xact(const interval_t& period, xact_t& xact);
|
|
};
|
|
|
|
#define BUDGET_NO_BUDGET 0x00
|
|
#define BUDGET_BUDGETED 0x01
|
|
#define BUDGET_UNBUDGETED 0x02
|
|
|
|
class budget_xacts : public generate_xacts
|
|
{
|
|
unsigned short flags;
|
|
|
|
budget_xacts();
|
|
|
|
public:
|
|
budget_xacts(xact_handler_ptr handler,
|
|
unsigned long _flags = BUDGET_BUDGETED)
|
|
: generate_xacts(handler), flags(_flags) {
|
|
TRACE_CTOR(budget_xacts,
|
|
"xact_handler_ptr, unsigned long");
|
|
}
|
|
virtual ~budget_xacts() throw() {
|
|
TRACE_DTOR(budget_xacts);
|
|
}
|
|
|
|
void report_budget_items(const datetime_t& moment);
|
|
|
|
virtual void operator()(xact_t& xact);
|
|
};
|
|
|
|
class forecast_xacts : public generate_xacts
|
|
{
|
|
item_predicate<xact_t> pred;
|
|
|
|
public:
|
|
forecast_xacts(xact_handler_ptr handler,
|
|
const expr_t& predicate)
|
|
: generate_xacts(handler), pred(predicate) {
|
|
TRACE_CTOR(forecast_xacts, "xact_handler_ptr, const expr_t&");
|
|
}
|
|
forecast_xacts(xact_handler_ptr handler,
|
|
const string& predicate)
|
|
: generate_xacts(handler), pred(predicate) {
|
|
TRACE_CTOR(forecast_xacts, "xact_handler_ptr, const string&");
|
|
}
|
|
virtual ~forecast_xacts() throw() {
|
|
TRACE_DTOR(forecast_xacts);
|
|
}
|
|
|
|
virtual void add_xact(const interval_t& period,
|
|
xact_t& xact);
|
|
virtual void flush();
|
|
};
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Account walking functions
|
|
//
|
|
|
|
#define ACCOUNT_TO_DISPLAY 0x0001
|
|
#define ACCOUNT_DISPLAYED 0x0002
|
|
#define ACCOUNT_SORT_CALC 0x0004
|
|
#define ACCOUNT_HAS_NON_VIRTUALS 0x0008
|
|
#define ACCOUNT_HAS_UNB_VIRTUALS 0x0010
|
|
|
|
struct account_xdata_t : public noncopyable
|
|
{
|
|
value_t value;
|
|
value_t total;
|
|
value_t sort_value;
|
|
unsigned int count; // xacts counted toward amount
|
|
unsigned int total_count; // xacts counted toward total
|
|
unsigned int virtuals;
|
|
unsigned short dflags;
|
|
|
|
account_xdata_t() : count(0), total_count(0), virtuals(0), dflags(0) {
|
|
TRACE_CTOR(account_xdata_t, "");
|
|
}
|
|
~account_xdata_t() throw() {
|
|
TRACE_DTOR(account_xdata_t);
|
|
}
|
|
};
|
|
|
|
inline bool account_has_xdata(const account_t& account) {
|
|
return account.data != NULL;
|
|
}
|
|
|
|
inline account_xdata_t& account_xdata_(const account_t& account) {
|
|
return *((account_xdata_t *) account.data);
|
|
}
|
|
|
|
account_xdata_t& account_xdata(const account_t& account);
|
|
|
|
void sum_accounts(account_t& account);
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
class accounts_iterator : public noncopyable
|
|
{
|
|
std::list<accounts_map::const_iterator> accounts_i;
|
|
std::list<accounts_map::const_iterator> accounts_end;
|
|
|
|
public:
|
|
accounts_iterator() {
|
|
TRACE_CTOR(accounts_iterator, "");
|
|
}
|
|
accounts_iterator(account_t& account) {
|
|
TRACE_CTOR(accounts_iterator, "account_t&");
|
|
push_back(account);
|
|
}
|
|
virtual ~accounts_iterator() throw() {
|
|
TRACE_DTOR(accounts_iterator);
|
|
}
|
|
|
|
void push_back(account_t& account) {
|
|
accounts_i.push_back(account.accounts.begin());
|
|
accounts_end.push_back(account.accounts.end());
|
|
}
|
|
|
|
virtual account_t * operator()();
|
|
};
|
|
|
|
class sorted_accounts_iterator : public noncopyable
|
|
{
|
|
expr_t sort_cmp;
|
|
|
|
typedef std::deque<account_t *> accounts_deque_t;
|
|
|
|
std::list<accounts_deque_t> accounts_list;
|
|
std::list<accounts_deque_t::const_iterator> sorted_accounts_i;
|
|
std::list<accounts_deque_t::const_iterator> sorted_accounts_end;
|
|
|
|
public:
|
|
sorted_accounts_iterator(const string& sort_order) {
|
|
TRACE_CTOR(sorted_accounts_iterator, "const string&");
|
|
sort_cmp = expr_t(sort_order);
|
|
}
|
|
sorted_accounts_iterator(account_t& account, const string& sort_order) {
|
|
TRACE_CTOR(sorted_accounts_iterator, "account_t&, const string&");
|
|
sort_cmp = expr_t(sort_order);
|
|
push_back(account);
|
|
}
|
|
virtual ~sorted_accounts_iterator() throw() {
|
|
TRACE_DTOR(sorted_accounts_iterator);
|
|
}
|
|
|
|
void sort_accounts(account_t& account, accounts_deque_t& deque);
|
|
|
|
void push_back(account_t& account) {
|
|
accounts_list.push_back(accounts_deque_t());
|
|
sort_accounts(account, accounts_list.back());
|
|
|
|
sorted_accounts_i.push_back(accounts_list.back().begin());
|
|
sorted_accounts_end.push_back(accounts_list.back().end());
|
|
}
|
|
|
|
virtual account_t * operator()();
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
typedef shared_ptr<item_handler<account_t> > acct_handler_ptr;
|
|
|
|
class clear_account_xdata : public item_handler<account_t>
|
|
{
|
|
public:
|
|
virtual void operator()(account_t& acct) {
|
|
if (acct.data) {
|
|
checked_delete((account_xdata_t *) acct.data);
|
|
acct.data = NULL;
|
|
}
|
|
}
|
|
};
|
|
|
|
template <typename Iterator>
|
|
class pass_down_accounts : public item_handler<account_t>
|
|
{
|
|
pass_down_accounts();
|
|
|
|
public:
|
|
pass_down_accounts(acct_handler_ptr handler, Iterator& iter)
|
|
: item_handler<account_t>(handler) {
|
|
TRACE_CTOR(pass_down_accounts,
|
|
"acct_handler_ptr, accounts_iterator");
|
|
for (account_t * account = iter(); account; account = iter())
|
|
item_handler<account_t>::operator()(*account);
|
|
}
|
|
|
|
virtual ~pass_down_accounts() {
|
|
TRACE_DTOR(pass_down_accounts);
|
|
}
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#if 0
|
|
inline void clear_journal_xdata(journal_t& journal) {
|
|
clear_xact_xdata xact_cleaner;
|
|
walk_entries(journal.entries, xact_cleaner);
|
|
|
|
clear_account_xdata acct_cleaner;
|
|
walk_accounts(*journal.master, acct_cleaner);
|
|
}
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
class journals_iterator : public noncopyable
|
|
{
|
|
ptr_list<journal_t>::iterator journals_i;
|
|
ptr_list<journal_t>::iterator journals_end;
|
|
|
|
public:
|
|
journals_iterator() {
|
|
TRACE_CTOR(journals_iterator, "");
|
|
}
|
|
journals_iterator(session_t& session) {
|
|
TRACE_CTOR(journals_iterator, "session_t&");
|
|
reset(session);
|
|
}
|
|
virtual ~journals_iterator() throw() {
|
|
TRACE_DTOR(journals_iterator);
|
|
}
|
|
|
|
void reset(session_t& session);
|
|
|
|
virtual journal_t * operator()();
|
|
};
|
|
|
|
} // namespace ledger
|
|
|
|
#endif // _WALK_H
|