Allow for sorting of the balance report
Sorting is repeated at each level of the hierarchy, unless --flat was specified in which case it applies to the entire applicable accounts list.
This commit is contained in:
parent
d67c9fee0f
commit
9805abbf2b
6 changed files with 97 additions and 68 deletions
|
|
@ -179,6 +179,33 @@ void sorted_accounts_iterator::sort_accounts(account_t& account,
|
||||||
compare_items<account_t>(sort_cmp));
|
compare_items<account_t>(sort_cmp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sorted_accounts_iterator::push_all(account_t& account)
|
||||||
|
{
|
||||||
|
accounts_deque_t& deque(accounts_list.back());
|
||||||
|
|
||||||
|
foreach (accounts_map::value_type& pair, account.accounts) {
|
||||||
|
deque.push_back(pair.second);
|
||||||
|
push_all(*pair.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sorted_accounts_iterator::push_back(account_t& account)
|
||||||
|
{
|
||||||
|
accounts_list.push_back(accounts_deque_t());
|
||||||
|
|
||||||
|
if (flatten_all) {
|
||||||
|
push_all(account);
|
||||||
|
std::stable_sort(accounts_list.back().begin(),
|
||||||
|
accounts_list.back().end(),
|
||||||
|
compare_items<account_t>(sort_cmp));
|
||||||
|
} else {
|
||||||
|
sort_accounts(account, accounts_list.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
sorted_accounts_i.push_back(accounts_list.back().begin());
|
||||||
|
sorted_accounts_end.push_back(accounts_list.back().end());
|
||||||
|
}
|
||||||
|
|
||||||
account_t * sorted_accounts_iterator::operator()()
|
account_t * sorted_accounts_iterator::operator()()
|
||||||
{
|
{
|
||||||
while (! sorted_accounts_i.empty() &&
|
while (! sorted_accounts_i.empty() &&
|
||||||
|
|
@ -195,9 +222,10 @@ account_t * sorted_accounts_iterator::operator()()
|
||||||
assert(account);
|
assert(account);
|
||||||
|
|
||||||
// If this account has children, queue them up to be iterated next.
|
// If this account has children, queue them up to be iterated next.
|
||||||
if (! account->accounts.empty())
|
if (! flatten_all && ! account->accounts.empty())
|
||||||
push_back(*account);
|
push_back(*account);
|
||||||
|
|
||||||
|
// Make sure the sorting value gets recalculated for this account
|
||||||
account->xdata().drop_flags(ACCOUNT_EXT_SORT_CALC);
|
account->xdata().drop_flags(ACCOUNT_EXT_SORT_CALC);
|
||||||
return account;
|
return account;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -244,6 +244,7 @@ public:
|
||||||
class sorted_accounts_iterator : public accounts_iterator
|
class sorted_accounts_iterator : public accounts_iterator
|
||||||
{
|
{
|
||||||
expr_t sort_cmp;
|
expr_t sort_cmp;
|
||||||
|
bool flatten_all;
|
||||||
|
|
||||||
typedef std::deque<account_t *> accounts_deque_t;
|
typedef std::deque<account_t *> accounts_deque_t;
|
||||||
|
|
||||||
|
|
@ -252,13 +253,14 @@ class sorted_accounts_iterator : public accounts_iterator
|
||||||
std::list<accounts_deque_t::const_iterator> sorted_accounts_end;
|
std::list<accounts_deque_t::const_iterator> sorted_accounts_end;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
sorted_accounts_iterator(const string& sort_order) {
|
sorted_accounts_iterator(const expr_t& _sort_cmp, bool _flatten_all)
|
||||||
TRACE_CTOR(sorted_accounts_iterator, "const string&");
|
: sort_cmp(_sort_cmp), flatten_all(_flatten_all) {
|
||||||
sort_cmp = expr_t(sort_order);
|
TRACE_CTOR(sorted_accounts_iterator, "const expr_t&, bool");
|
||||||
}
|
}
|
||||||
sorted_accounts_iterator(account_t& account, const string& sort_order) {
|
sorted_accounts_iterator(const expr_t& _sort_cmp, bool _flatten_all,
|
||||||
TRACE_CTOR(sorted_accounts_iterator, "account_t&, const string&");
|
account_t& account)
|
||||||
sort_cmp = expr_t(sort_order);
|
: sort_cmp(_sort_cmp), flatten_all(_flatten_all) {
|
||||||
|
TRACE_CTOR(sorted_accounts_iterator, "const expr_t&, bool, account_t&");
|
||||||
push_back(account);
|
push_back(account);
|
||||||
}
|
}
|
||||||
virtual ~sorted_accounts_iterator() throw() {
|
virtual ~sorted_accounts_iterator() throw() {
|
||||||
|
|
@ -266,14 +268,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void sort_accounts(account_t& account, accounts_deque_t& deque);
|
void sort_accounts(account_t& account, accounts_deque_t& deque);
|
||||||
|
void push_all(account_t& account);
|
||||||
void push_back(account_t& account) {
|
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()();
|
virtual account_t * operator()();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -210,12 +210,8 @@ void format_entries::operator()(xact_t& xact)
|
||||||
last_entry = xact.entry;
|
last_entry = xact.entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t format_accounts::post_accounts(account_t& account)
|
void format_accounts::post_account(account_t& account)
|
||||||
{
|
{
|
||||||
std::size_t displayed = 0;
|
|
||||||
|
|
||||||
// Don't ever print the top-most account
|
|
||||||
if (account.parent) {
|
|
||||||
bind_scope_t bound_scope(report, account);
|
bind_scope_t bound_scope(report, account);
|
||||||
bool format_account = false;
|
bool format_account = false;
|
||||||
|
|
||||||
|
|
@ -248,25 +244,30 @@ std::size_t format_accounts::post_accounts(account_t& account)
|
||||||
|
|
||||||
if (format_account) {
|
if (format_account) {
|
||||||
account.xdata().add_flags(ACCOUNT_EXT_DISPLAYED);
|
account.xdata().add_flags(ACCOUNT_EXT_DISPLAYED);
|
||||||
displayed++;
|
|
||||||
|
|
||||||
format.format(report.output_stream, bound_scope);
|
format.format(report.output_stream, bound_scope);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
foreach (accounts_map::value_type pair, account.accounts) {
|
|
||||||
if (post_accounts(*pair.second) > 0)
|
|
||||||
displayed++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return displayed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void format_accounts::flush()
|
void format_accounts::flush()
|
||||||
{
|
{
|
||||||
std::ostream& out(report.output_stream);
|
std::ostream& out(report.output_stream);
|
||||||
|
|
||||||
std::size_t top_displayed = post_accounts(*report.session.master.get());
|
std::size_t top_displayed = 0;
|
||||||
|
|
||||||
|
foreach (account_t * account, posted_accounts) {
|
||||||
|
post_account(*account);
|
||||||
|
|
||||||
|
if (flatten_list && account->has_flags(ACCOUNT_EXT_DISPLAYED))
|
||||||
|
top_displayed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! flatten_list) {
|
||||||
|
foreach (accounts_map::value_type pair, report.session.master->accounts) {
|
||||||
|
if (pair.second->has_flags(ACCOUNT_EXT_DISPLAYED) ||
|
||||||
|
pair.second->children_with_flags(ACCOUNT_EXT_DISPLAYED))
|
||||||
|
top_displayed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
assert(report.session.master->has_xdata());
|
assert(report.session.master->has_xdata());
|
||||||
account_t::xdata_t& xdata(report.session.master->xdata());
|
account_t::xdata_t& xdata(report.session.master->xdata());
|
||||||
|
|
@ -300,6 +301,7 @@ void format_accounts::operator()(account_t& account)
|
||||||
" But it did not match the display predicate");
|
" But it did not match the display predicate");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
posted_accounts.push_back(&account);
|
||||||
}
|
}
|
||||||
|
|
||||||
format_equity::format_equity(report_t& _report, const string& _format)
|
format_equity::format_equity(report_t& _report, const string& _format)
|
||||||
|
|
@ -351,12 +353,12 @@ void format_equity::flush()
|
||||||
out.flush();
|
out.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t format_equity::post_accounts(account_t& account)
|
void format_equity::post_account(account_t& account)
|
||||||
{
|
{
|
||||||
std::ostream& out(report.output_stream);
|
std::ostream& out(report.output_stream);
|
||||||
|
|
||||||
if (! account.has_flags(ACCOUNT_EXT_MATCHING))
|
if (! account.has_flags(ACCOUNT_EXT_MATCHING))
|
||||||
return 0;
|
return;
|
||||||
|
|
||||||
value_t val = account.xdata().value;
|
value_t val = account.xdata().value;
|
||||||
|
|
||||||
|
|
@ -378,8 +380,6 @@ std::size_t format_equity::post_accounts(account_t& account)
|
||||||
next_lines_format.format(out, bound_scope);
|
next_lines_format.format(out, bound_scope);
|
||||||
}
|
}
|
||||||
total += val;
|
total += val;
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
|
||||||
|
|
@ -165,6 +165,8 @@ protected:
|
||||||
item_predicate disp_pred;
|
item_predicate disp_pred;
|
||||||
bool flatten_list;
|
bool flatten_list;
|
||||||
|
|
||||||
|
std::list<account_t *> posted_accounts;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
format_accounts(report_t& _report,
|
format_accounts(report_t& _report,
|
||||||
const string& _format = "",
|
const string& _format = "",
|
||||||
|
|
@ -184,7 +186,7 @@ public:
|
||||||
TRACE_DTOR(format_accounts);
|
TRACE_DTOR(format_accounts);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::size_t post_accounts(account_t& account);
|
virtual void post_account(account_t& account);
|
||||||
virtual void flush();
|
virtual void flush();
|
||||||
|
|
||||||
virtual void operator()(account_t& account);
|
virtual void operator()(account_t& account);
|
||||||
|
|
@ -209,7 +211,7 @@ class format_equity : public format_accounts
|
||||||
TRACE_DTOR(format_equity);
|
TRACE_DTOR(format_equity);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::size_t post_accounts(account_t& account);
|
virtual void post_account(account_t& account);
|
||||||
virtual void flush();
|
virtual void flush();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,8 +77,8 @@ void report_t::accounts_report(acct_handler_ptr handler)
|
||||||
if (! HANDLED(sort_))
|
if (! HANDLED(sort_))
|
||||||
iter.reset(new basic_accounts_iterator(*session.master));
|
iter.reset(new basic_accounts_iterator(*session.master));
|
||||||
else
|
else
|
||||||
iter.reset(new sorted_accounts_iterator(*session.master,
|
iter.reset(new sorted_accounts_iterator(HANDLER(sort_).str(),
|
||||||
HANDLER(sort_).str()));
|
HANDLED(flat), *session.master.get()));
|
||||||
|
|
||||||
if (HANDLED(display_))
|
if (HANDLED(display_))
|
||||||
pass_down_accounts(handler, *iter.get(),
|
pass_down_accounts(handler, *iter.get(),
|
||||||
|
|
|
||||||
|
|
@ -1424,6 +1424,9 @@ bool sort_value_is_less_than(const std::list<sort_value_t>& left_values,
|
||||||
|
|
||||||
while (left_iter != left_values.end() &&
|
while (left_iter != left_values.end() &&
|
||||||
right_iter != right_values.end()) {
|
right_iter != right_values.end()) {
|
||||||
|
DEBUG("value.sort",
|
||||||
|
"Comparing " << (*left_iter).value << " < " << (*right_iter).value);
|
||||||
|
|
||||||
if ((*left_iter).value < (*right_iter).value)
|
if ((*left_iter).value < (*right_iter).value)
|
||||||
return ! (*left_iter).inverted;
|
return ! (*left_iter).inverted;
|
||||||
else if ((*left_iter).value > (*right_iter).value)
|
else if ((*left_iter).value > (*right_iter).value)
|
||||||
|
|
@ -1434,7 +1437,7 @@ bool sort_value_is_less_than(const std::list<sort_value_t>& left_values,
|
||||||
assert(left_iter == left_values.end());
|
assert(left_iter == left_values.end());
|
||||||
assert(right_iter == right_values.end());
|
assert(right_iter == right_values.end());
|
||||||
|
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ledger
|
} // namespace ledger
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue