diff --git a/src/engine/Backend.c b/src/engine/Backend.c index fecaf23639..ed34746eb1 100644 --- a/src/engine/Backend.c +++ b/src/engine/Backend.c @@ -30,6 +30,7 @@ #include "BackendP.h" #include "Group.h" #include "GroupP.h" +#include "gnc-book-p.h" #include "gnc-engine-util.h" #include "gnc-pricedb.h" #include "gnc-pricedb-p.h" @@ -71,28 +72,23 @@ xaccBackendGetError (Backend *be) Backend * xaccAccountGetBackend (Account * acc) { - Account *parent_acc; AccountGroup * grp; if (!acc) return NULL; + grp = xaccAccountGetRoot (acc); + if (!grp || !grp->book) return NULL; - /* find the first account group that has a backend */ - grp = acc->parent; - while (grp) { - if (grp->backend) return (grp->backend); - parent_acc = grp -> parent; - grp = NULL; - if (parent_acc) { - grp = parent_acc->parent; - } - } - return NULL; + return grp->book->backend; } /********************************************************************\ * Fetch the backend * \********************************************************************/ +/* XXX hack alert -- practically, it would be easier if we found the + * book, and then asked the book about the backend. + */ + Backend * xaccTransactionGetBackend (Transaction *trans) { @@ -124,11 +120,6 @@ xaccTransactionGetBackend (Transaction *trans) } if (!s) return NULL; - /* I suppose it would be more 'technically correct' to make sure that - * all splits share the same backend, and flag an error if they - * don't. However, at this point, it seems quite unlikely, so we'll - * just use the first backend we find. - */ return xaccAccountGetBackend (xaccSplitGetAccount(s)); } @@ -136,25 +127,12 @@ xaccTransactionGetBackend (Transaction *trans) * Set the backend * \********************************************************************/ -void -xaccGroupSetBackend (AccountGroup *grp, Backend *be) -{ - if (!grp) return; - grp->backend = be; -} - Backend * xaccGroupGetBackend (AccountGroup *grp) { - while (grp) - { - Account *parent; - if (grp->backend) return (grp->backend); - parent = grp->parent; - if (!parent) return NULL; - grp = parent->parent; - } - return NULL; + grp = xaccGroupGetRoot (grp); + if (!grp || !grp->book) return NULL; + return grp->book->backend; } /********************************************************************\ diff --git a/src/engine/BackendP.h b/src/engine/BackendP.h index 7ed2034866..42b82f91e9 100644 --- a/src/engine/BackendP.h +++ b/src/engine/BackendP.h @@ -215,10 +215,6 @@ GNCBackendError xaccBackendGetError (Backend *be); Backend * xaccAccountGetBackend (Account *account); Backend * xaccTransactionGetBackend (Transaction *trans); -/* - * The xaccGroupSetBackend() associates a backend to a group - */ -void xaccGroupSetBackend (AccountGroup *group, Backend *be); Backend * xaccGroupGetBackend (AccountGroup *group); Backend * xaccGNCBookGetBackend (GNCBook *book); diff --git a/src/engine/Group.c b/src/engine/Group.c index ac94b64dc9..db87cb369d 100644 --- a/src/engine/Group.c +++ b/src/engine/Group.c @@ -52,42 +52,29 @@ static short module = MOD_ENGINE; \********************************************************************/ static void -xaccInitializeAccountGroup (AccountGroup *grp, GNCEntityTable *entity_table) +xaccInitializeAccountGroup (AccountGroup *grp, GNCBook *book) { grp->saved = 1; grp->parent = NULL; grp->accounts = NULL; - grp->backend = NULL; - grp->book = NULL; - - grp->entity_table = entity_table; + grp->book = book; } /********************************************************************\ \********************************************************************/ -static AccountGroup * -xaccMallocAccountGroupEntityTable (GNCEntityTable *entity_table) -{ - AccountGroup *grp; - - g_return_val_if_fail (entity_table, NULL); - - grp = g_new (AccountGroup, 1); - - xaccInitializeAccountGroup (grp, entity_table); - - return grp; -} - AccountGroup * xaccMallocAccountGroup (GNCBook *book) { + AccountGroup *grp; g_return_val_if_fail (book, NULL); - return xaccMallocAccountGroupEntityTable - (gnc_book_get_entity_table (book)); + + grp = g_new (AccountGroup, 1); + xaccInitializeAccountGroup (grp, book); + + return grp; } /********************************************************************\ @@ -242,8 +229,9 @@ xaccAccountGetBook (Account *account) if (!account) return NULL; group = xaccAccountGetParent (account); + if (!group) return NULL; - return xaccGroupGetBook (group); + return group->book; } /********************************************************************\ @@ -400,7 +388,7 @@ xaccGroupGetSubAccounts (AccountGroup *grp) return g_list_reverse (accounts); } -GList * +AccountList * xaccGroupGetAccountList (AccountGroup *grp) { if (!grp) return NULL; @@ -413,16 +401,11 @@ xaccGroupGetAccountList (AccountGroup *grp) \********************************************************************/ AccountGroup * -xaccAccountGetRoot (Account * acc) +xaccGroupGetRoot (AccountGroup * grp) { - AccountGroup * grp; AccountGroup * root = NULL; - if (!acc) return NULL; - /* find the root of the account group structure */ - grp = acc->parent; - while (grp) { Account *parent_acc; @@ -439,6 +422,13 @@ xaccAccountGetRoot (Account * acc) return root; } +AccountGroup * +xaccAccountGetRoot (Account * acc) +{ + if (!acc) return NULL; + return xaccGroupGetRoot (acc->parent); +} + /********************************************************************\ * Fetch an account, given its name * \********************************************************************/ @@ -632,7 +622,8 @@ void xaccGroupRemoveAccount (AccountGroup *grp, Account *acc) { if (!acc) return; - /* this routine might be called on accounts which + + /* Note this routine might be called on accounts which * are not yet parented. */ if (!grp) return; @@ -667,16 +658,18 @@ xaccGroupRemoveAccount (AccountGroup *grp, Account *acc) void xaccAccountInsertSubAccount (Account *adult, Account *child) { - if (!adult || !child) return; + if (!adult) return; + /* We want the parent to have an entity table. It doesn't have to + * be the same entity table as the child, the xaccGroupInsertAccount + * routine will take care of that. */ g_return_if_fail (adult->entity_table); - g_return_if_fail (adult->entity_table == child->entity_table); /* if a container for the children doesn't yet exist, add it */ if (adult->children == NULL) { - adult->children = xaccMallocAccountGroupEntityTable (adult->entity_table); - xaccGroupSetBook (adult->children, xaccGroupGetBook (adult->parent)); + GNCBook *book = xaccGroupGetBook (adult->parent); + adult->children = xaccMallocAccountGroup (book); } /* set back-pointer to parent */ @@ -706,11 +699,9 @@ group_sort_helper (gconstpointer a, gconstpointer b) void xaccGroupInsertAccount (AccountGroup *grp, Account *acc) { - if (!grp) return; + if (!grp || !grp->book) return; if (!acc) return; - g_return_if_fail (grp->entity_table == acc->entity_table); - /* If the account is currently in another group, remove it there * first. Basically, we can't have accounts being in two places at * once. If old and new parents are the same, reinsertion causes @@ -723,9 +714,29 @@ xaccGroupInsertAccount (AccountGroup *grp, Account *acc) { xaccAccountBeginEdit (acc); - if (acc->parent) + if (acc->parent) + { xaccGroupRemoveAccount (acc->parent, acc); + /* switch over entity tables if needed */ + if (grp->book->entity_table != acc->entity_table) + { + /* hack alert -- this implementation is not exactly correct. + * If the entity tables are not identical, then the 'from' book + * will have a different backend than the 'to' book. This means + * that we should get the 'from' backend to destroy this account, + * and the 'to' backend to save it. Right now, this is broken. + */ + PWARN ("reparenting accounts accross books is not correctly supported\n"); + + gnc_engine_generate_event (&acc->guid, GNC_EVENT_DESTROY); + xaccRemoveEntity (acc->entity_table, &acc->guid); + + xaccStoreEntity (grp->book->entity_table, acc, &acc->guid, GNC_ID_ACCOUNT); + gnc_engine_generate_event (&acc->guid, GNC_EVENT_CREATE); + } + } + /* set back-pointer to the account's parent */ acc->parent = grp; @@ -738,7 +749,7 @@ xaccGroupInsertAccount (AccountGroup *grp, Account *acc) grp->saved = 0; - xaccGroupSetBook (acc->children, xaccGroupGetBook (grp)); + xaccGroupSetBook (acc->children, grp->book); gnc_engine_generate_event (&acc->guid, GNC_EVENT_MODIFY); } @@ -752,10 +763,10 @@ xaccGroupConcatGroup (AccountGroup *togrp, AccountGroup *fromgrp) if (!togrp) return; if (!fromgrp) return; - g_return_if_fail (togrp->entity_table == fromgrp->entity_table); - /* The act of inserting the account into togrp also causes it to - * automatically be deleted from fromgrp. Be careful! */ + * automatically be deleted from fromgrp. This causes linked + * lists to be re-written, and so a cursor traversal is not safe. + * Be careful! */ while (TRUE) { @@ -764,8 +775,7 @@ xaccGroupConcatGroup (AccountGroup *togrp, AccountGroup *fromgrp) GList *next; accounts = fromgrp->accounts; - if (!accounts) - return; + if (!accounts) return; next = accounts->next; @@ -773,14 +783,39 @@ xaccGroupConcatGroup (AccountGroup *togrp, AccountGroup *fromgrp) xaccGroupInsertAccount (togrp, account); - if (!next) - return; + if (!next) return; } } /********************************************************************\ \********************************************************************/ +void +xaccGroupCopyGroup (AccountGroup *to, AccountGroup *from) +{ + GList *node; + if (!to || !from) return; + if (!from->accounts || !to->book) return; + + for (node = from->accounts; node; node=node->next) + { + Account *to_acc, *from_acc = node->data; + to_acc = xaccCloneAccountSimple (from_acc, to->book); + + xaccAccountBeginEdit (to_acc); + to->accounts = g_list_append (to->accounts, to_acc); + if (from_acc->children) + { + to_acc->children = xaccMallocAccountGroup (to->book); + xaccGroupCopyGroup (to_acc->children, from_acc->children); + } + xaccAccountCommitEdit (to_acc); + } +} + +/********************************************************************\ +\********************************************************************/ + void xaccGroupMergeAccounts (AccountGroup *grp) { diff --git a/src/engine/Group.h b/src/engine/Group.h index c9373baa64..aa209a297f 100644 --- a/src/engine/Group.h +++ b/src/engine/Group.h @@ -43,8 +43,16 @@ void xaccAccountGroupBeginEdit (AccountGroup *grp); void xaccAccountGroupCommitEdit (AccountGroup *grp); /* - * The xaccGroupConcatGroup() subroutine will move all accounts - * from the "from" group to the "to" group + * The xaccGroupConcatGroup() subroutine will move (reparent) + * all accounts from the "from" group to the "to" group, + * preserving the account heirarchy. It will also take care + * that the moved accounts will have the "to" group's book + * parent as well. + * + * The xaccGroupCopyGroup() subroutine will copy all accounts + * from the "from" group to the "to" group, preserving the + * account heirarchy. It will also take care that the moved + * accounts will have the "to" groups book parent as well. * * The xaccGroupMergeAccounts() subroutine will go through a group, * merging all accounts that have the same name and description. @@ -52,6 +60,7 @@ void xaccAccountGroupCommitEdit (AccountGroup *grp); */ void xaccGroupConcatGroup (AccountGroup *to, AccountGroup *from); +void xaccGroupCopyGroup (AccountGroup *to, AccountGroup *from); void xaccGroupMergeAccounts (AccountGroup *grp); /* @@ -90,6 +99,18 @@ void xaccGroupMarkDoFree (AccountGroup *grp); * account group can now be reparented to a new location. * Note, however, that it will mark the old parents as having * been modified. + * + * The xaccGroupInsertAccount() subroutine will insert the indicated + * account into the indicated group. If it already is the child + * of another group, it will be removed there first. If the + * account belongs to a different book than the the group, it + * will be removed from the other book (and thus, the other book's + * entity tables, generating destroy & create events). If the + * account is removed from and inserted into the same group, the + * overall account sort order will be recomputed. + * + * The xaccAccountInsertSubAccount() does the same, except that + * the parent is specified as an account. */ void xaccGroupRemoveAccount (AccountGroup *grp, Account *account); @@ -157,9 +178,13 @@ Account *xaccGetPeerAccountFromFullName (Account *acc, const char separator); /* - * The xaccGetAccountRoot () subroutine will find the topmost + * The xaccGroupGetRoot() subroutine will find the topmost + * (root) group to which this group belongs. + * + * The xaccGetAccountRoot() subroutine will find the topmost * (root) group to which this account belongs. */ +AccountGroup * xaccGroupGetRoot (AccountGroup *grp); AccountGroup * xaccAccountGetRoot (Account *account); /* The xaccGroupGetParentAccount() subroutine returns the parent diff --git a/src/engine/GroupP.h b/src/engine/GroupP.h index dc6d7b5d0a..11c9a7e056 100644 --- a/src/engine/GroupP.h +++ b/src/engine/GroupP.h @@ -51,15 +51,10 @@ struct account_group_s /* The flags: */ unsigned int saved : 1; - GNCEntityTable *entity_table; /* table which child accounts must - * be stored in. */ - Account *parent; /* back-pointer to parent */ AccountList *accounts; /* list of account pointers */ - Backend *backend; /* persistant storage backend */ - GNCBook *book; /* The book which this group belongs to */ }; diff --git a/src/engine/Period.c b/src/engine/Period.c index 8d099a25aa..4bcac7b56c 100644 --- a/src/engine/Period.c +++ b/src/engine/Period.c @@ -36,18 +36,27 @@ GNCBook * gnc_book_partition (GNCBook *, Query *); #endif XACC_PERIOD_H__ +#include "gnc-book-p.h" +#include "GroupP.h" + +/* ================================================================ */ GNCBook * gnc_book_partition (GNCBook *existing_book, Query *query) { GNCBook *partition_book; + AccountGroup *part_topgrp; + if (!existing_book || !query) return NULL; - partition_book = gnc_book_new(); + /* first, copy all of the accounts */ + xaccGroupCopyGroup (partition_book->topgroup, existing_book->topgroup); + return partition_book; } +/* ================================================================ */ /* ============================= END OF FILE ====================== */ diff --git a/src/engine/Query.c b/src/engine/Query.c index 4130925f25..d4a631ea7e 100644 --- a/src/engine/Query.c +++ b/src/engine/Query.c @@ -32,6 +32,7 @@ #include #include +#include "gnc-book-p.h" #include "gnc-engine-util.h" #include "gnc-numeric.h" #include "AccountP.h" @@ -1073,7 +1074,7 @@ guid_list_to_account_list (Query * q, GList *guids) GList *accounts = NULL; GList *node; - if (!q || !q->acct_group) + if (!q || !q->acct_group || !q->acct_group->book) return NULL; for (node = guids; node; node = node->next) @@ -1084,7 +1085,7 @@ guid_list_to_account_list (Query * q, GList *guids) if (!guid) continue; - account = xaccAccountLookupEntityTable (guid, q->acct_group->entity_table); + account = xaccAccountLookupEntityTable (guid, q->acct_group->book->entity_table); if (!account) continue; diff --git a/src/engine/gnc-book.c b/src/engine/gnc-book.c index 599be531e1..13e04709f0 100644 --- a/src/engine/gnc-book.c +++ b/src/engine/gnc-book.c @@ -192,8 +192,6 @@ gnc_book_set_group (GNCBook *book, AccountGroup *grp) xaccGroupSetBook (grp, book); book->topgroup = grp; - - xaccGroupSetBackend (grp, book->backend); } void @@ -202,7 +200,6 @@ gnc_book_set_backend (GNCBook *book, Backend *be) if (!book) return; book->backend = be; - xaccGroupSetBackend (book->topgroup, be); xaccPriceDBSetBackend (book->pricedb, be); } @@ -279,8 +276,6 @@ gnc_book_set_template_group (GNCBook *book, AccountGroup *templateGroup) xaccGroupSetBook (templateGroup, book); book->template_group = templateGroup; - - xaccGroupSetBackend (templateGroup, book->backend); } Backend *