diff options
Diffstat (limited to 'filters.h')
-rw-r--r-- | filters.h | 702 |
1 files changed, 702 insertions, 0 deletions
diff --git a/filters.h b/filters.h new file mode 100644 index 00000000..7f67cbd8 --- /dev/null +++ b/filters.h @@ -0,0 +1,702 @@ +/* + * 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 |