ledger/filters.h
John Wiegley bbdab79302 Rearranged the code a bit, breaking walk.cc into several different files:
compare         compare_items<T>
  handler         item_handler<T>
  iterators       used to iterators sets of journal objects
  filters         derived from item_handler, they morph the result set
  output          derived from item_handler, these do the printing

Also, created a new 'help' files which contains just Ledger's help text.
2008-08-03 21:38:53 -04:00

702 lines
16 KiB
C++

/*
* Copyright (c) 2003-2008, John Wiegley. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of New Artisans LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FILTERS_H
#define _FILTERS_H
#include "handler.h"
#include "predicate.h"
#include "entry.h"
namespace ledger {
//////////////////////////////////////////////////////////////////////
//
// Transaction filters
//
class ignore_xacts : public item_handler<xact_t>
{
public:
virtual void operator()(xact_t&) {}
};
class clear_xact_xdata : public item_handler<xact_t>
{
public:
virtual void operator()(xact_t& xact) {
xact.clear_xdata();
}
};
class xacts_iterator;
class pass_down_xacts : public item_handler<xact_t>
{
pass_down_xacts();
public:
pass_down_xacts(xact_handler_ptr handler, xacts_iterator& iter);
virtual ~pass_down_xacts() {
TRACE_DTOR(pass_down_xacts);
}
};
class push_to_xacts_list : public item_handler<xact_t>
{
push_to_xacts_list();
public:
xacts_list& xacts;
push_to_xacts_list(xacts_list& _xacts) : xacts(_xacts) {
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) {
xacts.push_back(&xact);
}
};
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) {
if (tail_count == 0 && head_count > 0 &&
xacts.size() >= static_cast<unsigned int>(head_count))
return;
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 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().add_flags(XACT_EXT_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) {
foreach (entry_t& entry, entries_list)
entry.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().add_flags(XACT_EXT_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_date);
last_xact = NULL;
}
item_handler<xact_t>::flush();
}
void output_diff(const date_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:
date_t start;
date_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_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 date_t& moment = date_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().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);
};
class budget_xacts : public generate_xacts
{
#define BUDGET_NO_BUDGET 0x00
#define BUDGET_BUDGETED 0x01
#define BUDGET_UNBUDGETED 0x02
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 date_t& date);
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 filters
//
class clear_account_xdata : public item_handler<account_t>
{
public:
virtual void operator()(account_t& acct) {
acct.clear_xdata();
}
};
class accounts_iterator;
class pass_down_accounts : public item_handler<account_t>
{
pass_down_accounts();
public:
pass_down_accounts(acct_handler_ptr handler, accounts_iterator& iter);
virtual ~pass_down_accounts() {
TRACE_DTOR(pass_down_accounts);
}
};
} // namespace ledger
#endif // _FILTERS_H