357 lines
8.8 KiB
C++
357 lines
8.8 KiB
C++
/*
|
|
* Copyright (c) 2003-2007, 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.
|
|
*/
|
|
|
|
#include "transform.h"
|
|
|
|
namespace ledger {
|
|
|
|
#if 0
|
|
void populate_account(account_t& acct, xml::document_t& document)
|
|
{
|
|
if (! acct.parent)
|
|
return;
|
|
|
|
account_repitem_t * acct_item;
|
|
if (acct.data == NULL) {
|
|
acct.data = acct_item =
|
|
static_cast<account_repitem_t *>(repitem_t::wrap(&acct));
|
|
if (acct.parent) {
|
|
if (acct.parent->data == NULL)
|
|
populate_account(*acct.parent, acct_item);
|
|
else
|
|
static_cast<account_repitem_t *>(acct.parent->data)->
|
|
add_child(acct_item);
|
|
}
|
|
} else {
|
|
acct_item = static_cast<account_repitem_t *>(acct.data);
|
|
}
|
|
|
|
if (item->kind == repitem_t::ACCOUNT)
|
|
acct_item->add_child(item);
|
|
else
|
|
acct_item->add_content(item);
|
|
}
|
|
|
|
class populate_accounts : public repitem_t::select_callback_t {
|
|
virtual void operator()(xml::document_t& document) {
|
|
if (item->kind == repitem_t::TRANSACTION) {
|
|
item->extract();
|
|
populate_account(*static_cast<xact_repitem_t *>(item)->account(), item);
|
|
}
|
|
}
|
|
};
|
|
|
|
class clear_account_data : public repitem_t::select_callback_t {
|
|
virtual void operator()(xml::document_t& document) {
|
|
if (item->kind == repitem_t::ACCOUNT)
|
|
static_cast<account_repitem_t *>(item)->account->data = NULL;
|
|
}
|
|
};
|
|
|
|
void accounts_transform::execute(xml::document_t& document)
|
|
{
|
|
populate_accounts cb1;
|
|
items->select_all(cb1);
|
|
|
|
for (repitem_t * j = items->children; j; j = j->next) {
|
|
assert(j->kind == repitem_t::JOURNAL);
|
|
|
|
j->clear();
|
|
|
|
for (accounts_map::iterator i = j->journal->master->accounts.begin();
|
|
i != j->journal->master->accounts.end();
|
|
i++) {
|
|
assert((*i).second->data);
|
|
j->add_child(static_cast<account_repitem_t *>((*i).second->data));
|
|
(*i).second->data = NULL;
|
|
}
|
|
}
|
|
|
|
clear_account_data cb2;
|
|
items->select_all(cb2);
|
|
}
|
|
|
|
void compact_transform::execute(xml::document_t& document)
|
|
{
|
|
for (repitem_t * i = items; i; i = i->next) {
|
|
if (i->kind == repitem_t::ACCOUNT) {
|
|
while (! i->contents &&
|
|
i->children && ! i->children->next) {
|
|
account_repitem_t * p = static_cast<account_repitem_t *>(i);
|
|
i = p->children;
|
|
p->children = NULL;
|
|
p->last_child = NULL;
|
|
|
|
i->set_parent(p->parent);
|
|
p->set_parent(NULL);
|
|
i->prev = p->prev;
|
|
if (p->prev)
|
|
p->prev->next = i;
|
|
p->prev = NULL;
|
|
i->next = p->next;
|
|
if (p->next)
|
|
p->next->prev = i;
|
|
p->next = NULL;
|
|
|
|
if (i->parent->children == p)
|
|
i->parent->children = i;
|
|
if (i->parent->last_child == p)
|
|
i->parent->last_child = i;
|
|
|
|
account_repitem_t * acct = static_cast<account_repitem_t *>(i);
|
|
acct->parents_elided = p->parents_elided + 1;
|
|
|
|
checked_delete(p);
|
|
}
|
|
}
|
|
|
|
if (i->children)
|
|
execute(i->children);
|
|
}
|
|
}
|
|
|
|
void clean_transform::execute(xml::document_t& document)
|
|
{
|
|
repitem_t * i = items;
|
|
while (i) {
|
|
if (i->kind == repitem_t::ACCOUNT) {
|
|
value_t temp;
|
|
i->add_total(temp);
|
|
if (! temp) {
|
|
repitem_t * next = i->next;
|
|
checked_delete(i);
|
|
i = next;
|
|
continue;
|
|
}
|
|
}
|
|
#if 0
|
|
else if (i->kind == repitem_t::ENTRY && ! i->contents) {
|
|
assert(! i->children);
|
|
repitem_t * next = i->next;
|
|
checked_delete(i);
|
|
i = next;
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
if (i->children)
|
|
execute(i->children);
|
|
|
|
i = i->next;
|
|
}
|
|
}
|
|
|
|
void entries_transform::execute(xml::document_t& document)
|
|
{
|
|
}
|
|
|
|
void optimize_transform::execute(xml::document_t& document)
|
|
{
|
|
for (repitem_t * i = items; i; i = i->next) {
|
|
if (i->kind == repitem_t::ENTRY) {
|
|
if (i->contents &&
|
|
i->contents->next &&
|
|
! i->contents->next->next) { // exactly two transactions
|
|
xact_repitem_t * first =
|
|
static_cast<xact_repitem_t *>(i->contents);
|
|
xact_repitem_t * second =
|
|
static_cast<xact_repitem_t *>(i->contents->next);
|
|
if (first->xact->amount == - second->xact->amount)
|
|
;
|
|
}
|
|
}
|
|
|
|
if (i->children)
|
|
execute(i->children);
|
|
}
|
|
}
|
|
|
|
void split_transform::execute(xml::document_t& document)
|
|
{
|
|
for (repitem_t * i = items; i; i = i->next) {
|
|
if (i->contents && i->contents->next) {
|
|
repitem_t * j;
|
|
|
|
switch (i->kind) {
|
|
case repitem_t::TRANSACTION:
|
|
assert(false);
|
|
j = new xact_repitem_t(static_cast<xact_repitem_t *>(i)->xact);
|
|
break;
|
|
case repitem_t::ENTRY:
|
|
j = new entry_repitem_t(static_cast<entry_repitem_t *>(i)->entry);
|
|
break;
|
|
case repitem_t::ACCOUNT:
|
|
j = new account_repitem_t(static_cast<account_repitem_t *>(i)->account);
|
|
break;
|
|
default:
|
|
j = new repitem_t(i->kind);
|
|
break;
|
|
}
|
|
|
|
j->set_parent(i->parent);
|
|
j->prev = i;
|
|
j->next = i->next;
|
|
i->next = j;
|
|
|
|
j->contents = i->contents->next;
|
|
j->contents->prev = NULL;
|
|
j->contents->set_parent(j);
|
|
i->contents->next = NULL;
|
|
|
|
j->last_content = i->last_content;
|
|
if (j->contents == i->last_content)
|
|
i->last_content = i->contents;
|
|
}
|
|
|
|
if (i->children)
|
|
execute(i->children);
|
|
}
|
|
}
|
|
|
|
void merge_transform::execute(xml::document_t& document)
|
|
{
|
|
for (repitem_t * i = items; i; i = i->next) {
|
|
if (i->next) {
|
|
assert(i->kind == i->next->kind);
|
|
bool merge = false;
|
|
switch (i->kind) {
|
|
case repitem_t::TRANSACTION:
|
|
assert(false);
|
|
break;
|
|
case repitem_t::ENTRY:
|
|
if (static_cast<entry_repitem_t *>(i)->entry ==
|
|
static_cast<entry_repitem_t *>(i->next)->entry)
|
|
merge = true;
|
|
break;
|
|
case repitem_t::ACCOUNT:
|
|
#if 0
|
|
if (static_cast<account_repitem_t *>(i)->account ==
|
|
static_cast<account_repitem_t *>(i->next)->account)
|
|
merge = true;
|
|
#endif
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (merge) {
|
|
repitem_t * j = i->next;
|
|
|
|
i->next = i->next->next;
|
|
if (i->next)
|
|
i->next->prev = i;
|
|
|
|
for (repitem_t * k = j->contents; k; k = k->next)
|
|
k->set_parent(i);
|
|
|
|
i->last_content->next = j->contents;
|
|
i->last_content = j->last_content;
|
|
|
|
j->contents = NULL;
|
|
assert(! j->children);
|
|
checked_delete(j);
|
|
}
|
|
}
|
|
|
|
if (i->children)
|
|
execute(i->children);
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
#define REPITEM_FLAGGED 0x1
|
|
|
|
class mark_selected : public repitem_t::select_callback_t {
|
|
virtual void operator()(xml::document_t& document) {
|
|
item->flags |= REPITEM_FLAGGED;
|
|
}
|
|
};
|
|
|
|
class mark_selected_and_ancestors : public repitem_t::select_callback_t {
|
|
virtual void operator()(xml::document_t& document) {
|
|
while (item->parent) {
|
|
item->flags |= REPITEM_FLAGGED;
|
|
item = item->parent;
|
|
}
|
|
}
|
|
};
|
|
|
|
class delete_unmarked : public repitem_t::select_callback_t {
|
|
virtual void operator()(xml::document_t& document) {
|
|
if (item->parent && ! (item->flags & REPITEM_FLAGGED))
|
|
checked_delete(item);
|
|
}
|
|
};
|
|
|
|
class delete_marked : public repitem_t::select_callback_t {
|
|
virtual void operator()(xml::document_t& document) {
|
|
if (item->flags & REPITEM_FLAGGED)
|
|
checked_delete(item);
|
|
}
|
|
};
|
|
|
|
class clear_flags : public repitem_t::select_callback_t {
|
|
virtual void operator()(xml::document_t& document) {
|
|
item->flags = 0;
|
|
}
|
|
};
|
|
}
|
|
|
|
void select_transform::execute(xml::document_t& document)
|
|
{
|
|
if (! path) {
|
|
items->clear();
|
|
return;
|
|
}
|
|
mark_selected_and_ancestors cb1;
|
|
items->select(path, cb1);
|
|
|
|
delete_unmarked cb2;
|
|
items->select_all(cb2);
|
|
clear_flags cb3;
|
|
items->select_all(cb3);
|
|
}
|
|
|
|
void remove_transform::execute(xml::document_t& document)
|
|
{
|
|
if (! path)
|
|
return;
|
|
mark_selected cb1;
|
|
items->select(path, cb1);
|
|
|
|
delete_marked cb2;
|
|
items->select_all(cb2);
|
|
clear_flags cb3;
|
|
items->select_all(cb3);
|
|
}
|
|
#endif
|
|
|
|
} // namespace ledger
|