Move more account properties from the public data structure to a

private data structure, with access to them as properties of the
object.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@15921 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
David Hampton 2007-04-18 04:50:34 +00:00
parent 3c9babbcf2
commit c6a609b8f7
11 changed files with 722 additions and 221 deletions

View File

@ -451,6 +451,7 @@ gnc_numeric gnc_numeric_reduce(gnc_numeric in);
@{ @{
*/ */
GType gnc_numeric_get_type( void ); GType gnc_numeric_get_type( void );
#define GNC_NUMERIC (gnc_numeric_get_type ())
/** @} */ /** @} */

View File

@ -496,7 +496,11 @@ pgendAccountGetBalance (PGBackend *be, Account *acc, Timespec as_of_date)
cleared_baln = gnc_numeric_create (cl_b, deno); cleared_baln = gnc_numeric_create (cl_b, deno);
reconciled_baln = gnc_numeric_create (rec_b, deno); reconciled_baln = gnc_numeric_create (rec_b, deno);
xaccAccountSetStartingBalance (acc, baln, cleared_baln, reconciled_baln); g_object_set(acc,
"start-balance", &baln,
"start-cleared-balance", &cleared_baln,
"start-reconcoled-balance", &reconciled_baln,
NULL);
{ {
char buf[80]; char buf[80];

View File

@ -128,27 +128,28 @@ typedef struct AccountPrivate
Account *parent; /* back-pointer to parent */ Account *parent; /* back-pointer to parent */
GList *children; /* list of sub-accounts */ GList *children; /* list of sub-accounts */
// /* protected data, cached parameters */ /* protected data - should only be set by backends */
// gnc_numeric starting_balance; gnc_numeric starting_balance;
// gnc_numeric starting_cleared_balance; gnc_numeric starting_cleared_balance;
// gnc_numeric starting_reconciled_balance; gnc_numeric starting_reconciled_balance;
//
// gnc_numeric balance; /* cached parameters */
// gnc_numeric cleared_balance; gnc_numeric balance;
// gnc_numeric reconciled_balance; gnc_numeric cleared_balance;
gnc_numeric reconciled_balance;
gboolean balance_dirty; /* balances in splits incorrect */
/* version number, used for tracking multiuser updates */ /* version number, used for tracking multiuser updates */
gint32 version; gint32 version;
guint32 version_check; /* data aging timestamp */ guint32 version_check; /* data aging timestamp */
// SplitList *splits; /* list of split pointers */ GList *splits; /* list of split pointers */
gboolean sort_dirty; /* sort order of splits is bad */
LotList *lots; /* list of lot pointers */ LotList *lots; /* list of lot pointers */
GNCPolicy *policy; /* Cached pointer to policy method */ GNCPolicy *policy; /* Cached pointer to policy method */
// gboolean balance_dirty; /* balances in splits incorrect */
// gboolean sort_dirty; /* sort order of splits is bad */
/* The "mark" flag can be used by the user to mark this account /* The "mark" flag can be used by the user to mark this account
* in any way desired. Handy for specialty traversals of the * in any way desired. Handy for specialty traversals of the
* account tree. */ * account tree. */
@ -246,17 +247,17 @@ gnc_account_init(Account* acc)
// priv->commodity = NULL; // priv->commodity = NULL;
// priv->commodity_scu = 0; // priv->commodity_scu = 0;
// priv->non_standard_scu = FALSE; // priv->non_standard_scu = FALSE;
//
// priv->balance = gnc_numeric_zero(); priv->balance = gnc_numeric_zero();
// priv->cleared_balance = gnc_numeric_zero(); priv->cleared_balance = gnc_numeric_zero();
// priv->reconciled_balance = gnc_numeric_zero(); priv->reconciled_balance = gnc_numeric_zero();
// priv->starting_balance = gnc_numeric_zero();
// priv->starting_balance = gnc_numeric_zero(); priv->starting_cleared_balance = gnc_numeric_zero();
// priv->starting_cleared_balance = gnc_numeric_zero(); priv->starting_reconciled_balance = gnc_numeric_zero();
// priv->starting_reconciled_balance = gnc_numeric_zero(); priv->balance_dirty = FALSE;
//
// priv->balance_dirty = FALSE; priv->splits = NULL;
// priv->sort_dirty = FALSE; priv->sort_dirty = FALSE;
} }
static void static void
@ -304,6 +305,30 @@ gnc_account_get_property (GObject *object,
// NEED TO BE CONVERTED TO A G_TYPE_ENUM // NEED TO BE CONVERTED TO A G_TYPE_ENUM
g_value_set_int(value, priv->type); g_value_set_int(value, priv->type);
break; break;
case PROP_SORT_DIRTY:
g_value_set_boolean(value, priv->sort_dirty);
break;
case PROP_BALANCE_DIRTY:
g_value_set_boolean(value, priv->balance_dirty);
break;
case PROP_START_BALANCE:
g_value_set_boxed(value, &priv->starting_balance);
break;
case PROP_START_CLEARED_BALANCE:
g_value_set_boxed(value, &priv->starting_cleared_balance);
break;
case PROP_START_RECONCILED_BALANCE:
g_value_set_boxed(value, &priv->starting_reconciled_balance);
break;
case PROP_END_BALANCE:
g_value_set_boxed(value, &priv->balance);
break;
case PROP_END_CLEARED_BALANCE:
g_value_set_boxed(value, &priv->cleared_balance);
break;
case PROP_END_RECONCILED_BALANCE:
g_value_set_boxed(value, &priv->reconciled_balance);
break;
case PROP_ACCT_VERSION: case PROP_ACCT_VERSION:
g_value_set_int(value, priv->version); g_value_set_int(value, priv->version);
break; break;
@ -363,6 +388,24 @@ gnc_account_set_property (GObject *object,
// NEED TO BE CONVERTED TO A G_TYPE_ENUM // NEED TO BE CONVERTED TO A G_TYPE_ENUM
xaccAccountSetType(account, g_value_get_int(value)); xaccAccountSetType(account, g_value_get_int(value));
break; break;
case PROP_SORT_DIRTY:
gnc_account_set_sort_dirty(account);
break;
case PROP_BALANCE_DIRTY:
gnc_account_set_balance_dirty(account);
break;
case PROP_START_BALANCE:
number = g_value_get_boxed(value);
gnc_account_set_start_balance(account, *number);
break;
case PROP_START_CLEARED_BALANCE:
number = g_value_get_boxed(value);
gnc_account_set_start_cleared_balance(account, *number);
break;
case PROP_START_RECONCILED_BALANCE:
number = g_value_get_boxed(value);
gnc_account_set_start_reconciled_balance(account, *number);
break;
case PROP_ACCT_VERSION: case PROP_ACCT_VERSION:
xaccAccountSetVersion(account, g_value_get_int(value)); xaccAccountSetVersion(account, g_value_get_int(value));
break; break;
@ -478,6 +521,120 @@ gnc_account_class_init (AccountClass *klass)
ACCT_TYPE_BANK, ACCT_TYPE_BANK,
G_PARAM_READWRITE)); G_PARAM_READWRITE));
g_object_class_install_property
(gobject_class,
PROP_BALANCE_DIRTY,
g_param_spec_boolean("sort-dirty",
"Sort Dirty",
"TRUE if the splits in the account needs to be "
"resorted. This flag is set by the accounts "
"code for certain internal modifications, or "
"when external code calls the engine to say a "
"split has been modified in a way that may "
"affect the sort order of the account. Note: "
"This value can only be set to TRUE.",
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property
(gobject_class,
PROP_BALANCE_DIRTY,
g_param_spec_boolean("balance-dirty",
"Balance Dirty",
"TRUE if the running balances in the account "
"needs to be recalculated. This flag is set "
"by the accounts code for certain internal "
"modifications, or when external code calls "
"the engine to say a split has been modified. "
"Note: This value can only be set to TRUE.",
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property
(gobject_class,
PROP_START_BALANCE,
g_param_spec_boxed("start-balance",
"Starting Balance",
"The starting balance for the account. This "
"parameter is intended for use with backends that "
"do not return the complete list of splits for an "
"account, but rather return a partial list. In "
"such a case, the backend will typically return "
"all of the splits after some certain date, and "
"the 'starting balance' will represent the "
"summation of the splits up to that date.",
GNC_NUMERIC,
G_PARAM_READWRITE));
g_object_class_install_property
(gobject_class,
PROP_START_CLEARED_BALANCE,
g_param_spec_boxed("start-cleared-balance",
"Starting Cleared Balance",
"The starting cleared balance for the account. "
"This parameter is intended for use with backends "
"that do not return the complete list of splits "
"for an account, but rather return a partial "
"list. In such a case, the backend will "
"typically return all of the splits after "
"some certain date, and the 'starting cleared "
"balance' will represent the summation of the "
"splits up to that date.",
GNC_NUMERIC,
G_PARAM_READWRITE));
g_object_class_install_property
(gobject_class,
PROP_START_RECONCILED_BALANCE,
g_param_spec_boxed("start-reconciled-balance",
"Starting Reconciled Balance",
"The starting reconciled balance for the "
"account. This parameter is intended for use "
"with backends that do not return the complete "
"list of splits for an account, but rather return "
"a partial list. In such a case, the backend "
"will typically return all of the splits after "
"some certain date, and the 'starting recontiled "
"balance' will represent the summation of the "
"splits up to that date.",
GNC_NUMERIC,
G_PARAM_READWRITE));
g_object_class_install_property
(gobject_class,
PROP_END_BALANCE,
g_param_spec_boxed("end-balance",
"Ending Account Balance",
"This is the current ending balance for the "
"account. It is computed from the sum of the "
"starting balance and all splits in the account.",
GNC_NUMERIC,
G_PARAM_READABLE));
g_object_class_install_property
(gobject_class,
PROP_END_CLEARED_BALANCE,
g_param_spec_boxed("end-cleared-balance",
"Ending Account Cleared Balance",
"This is the current ending cleared balance for "
"the account. It is computed from the sum of the "
"starting balance and all cleared splits in the "
"account.",
GNC_NUMERIC,
G_PARAM_READABLE));
g_object_class_install_property
(gobject_class,
PROP_END_RECONCILED_BALANCE,
g_param_spec_boxed("end-reconciled-balance",
"Ending Account Reconciled Balance",
"This is the current ending reconciled balance "
"for the account. It is computed from the sum of "
"the starting balance and all reconciled splits "
"in the account.",
GNC_NUMERIC,
G_PARAM_READABLE));
g_object_class_install_property g_object_class_install_property
(gobject_class, (gobject_class,
PROP_ACCT_VERSION, PROP_ACCT_VERSION,
@ -557,25 +714,12 @@ xaccInitAccount (Account * acc, QofBook *book)
ENTER ("book=%p\n", book); ENTER ("book=%p\n", book);
qof_instance_init_data (&acc->inst, GNC_ID_ACCOUNT, book); qof_instance_init_data (&acc->inst, GNC_ID_ACCOUNT, book);
acc->balance = gnc_numeric_zero();
acc->cleared_balance = gnc_numeric_zero();
acc->reconciled_balance = gnc_numeric_zero();
acc->starting_balance = gnc_numeric_zero();
acc->starting_cleared_balance = gnc_numeric_zero();
acc->starting_reconciled_balance = gnc_numeric_zero();
acc->idata = 0; acc->idata = 0;
acc->commodity = NULL; acc->commodity = NULL;
acc->commodity_scu = 0; acc->commodity_scu = 0;
acc->non_standard_scu = FALSE; acc->non_standard_scu = FALSE;
acc->splits = NULL;
acc->balance_dirty = FALSE;
acc->sort_dirty = FALSE;
LEAVE ("account=%p\n", acc); LEAVE ("account=%p\n", acc);
} }
@ -818,7 +962,7 @@ xaccFreeAccount (Account *acc)
/* NB there shouldn't be any splits by now ... they should /* NB there shouldn't be any splits by now ... they should
* have been all been freed by CommitEdit(). We can remove this * have been all been freed by CommitEdit(). We can remove this
* check once we know the warning isn't occurring any more. */ * check once we know the warning isn't occurring any more. */
if (acc->splits) if (priv->splits)
{ {
GList *slist; GList *slist;
PERR (" instead of calling xaccFreeAccount(), please call \n" PERR (" instead of calling xaccFreeAccount(), please call \n"
@ -826,14 +970,14 @@ xaccFreeAccount (Account *acc)
acc->inst.editlevel = 0; acc->inst.editlevel = 0;
slist = g_list_copy(acc->splits); slist = g_list_copy(priv->splits);
for (lp = slist; lp; lp = lp->next) { for (lp = slist; lp; lp = lp->next) {
Split *s = (Split *) lp->data; Split *s = (Split *) lp->data;
g_assert(xaccSplitGetAccount(s) == acc); g_assert(xaccSplitGetAccount(s) == acc);
xaccSplitDestroy (s); xaccSplitDestroy (s);
} }
g_list_free(slist); g_list_free(slist);
g_assert(acc->splits == NULL); g_assert(priv->splits == NULL);
} }
CACHE_REPLACE(priv->accountName, NULL); CACHE_REPLACE(priv->accountName, NULL);
@ -847,16 +991,16 @@ xaccFreeAccount (Account *acc)
priv->parent = NULL; priv->parent = NULL;
priv->children = NULL; priv->children = NULL;
acc->balance = gnc_numeric_zero(); priv->balance = gnc_numeric_zero();
acc->cleared_balance = gnc_numeric_zero(); priv->cleared_balance = gnc_numeric_zero();
acc->reconciled_balance = gnc_numeric_zero(); priv->reconciled_balance = gnc_numeric_zero();
priv->type = ACCT_TYPE_NONE; priv->type = ACCT_TYPE_NONE;
acc->commodity = NULL; acc->commodity = NULL;
priv->version = 0; priv->version = 0;
acc->balance_dirty = FALSE; priv->balance_dirty = FALSE;
acc->sort_dirty = FALSE; priv->sort_dirty = FALSE;
/* qof_instance_release (&acc->inst); */ /* qof_instance_release (&acc->inst); */
g_object_unref(acc); g_object_unref(acc);
@ -930,7 +1074,7 @@ xaccAccountCommitEdit (Account *acc)
PINFO ("freeing splits for account %p (%s)", PINFO ("freeing splits for account %p (%s)",
acc, priv->accountName ? priv->accountName : "(null)"); acc, priv->accountName ? priv->accountName : "(null)");
slist = g_list_copy(acc->splits); slist = g_list_copy(priv->splits);
for (lp = slist; lp; lp = lp->next) for (lp = slist; lp; lp = lp->next)
{ {
Split *s = lp->data; Split *s = lp->data;
@ -942,7 +1086,7 @@ xaccAccountCommitEdit (Account *acc)
deleting all the splits in it. The splits will just get deleting all the splits in it. The splits will just get
recreated and put right back into the same account! recreated and put right back into the same account!
g_assert(acc->splits == NULL || qof_book_shutting_down(acc->inst.book)); g_assert(priv->splits == NULL || qof_book_shutting_down(acc->inst.book));
*/ */
if (!qof_book_shutting_down(acc->inst.book)) { if (!qof_book_shutting_down(acc->inst.book)) {
@ -1143,13 +1287,13 @@ xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
return FALSE; return FALSE;
} }
if (!gnc_numeric_equal (aa->starting_balance, ab->starting_balance)) if (!gnc_numeric_equal(priv_aa->starting_balance, priv_ab->starting_balance))
{ {
char *str_a; char *str_a;
char *str_b; char *str_b;
str_a = gnc_numeric_to_string (aa->starting_balance); str_a = gnc_numeric_to_string(priv_aa->starting_balance);
str_b = gnc_numeric_to_string (ab->starting_balance); str_b = gnc_numeric_to_string(priv_ab->starting_balance);
PWARN ("starting balances differ: %s vs %s", str_a, str_b); PWARN ("starting balances differ: %s vs %s", str_a, str_b);
@ -1159,14 +1303,14 @@ xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
return FALSE; return FALSE;
} }
if (!gnc_numeric_equal (aa->starting_cleared_balance, if (!gnc_numeric_equal(priv_aa->starting_cleared_balance,
ab->starting_cleared_balance)) priv_ab->starting_cleared_balance))
{ {
char *str_a; char *str_a;
char *str_b; char *str_b;
str_a = gnc_numeric_to_string (aa->starting_cleared_balance); str_a = gnc_numeric_to_string(priv_aa->starting_cleared_balance);
str_b = gnc_numeric_to_string (ab->starting_cleared_balance); str_b = gnc_numeric_to_string(priv_ab->starting_cleared_balance);
PWARN ("starting cleared balances differ: %s vs %s", str_a, str_b); PWARN ("starting cleared balances differ: %s vs %s", str_a, str_b);
@ -1176,14 +1320,14 @@ xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
return FALSE; return FALSE;
} }
if (!gnc_numeric_equal (aa->starting_reconciled_balance, if (!gnc_numeric_equal(priv_aa->starting_reconciled_balance,
ab->starting_reconciled_balance)) priv_ab->starting_reconciled_balance))
{ {
char *str_a; char *str_a;
char *str_b; char *str_b;
str_a = gnc_numeric_to_string (aa->starting_reconciled_balance); str_a = gnc_numeric_to_string(priv_aa->starting_reconciled_balance);
str_b = gnc_numeric_to_string (ab->starting_reconciled_balance); str_b = gnc_numeric_to_string(priv_ab->starting_reconciled_balance);
PWARN ("starting reconciled balances differ: %s vs %s", str_a, str_b); PWARN ("starting reconciled balances differ: %s vs %s", str_a, str_b);
@ -1193,13 +1337,13 @@ xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
return FALSE; return FALSE;
} }
if (!gnc_numeric_equal (aa->balance, ab->balance)) if (!gnc_numeric_equal(priv_aa->balance, priv_ab->balance))
{ {
char *str_a; char *str_a;
char *str_b; char *str_b;
str_a = gnc_numeric_to_string (aa->balance); str_a = gnc_numeric_to_string(priv_aa->balance);
str_b = gnc_numeric_to_string (ab->balance); str_b = gnc_numeric_to_string(priv_ab->balance);
PWARN ("balances differ: %s vs %s", str_a, str_b); PWARN ("balances differ: %s vs %s", str_a, str_b);
@ -1209,13 +1353,13 @@ xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
return FALSE; return FALSE;
} }
if (!gnc_numeric_equal (aa->cleared_balance, ab->cleared_balance)) if (!gnc_numeric_equal(priv_aa->cleared_balance, priv_ab->cleared_balance))
{ {
char *str_a; char *str_a;
char *str_b; char *str_b;
str_a = gnc_numeric_to_string (aa->cleared_balance); str_a = gnc_numeric_to_string(priv_aa->cleared_balance);
str_b = gnc_numeric_to_string (ab->cleared_balance); str_b = gnc_numeric_to_string(priv_ab->cleared_balance);
PWARN ("cleared balances differ: %s vs %s", str_a, str_b); PWARN ("cleared balances differ: %s vs %s", str_a, str_b);
@ -1225,13 +1369,13 @@ xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
return FALSE; return FALSE;
} }
if (!gnc_numeric_equal (aa->reconciled_balance, ab->reconciled_balance)) if (!gnc_numeric_equal(priv_aa->reconciled_balance, priv_ab->reconciled_balance))
{ {
char *str_a; char *str_a;
char *str_b; char *str_b;
str_a = gnc_numeric_to_string (aa->reconciled_balance); str_a = gnc_numeric_to_string(priv_aa->reconciled_balance);
str_b = gnc_numeric_to_string (ab->reconciled_balance); str_b = gnc_numeric_to_string(priv_ab->reconciled_balance);
PWARN ("reconciled balances differ: %s vs %s", str_a, str_b); PWARN ("reconciled balances differ: %s vs %s", str_a, str_b);
@ -1244,8 +1388,8 @@ xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
/* no parent; always compare downwards. */ /* no parent; always compare downwards. */
{ {
GList *la = aa->splits; GList *la = priv_aa->splits;
GList *lb = ab->splits; GList *lb = priv_ab->splits;
if ((la && !lb) || (!la && lb)) if ((la && !lb) || (!la && lb))
{ {
@ -1290,14 +1434,137 @@ xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
/********************************************************************\ /********************************************************************\
\********************************************************************/ \********************************************************************/
gboolean
gnc_account_get_sort_dirty (Account *acc)
{
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
return GET_PRIVATE(acc)->sort_dirty;
}
void
gnc_account_set_sort_dirty (Account *acc)
{
AccountPrivate *priv;
g_return_if_fail(GNC_IS_ACCOUNT(acc));
if (acc->inst.do_free)
return;
priv = GET_PRIVATE(acc);
priv->sort_dirty = TRUE;
}
gboolean
gnc_account_get_balance_dirty (Account *acc)
{
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
return GET_PRIVATE(acc)->balance_dirty;
}
void
gnc_account_set_balance_dirty (Account *acc)
{
AccountPrivate *priv;
g_return_if_fail(GNC_IS_ACCOUNT(acc));
if (acc->inst.do_free)
return;
priv = GET_PRIVATE(acc);
priv->balance_dirty = TRUE;
}
/********************************************************************\
\********************************************************************/
gboolean
gnc_account_find_split (Account *acc, Split *s)
{
AccountPrivate *priv;
GList *node;
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
g_return_val_if_fail(GNC_IS_SPLIT(s), FALSE);
priv = GET_PRIVATE(acc);
node = g_list_find(priv->splits, s);
return node ? TRUE : FALSE;
}
gboolean
gnc_account_insert_split (Account *acc, Split *s)
{
AccountPrivate *priv;
GList *node;
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
g_return_val_if_fail(GNC_IS_SPLIT(s), FALSE);
priv = GET_PRIVATE(acc);
node = g_list_find(priv->splits, s);
if (node)
return FALSE;
if (acc->inst.editlevel == 0) {
priv->splits = g_list_insert_sorted(priv->splits, s,
(GCompareFunc)xaccSplitOrder);
} else {
priv->splits = g_list_prepend(priv->splits, s);
priv->sort_dirty = TRUE;
}
//FIXME: find better event
qof_event_gen (&acc->inst, QOF_EVENT_MODIFY, NULL);
/* Also send an event based on the account */
qof_event_gen(&acc->inst, GNC_EVENT_ITEM_ADDED, s);
priv->balance_dirty = TRUE;
// DRH: Should the below be added? It is present in the delete path.
// xaccAccountRecomputeBalance(acc);
return TRUE;
}
gboolean
gnc_account_remove_split (Account *acc, Split *s)
{
AccountPrivate *priv;
GList *node;
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
g_return_val_if_fail(GNC_IS_SPLIT(s), FALSE);
priv = GET_PRIVATE(acc);
node = g_list_find(priv->splits, s);
if (NULL == node)
return FALSE;
priv->splits = g_list_delete_link(priv->splits, node);
//FIXME: find better event type
qof_event_gen(&acc->inst, QOF_EVENT_MODIFY, NULL);
// And send the account-based event, too
qof_event_gen(&acc->inst, GNC_EVENT_ITEM_REMOVED, s);
priv->balance_dirty = TRUE;
xaccAccountRecomputeBalance(acc);
return TRUE;
}
void void
xaccAccountSortSplits (Account *acc, gboolean force) xaccAccountSortSplits (Account *acc, gboolean force)
{ {
if (!acc || !acc->sort_dirty || (!force && acc->inst.editlevel > 0)) return; AccountPrivate *priv;
acc->splits = g_list_sort(acc->splits, (GCompareFunc)xaccSplitOrder); g_return_if_fail(GNC_IS_ACCOUNT(acc));
acc->sort_dirty = FALSE;
acc->balance_dirty = TRUE; priv = GET_PRIVATE(acc);
if (!priv->sort_dirty || (!force && acc->inst.editlevel > 0))
return;
priv->splits = g_list_sort(priv->splits, (GCompareFunc)xaccSplitOrder);
priv->sort_dirty = FALSE;
priv->balance_dirty = TRUE;
} }
static void static void
@ -1494,7 +1761,7 @@ xaccAccountMoveAllSplits (Account *accfrom, Account *accto)
/* optimizations */ /* optimizations */
from_priv = GET_PRIVATE(accfrom); from_priv = GET_PRIVATE(accfrom);
to_priv = GET_PRIVATE(accto); to_priv = GET_PRIVATE(accto);
if (!accfrom->splits || accfrom == accto) if (!from_priv->splits || accfrom == accto)
return; return;
/* check for book mix-up */ /* check for book mix-up */
@ -1504,27 +1771,27 @@ xaccAccountMoveAllSplits (Account *accfrom, Account *accto)
xaccAccountBeginEdit(accfrom); xaccAccountBeginEdit(accfrom);
xaccAccountBeginEdit(accto); xaccAccountBeginEdit(accto);
/* Begin editing both accounts and all transactions in accfrom. */ /* Begin editing both accounts and all transactions in accfrom. */
g_list_foreach(accfrom->splits, (GFunc)xaccPreSplitMove, NULL); g_list_foreach(from_priv->splits, (GFunc)xaccPreSplitMove, NULL);
/* Concatenate accfrom's lists of splits and lots to accto's lists. */ /* Concatenate accfrom's lists of splits and lots to accto's lists. */
//accto->splits = g_list_concat(accto->splits, accfrom->splits); //to_priv->splits = g_list_concat(to_priv->splits, from_priv->splits);
//to_priv->lots = g_list_concat(to_priv->lots, from_priv->lots); //to_priv->lots = g_list_concat(to_priv->lots, from_priv->lots);
/* Set appropriate flags. */ /* Set appropriate flags. */
//accfrom->balance_dirty = TRUE; //from_priv->balance_dirty = TRUE;
//accfrom->sort_dirty = FALSE; //from_priv->sort_dirty = FALSE;
//accto->balance_dirty = TRUE; //to_priv->balance_dirty = TRUE;
//accto->sort_dirty = TRUE; //to_priv->sort_dirty = TRUE;
/* /*
* Change each split's account back pointer to accto. * Change each split's account back pointer to accto.
* Convert each split's amount to accto's commodity. * Convert each split's amount to accto's commodity.
* Commit to editing each transaction. * Commit to editing each transaction.
*/ */
g_list_foreach(accfrom->splits, (GFunc)xaccPostSplitMove, (gpointer)accto); g_list_foreach(from_priv->splits, (GFunc)xaccPostSplitMove, (gpointer)accto);
/* Finally empty accfrom. */ /* Finally empty accfrom. */
g_assert(accfrom->splits == NULL); g_assert(from_priv->splits == NULL);
g_assert(from_priv->lots == NULL); g_assert(from_priv->lots == NULL);
xaccAccountCommitEdit(accfrom); xaccAccountCommitEdit(accfrom);
xaccAccountCommitEdit(accto); xaccAccountCommitEdit(accto);
@ -1575,17 +1842,17 @@ xaccAccountRecomputeBalance (Account * acc)
priv = GET_PRIVATE(acc); priv = GET_PRIVATE(acc);
if (acc->inst.editlevel > 0) return; if (acc->inst.editlevel > 0) return;
if (!acc->balance_dirty) return; if (!priv->balance_dirty) return;
if (acc->inst.do_free) return; if (acc->inst.do_free) return;
if (qof_book_shutting_down(acc->inst.book)) return; if (qof_book_shutting_down(acc->inst.book)) return;
balance = acc->starting_balance; balance = priv->starting_balance;
cleared_balance = acc->starting_cleared_balance; cleared_balance = priv->starting_cleared_balance;
reconciled_balance = acc->starting_reconciled_balance; reconciled_balance = priv->starting_reconciled_balance;
PINFO ("acct=%s starting baln=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT, PINFO ("acct=%s starting baln=%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT,
priv->accountName, balance.num, balance.denom); priv->accountName, balance.num, balance.denom);
for(lp = acc->splits; lp; lp = lp->next) for(lp = priv->splits; lp; lp = lp->next)
{ {
Split *split = (Split *) lp->data; Split *split = (Split *) lp->data;
gnc_numeric amt = xaccSplitGetAmount (split); gnc_numeric amt = xaccSplitGetAmount (split);
@ -1611,30 +1878,10 @@ xaccAccountRecomputeBalance (Account * acc)
last_split = split; last_split = split;
} }
acc->balance = balance; priv->balance = balance;
acc->cleared_balance = cleared_balance; priv->cleared_balance = cleared_balance;
acc->reconciled_balance = reconciled_balance; priv->reconciled_balance = reconciled_balance;
priv->balance_dirty = FALSE;
acc->balance_dirty = FALSE;
}
/********************************************************************\
\********************************************************************/
void
xaccAccountSetStartingBalance(Account *acc,
const gnc_numeric start_baln,
const gnc_numeric start_cleared_baln,
const gnc_numeric start_reconciled_baln)
{
if (!acc) return;
acc->starting_balance = start_baln;
acc->starting_cleared_balance = start_cleared_baln;
acc->starting_reconciled_balance = start_reconciled_baln;
acc->balance_dirty = TRUE;
} }
/********************************************************************\ /********************************************************************\
@ -1741,7 +1988,7 @@ xaccAccountSetType (Account *acc, GNCAccountType tip)
xaccAccountBeginEdit(acc); xaccAccountBeginEdit(acc);
priv->type = tip; priv->type = tip;
acc->balance_dirty = TRUE; /* new type may affect balance computation */ priv->balance_dirty = TRUE; /* new type may affect balance computation */
mark_account(acc); mark_account(acc);
xaccAccountCommitEdit(acc); xaccAccountCommitEdit(acc);
} }
@ -1841,9 +2088,11 @@ xaccAccountSetNotes (Account *acc, const char *str)
void void
xaccAccountSetCommodity (Account * acc, gnc_commodity * com) xaccAccountSetCommodity (Account * acc, gnc_commodity * com)
{ {
AccountPrivate *priv;
GList *lp; GList *lp;
if (!acc || !com || com == acc->commodity) return; if (!acc || !com || com == acc->commodity) return;
priv = GET_PRIVATE(acc);
xaccAccountBeginEdit(acc); xaccAccountBeginEdit(acc);
acc->commodity = com; acc->commodity = com;
@ -1851,7 +2100,7 @@ xaccAccountSetCommodity (Account * acc, gnc_commodity * com)
acc->non_standard_scu = FALSE; acc->non_standard_scu = FALSE;
/* iterate over splits */ /* iterate over splits */
for (lp = acc->splits; lp; lp = lp->next) for (lp = priv->splits; lp; lp = lp->next)
{ {
Split *s = (Split *) lp->data; Split *s = (Split *) lp->data;
Transaction *trans = xaccSplitGetParent (s); Transaction *trans = xaccSplitGetParent (s);
@ -1861,8 +2110,8 @@ xaccAccountSetCommodity (Account * acc, gnc_commodity * com)
xaccTransCommitEdit (trans); xaccTransCommitEdit (trans);
} }
acc->sort_dirty = TRUE; /* Not needed. */ priv->sort_dirty = TRUE; /* Not needed. */
acc->balance_dirty = TRUE; priv->balance_dirty = TRUE;
mark_account (acc); mark_account (acc);
if (gnc_commodity_is_iso(com)) { if (gnc_commodity_is_iso(com)) {
@ -2531,27 +2780,96 @@ xaccAccountGetCommodity (const Account *acc)
return acc ? acc->commodity : NULL; return acc ? acc->commodity : NULL;
} }
/********************************************************************\
\********************************************************************/
gnc_numeric
gnc_account_get_start_balance (Account *acc)
{
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
return GET_PRIVATE(acc)->starting_balance;
}
void
gnc_account_set_start_balance (Account *acc, const gnc_numeric start_baln)
{
AccountPrivate *priv;
g_return_if_fail(GNC_IS_ACCOUNT(acc));
priv = GET_PRIVATE(acc);
priv->starting_balance = start_baln;
priv->balance_dirty = TRUE;
}
gnc_numeric
gnc_account_get_start_cleared_balance (Account *acc)
{
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
return GET_PRIVATE(acc)->starting_cleared_balance;
}
void
gnc_account_set_start_cleared_balance (Account *acc,
const gnc_numeric start_baln)
{
AccountPrivate *priv;
g_return_if_fail(GNC_IS_ACCOUNT(acc));
priv = GET_PRIVATE(acc);
priv->starting_balance = start_baln;
priv->balance_dirty = TRUE;
}
gnc_numeric
gnc_account_get_start_reconciled_balance (Account *acc)
{
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
return GET_PRIVATE(acc)->starting_reconciled_balance;
}
void
gnc_account_set_start_reconciled_balance (Account *acc,
const gnc_numeric start_baln)
{
AccountPrivate *priv;
g_return_if_fail(GNC_IS_ACCOUNT(acc));
priv = GET_PRIVATE(acc);
priv->starting_balance = start_baln;
priv->balance_dirty = TRUE;
}
gnc_numeric gnc_numeric
xaccAccountGetBalance (const Account *acc) xaccAccountGetBalance (const Account *acc)
{ {
return acc ? acc->balance : gnc_numeric_zero(); g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
return GET_PRIVATE(acc)->balance;
} }
gnc_numeric gnc_numeric
xaccAccountGetClearedBalance (const Account *acc) xaccAccountGetClearedBalance (const Account *acc)
{ {
return acc ? acc->cleared_balance : gnc_numeric_zero(); g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
return GET_PRIVATE(acc)->cleared_balance;
} }
gnc_numeric gnc_numeric
xaccAccountGetReconciledBalance (const Account *acc) xaccAccountGetReconciledBalance (const Account *acc)
{ {
return acc ? acc->reconciled_balance : gnc_numeric_zero(); g_return_val_if_fail(GNC_IS_ACCOUNT(acc), gnc_numeric_zero());
return GET_PRIVATE(acc)->reconciled_balance;
} }
gnc_numeric gnc_numeric
xaccAccountGetProjectedMinimumBalance (const Account *acc) xaccAccountGetProjectedMinimumBalance (const Account *acc)
{ {
AccountPrivate *priv;
GList *node; GList *node;
time_t today; time_t today;
gnc_numeric lowest = gnc_numeric_zero (); gnc_numeric lowest = gnc_numeric_zero ();
@ -2559,8 +2877,9 @@ xaccAccountGetProjectedMinimumBalance (const Account *acc)
if (!acc) return gnc_numeric_zero (); if (!acc) return gnc_numeric_zero ();
priv = GET_PRIVATE(acc);
today = gnc_timet_get_today_end(); today = gnc_timet_get_today_end();
for (node = g_list_last (acc->splits); node; node = node->prev) for (node = g_list_last(priv->splits); node; node = node->prev)
{ {
Split *split = node->data; Split *split = node->data;
@ -2592,6 +2911,7 @@ xaccAccountGetBalanceAsOfDate (Account *acc, time_t date)
* xaccAccountForEachTransaction by using gpointer return * xaccAccountForEachTransaction by using gpointer return
* values rather than gints. * values rather than gints.
*/ */
AccountPrivate *priv;
GList *lp; GList *lp;
Timespec ts, trans_ts; Timespec ts, trans_ts;
gboolean found = FALSE; gboolean found = FALSE;
@ -2602,7 +2922,8 @@ xaccAccountGetBalanceAsOfDate (Account *acc, time_t date)
xaccAccountSortSplits (acc, TRUE); /* just in case, normally a noop */ xaccAccountSortSplits (acc, TRUE); /* just in case, normally a noop */
xaccAccountRecomputeBalance (acc); /* just in case, normally a noop */ xaccAccountRecomputeBalance (acc); /* just in case, normally a noop */
balance = acc->balance; priv = GET_PRIVATE(acc);
balance = priv->balance;
/* Since transaction post times are stored as a Timespec, /* Since transaction post times are stored as a Timespec,
* convert date into a Timespec as well rather than converting * convert date into a Timespec as well rather than converting
@ -2619,7 +2940,7 @@ xaccAccountGetBalanceAsOfDate (Account *acc, time_t date)
ts.tv_sec = date; ts.tv_sec = date;
ts.tv_nsec = 0; ts.tv_nsec = 0;
lp = acc->splits; lp = priv->splits;
while( lp && !found ) while( lp && !found )
{ {
xaccTransGetDatePostedTS( xaccSplitGetParent( (Split *)lp->data ), xaccTransGetDatePostedTS( xaccSplitGetParent( (Split *)lp->data ),
@ -2661,13 +2982,15 @@ xaccAccountGetBalanceAsOfDate (Account *acc, time_t date)
gnc_numeric gnc_numeric
xaccAccountGetPresentBalance (const Account *acc) xaccAccountGetPresentBalance (const Account *acc)
{ {
AccountPrivate *priv;
GList *node; GList *node;
time_t today; time_t today;
g_return_val_if_fail(acc, gnc_numeric_zero()); g_return_val_if_fail(acc, gnc_numeric_zero());
priv = GET_PRIVATE(acc);
today = gnc_timet_get_today_end(); today = gnc_timet_get_today_end();
for (node = g_list_last (acc->splits); node; node = node->prev) for (node = g_list_last(priv->splits); node; node = node->prev)
{ {
Split *split = node->data; Split *split = node->data;
@ -2961,11 +3284,20 @@ xaccAccountGetBalanceChangeForPeriod (Account *acc, time_t t1, time_t t2, gboole
/********************************************************************\ /********************************************************************\
\********************************************************************/ \********************************************************************/
/* THIS API NEEDS TO CHANGE.
*
* This code exposes the internal structure of the account object to
* external callers by returning the actual list used by the object.
* It should instead return a copy of the split list that the caller
* is required to free. That change would provide the freedom of
* allowing the internal organization to change data structures if
* necessary for whatever reason, while leaving the external API
* unchanged. */
SplitList * SplitList *
xaccAccountGetSplitList (const Account *acc) xaccAccountGetSplitList (const Account *acc)
{ {
g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL); g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
return acc->splits; return GET_PRIVATE(acc)->splits;
} }
LotList * LotList *
@ -3755,6 +4087,7 @@ static void
finder_help_function(const Account *acc, const char *description, finder_help_function(const Account *acc, const char *description,
Split **split, Transaction **trans ) Split **split, Transaction **trans )
{ {
AccountPrivate *priv;
GList *slp; GList *slp;
/* First, make sure we set the data to NULL BEFORE we start */ /* First, make sure we set the data to NULL BEFORE we start */
@ -3767,7 +4100,8 @@ finder_help_function(const Account *acc, const char *description,
/* Why is this loop iterated backwards ?? Presumably because the split /* Why is this loop iterated backwards ?? Presumably because the split
* list is in date order, and the most recent matches should be * list is in date order, and the most recent matches should be
* returned!? */ * returned!? */
for (slp = g_list_last (acc->splits); slp; slp = slp->prev) { priv = GET_PRIVATE(acc);
for (slp = g_list_last(priv->splits); slp; slp = slp->prev) {
Split *lsplit = slp->data; Split *lsplit = slp->data;
Transaction *ltrans = xaccSplitGetParent(lsplit); Transaction *ltrans = xaccSplitGetParent(lsplit);
@ -3933,8 +4267,8 @@ gnc_account_merge_children (Account *parent)
gnc_account_merge_children (acc_a); gnc_account_merge_children (acc_a);
/* consolidate transactions */ /* consolidate transactions */
while (acc_b->splits) while (priv_b->splits)
xaccSplitSetAccount (acc_b->splits->data, acc_a); xaccSplitSetAccount (priv_b->splits->data, acc_a);
/* move back one before removal. next iteration around the loop /* move back one before removal. next iteration around the loop
* will get the node after node_b */ * will get the node after node_b */
@ -3971,8 +4305,12 @@ xaccSplitsBeginStagedTransactionTraversals (GList *splits)
void void
xaccAccountBeginStagedTransactionTraversals (const Account *account) xaccAccountBeginStagedTransactionTraversals (const Account *account)
{ {
if (account) AccountPrivate *priv;
xaccSplitsBeginStagedTransactionTraversals (account->splits);
if (!account)
return;
priv = GET_PRIVATE(account);
xaccSplitsBeginStagedTransactionTraversals(priv->splits);
} }
gboolean gboolean
@ -4005,7 +4343,8 @@ static void do_one_split (Split *s, gpointer data)
static void do_one_account (Account *account, gpointer data) static void do_one_account (Account *account, gpointer data)
{ {
g_list_foreach(account->splits, (GFunc)do_one_split, NULL); AccountPrivate *priv = GET_PRIVATE(account);
g_list_foreach(priv->splits, (GFunc)do_one_split, NULL);
} }
/* Replacement for xaccGroupBeginStagedTransactionTraversals */ /* Replacement for xaccGroupBeginStagedTransactionTraversals */
@ -4025,6 +4364,7 @@ xaccAccountStagedTransactionTraversal (const Account *acc,
TransactionCallback thunk, TransactionCallback thunk,
void *cb_data) void *cb_data)
{ {
AccountPrivate *priv;
GList *split_p; GList *split_p;
Transaction *trans; Transaction *trans;
Split *s; Split *s;
@ -4032,7 +4372,8 @@ xaccAccountStagedTransactionTraversal (const Account *acc,
if (!acc) return 0; if (!acc) return 0;
for(split_p = acc->splits; split_p; split_p = g_list_next(split_p)) { priv = GET_PRIVATE(acc);
for(split_p = priv->splits; split_p; split_p = g_list_next(split_p)) {
s = split_p->data; s = split_p->data;
trans = s->parent; trans = s->parent;
if (trans && (trans->marker < stage)) { if (trans && (trans->marker < stage)) {
@ -4070,7 +4411,7 @@ gnc_account_tree_staged_transaction_traversal (const Account *acc,
} }
/* Now this account */ /* Now this account */
for(split_p = acc->splits; split_p; split_p = g_list_next(split_p)) { for(split_p = priv->splits; split_p; split_p = g_list_next(split_p)) {
s = split_p->data; s = split_p->data;
trans = s->parent; trans = s->parent;
if (trans && (trans->marker < stage)) { if (trans && (trans->marker < stage)) {

View File

@ -275,6 +275,80 @@ GNCAccountType xaccAccountGetType (const Account *account);
/** Is the account a stock, mutual fund or currency? */ /** Is the account a stock, mutual fund or currency? */
gboolean xaccAccountIsPriced(const Account *acc); gboolean xaccAccountIsPriced(const Account *acc);
/** This function will set the starting commodity balance for this
* account. This routine is intended for use with backends that do
* not return the complete list of splits for an account, but rather
* return a partial list. In such a case, the backend will typically
* return all of the splits after some certain date, and the
* 'starting balance' will represent the summation of the splits up
* to that date. */
void gnc_account_set_start_balance (Account *acc,
const gnc_numeric start_baln);
/** This function will set the starting cleared commodity balance for
* this account. This routine is intended for use with backends that
* do not return the complete list of splits for an account, but
* rather return a partial list. In such a case, the backend will
* typically return all of the splits after some certain date, and
* the 'starting balance' will represent the summation of the splits
* up to that date. */
void gnc_account_set_start_cleared_balance (Account *acc,
const gnc_numeric start_baln);
/** This function will set the starting reconciled commodity balance
* for this account. This routine is intended for use with backends
* that do not return the complete list of splits for an account, but
* rather return a partial list. In such a case, the backend will
* typically return all of the splits after some certain date, and
* the 'starting balance' will represent the summation of the splits
* up to that date. */
void gnc_account_set_start_reconciled_balance (Account *acc,
const gnc_numeric start_baln);
/** Tell the account that the running balances may be incorrect and
* need to be recomputed.
*
* @param acc Set the flag on this account. */
void gnc_account_set_balance_dirty (Account *acc);
/** Tell the account believes that the splits may be incorrectly
* sorted and need to be resorted.
*
* @param acc Set the flag on this account. */
void gnc_account_set_sort_dirty (Account *acc);
/** Find the given split in an account.
*
* @param acc The account whose splits are to be searched.
*
* @param s The split to be found.
*
* @result TRUE is the split is found in the accounts list of splits.
* FALSE otherwise. */
gboolean gnc_account_find_split (Account *acc, Split *s);
/** Insert the given split from an account.
*
* @param acc The account to which the split should be added.
*
* @param s The split to be added.
*
* @result TRUE is the split is successfully added to the set of
* splits in the account. FALSE if the addition fails for any reason
* (including that the split is already in the account). */
gboolean gnc_account_insert_split (Account *acc, Split *s);
/** Remove the given split from an account.
*
* @param acc The account from which the split should be removed.
*
* @param s The split to be removed.
*
* @result TRUE is the split is successfully removed from the set of
* splits in the account. FALSE if the removal fails for any
* reason. */
gboolean gnc_account_remove_split (Account *acc, Split *s);
/** Get the account's name */ /** Get the account's name */
const char * xaccAccountGetName (const Account *account); const char * xaccAccountGetName (const Account *account);
/** Get the account's accounting code */ /** Get the account's accounting code */
@ -292,6 +366,45 @@ GNCPolicy *gnc_account_get_policy (Account *account);
gint32 xaccAccountGetVersion (const Account* acc); gint32 xaccAccountGetVersion (const Account* acc);
/** Get the account version_check number */ /** Get the account version_check number */
guint32 gnc_account_get_version_check (const Account *acc); guint32 gnc_account_get_version_check (const Account *acc);
/** Retrieve the starting commodity balance for this account. */
gnc_numeric gnc_account_get_start_balance (Account *acc);
/** Retrieve the starting cleared commodity balance for this
* account. */
gnc_numeric gnc_account_get_start_cleared_balance (Account *acc);
/** Retrieve the starting reconciled commodity balance for this
* account. */
gnc_numeric gnc_account_get_start_reconciled_balance (Account *acc);
/** Get an indication of whether the account believes that the running
* balances may be incorrect and need to be recomputed.
*
* @param acc Retrieve the flag on this account.
*
* @return TRUE if the running account balances need to be recomputed.
* FALSE if they are correct. */
gboolean gnc_account_get_balance_dirty (Account *acc);
/** Get an indication of whether the account believes that the splits
* may be incorrectly sorted and need to be resorted.
*
* @param acc Retrieve the flag on this account.
*
* @return TRUE if the splits in the account need to be resorted.
* FALSE if the sort order is correct. */
gboolean gnc_account_get_sort_dirty (Account *acc);
/** The following recompute the partial balances (stored with the
* transaction) and the total balance, for this account
*/
void xaccAccountRecomputeBalance (Account *);
/** The xaccAccountSortSplits() routine will resort the account's
* splits if the sort is dirty. If 'force' is true, the account
* is sorted even if the editlevel is not zero.
*/
void xaccAccountSortSplits (Account *acc, gboolean force);
/** The xaccAccountGetFullName routine returns the fully qualified name /** The xaccAccountGetFullName routine returns the fully qualified name
* of the account using the given separator char. The name must be * of the account using the given separator char. The name must be
@ -864,7 +977,11 @@ guint32 xaccAccountTypesValid(void);
* data structure: do not delete it when done; treat it as a read-only * data structure: do not delete it when done; treat it as a read-only
* structure. Note that some routines (such as xaccAccountRemoveSplit()) * structure. Note that some routines (such as xaccAccountRemoveSplit())
* modify this list directly, and could leave you with a corrupted * modify this list directly, and could leave you with a corrupted
* pointer. */ * pointer.
* @note This should be changed so that the returned value is a copy
* of the list. No other part of the code should have access to the
* internal data structure used by this object.
*/
SplitList* xaccAccountGetSplitList (const Account *account); SplitList* xaccAccountGetSplitList (const Account *account);
/** The xaccAccountMoveAllSplits() routine reassigns each of the splits /** The xaccAccountMoveAllSplits() routine reassigns each of the splits

View File

@ -65,58 +65,16 @@ struct account_s
int commodity_scu; int commodity_scu;
gboolean non_standard_scu; gboolean non_standard_scu;
/* protected data, cached parameters */
gnc_numeric starting_balance;
gnc_numeric starting_cleared_balance;
gnc_numeric starting_reconciled_balance;
gnc_numeric balance;
gnc_numeric cleared_balance;
gnc_numeric reconciled_balance;
SplitList *splits; /* list of split pointers */
gboolean balance_dirty; /* balances in splits incorrect */
gboolean sort_dirty; /* sort order of splits is bad */
/* -------------------------------------------------------------- */ /* -------------------------------------------------------------- */
/* Backend private expansion data */ /* Backend private expansion data */
guint32 idata; /* used by the sql backend for kvp management */ guint32 idata; /* used by the sql backend for kvp management */
}; };
/* The xaccAccountSortSplits() routine will resort the account's
* splits if the sort is dirty. If 'force' is true, the account
* is sorted even if the editlevel is not zero.
*/
void xaccAccountSortSplits (Account *acc, gboolean force);
/* The following recompute the partial balances (stored with the
* transaction) and the total balance, for this account
*/
void xaccAccountRecomputeBalance (Account *);
/* Set the account's GUID. This should only be done when reading /* Set the account's GUID. This should only be done when reading
* an account from a datafile, or some other external source. Never * an account from a datafile, or some other external source. Never
* call this on an existing account! */ * call this on an existing account! */
void xaccAccountSetGUID (Account *account, const GUID *guid); void xaccAccountSetGUID (Account *account, const GUID *guid);
/* The xaccAccountSetStartingBalance() routine will set the starting
* commodity balance for this account. This routine is intended for
* use with backends that do not return the complete list of splits
* for an account, but rather return a partial list. In such a case,
* the backend will typically return all of the splits after some
* certain date, and the 'starting balance' will represent the summation
* of the splits up to that date.
*
* This routine is in the private .h file because only backends are
* allowed to set the starting balance. This is *not* a user interface
* function.
*/
void xaccAccountSetStartingBalance(Account *account,
const gnc_numeric start_baln,
const gnc_numeric start_cleared_baln,
const gnc_numeric start_reconciled_baln);
/* Register Accounts with the engine */ /* Register Accounts with the engine */
gboolean xaccAccountRegister (void); gboolean xaccAccountRegister (void);

View File

@ -112,8 +112,7 @@ gnc_book_insert_trans_clobber (QofBook *book, Transaction *trans)
else else
{ {
xaccAccountInsertSplit (twin, s); xaccAccountInsertSplit (twin, s);
twin->balance_dirty = TRUE; g_object_set(twin, "sort-dirty", TRUE, "balance-dirty", TRUE, NULL);
twin->sort_dirty = TRUE;
} }
} }
@ -179,8 +178,7 @@ gnc_book_insert_trans (QofBook *book, Transaction *trans)
if (s->acc != twin) if (s->acc != twin)
{ {
xaccAccountInsertSplit (twin, s); xaccAccountInsertSplit (twin, s);
twin->balance_dirty = TRUE; g_object_set(twin, "sort-dirty", TRUE, "balance-dirty", TRUE, NULL);
twin->sort_dirty = TRUE;
} }
} }
} }

View File

@ -57,7 +57,7 @@ static QofLogModule log_module = GNC_MOD_LOT;
void void
xaccAccountAssignLots (Account *acc) xaccAccountAssignLots (Account *acc)
{ {
SplitList *node; SplitList *splits, *node;
if (!acc) return; if (!acc) return;
@ -65,7 +65,8 @@ xaccAccountAssignLots (Account *acc)
xaccAccountBeginEdit (acc); xaccAccountBeginEdit (acc);
restart_loop: restart_loop:
for (node=acc->splits; node; node=node->next) splits = xaccAccountGetSplitList(acc);
for (node=splits; node; node=node->next)
{ {
Split * split = node->data; Split * split = node->data;

View File

@ -296,17 +296,11 @@ xaccFreeSplit (Split *split)
g_object_unref(split); g_object_unref(split);
} }
static void mark_acc(Account *acc)
{
if (acc && !acc->inst.do_free) {
acc->balance_dirty = TRUE;
acc->sort_dirty = TRUE;
}
}
void mark_split (Split *s) void mark_split (Split *s)
{ {
mark_acc(s->acc); if (s->acc) {
g_object_set(s->acc, "sort-dirty", TRUE, "balance-dirty", TRUE, NULL);
}
/* set dirty flag on lot too. */ /* set dirty flag on lot too. */
if (s->lot) s->lot->is_closed = -1; if (s->lot) s->lot->is_closed = -1;
@ -526,41 +520,21 @@ xaccSplitCommitEdit(Split *s)
/* Possibly remove the split from the original account... */ /* Possibly remove the split from the original account... */
if (orig_acc && (orig_acc != acc || s->inst.do_free)) { if (orig_acc && (orig_acc != acc || s->inst.do_free)) {
GList *node = g_list_find (orig_acc->splits, s); if (!gnc_account_remove_split(orig_acc, s)) {
if (node) { PERR("Account lost track of moved or deleted split.");
orig_acc->splits = g_list_delete_link (orig_acc->splits, node); }
//FIXME: find better event type
qof_event_gen (&orig_acc->inst, QOF_EVENT_MODIFY, NULL);
// And send the account-based event, too
qof_event_gen(&orig_acc->inst, GNC_EVENT_ITEM_REMOVED, s);
} else PERR("Account lost track of moved or deleted split.");
orig_acc->balance_dirty = TRUE;
xaccAccountRecomputeBalance(orig_acc);
} }
/* ... and insert it into the new account if needed */ /* ... and insert it into the new account if needed */
if (orig_acc != s->acc && !s->inst.do_free) { if (acc && (orig_acc != acc) && !s->inst.do_free) {
if (!g_list_find(acc->splits, s)) { if (gnc_account_insert_split(acc, s)) {
if (acc->inst.editlevel == 0) {
acc->splits = g_list_insert_sorted(
acc->splits, s, (GCompareFunc)xaccSplitOrder);
} else {
acc->splits = g_list_prepend(acc->splits, s);
acc->sort_dirty = TRUE;
}
/* If the split's lot belonged to some other account, we /* If the split's lot belonged to some other account, we
leave it so. */ leave it so. */
if (s->lot && (NULL == s->lot->account)) if (s->lot && (NULL == s->lot->account))
xaccAccountInsertLot (acc, s->lot); xaccAccountInsertLot (acc, s->lot);
} else {
//FIXME: find better event PERR("Account grabbed split prematurely.");
qof_event_gen (&acc->inst, QOF_EVENT_MODIFY, NULL); }
/* Also send an event based on the account */
qof_event_gen(&acc->inst, GNC_EVENT_ITEM_ADDED, s);
} else PERR("Account grabbed split prematurely.");
acc->balance_dirty = TRUE;
xaccSplitSetAmount(s, xaccSplitGetAmount(s)); xaccSplitSetAmount(s, xaccSplitGetAmount(s));
} }
@ -585,8 +559,10 @@ xaccSplitCommitEdit(Split *s)
/* This is because Splits don't call qof_commit_edit(). */ /* This is because Splits don't call qof_commit_edit(). */
qof_instance_set_dirty(QOF_INSTANCE(s->parent)); qof_instance_set_dirty(QOF_INSTANCE(s->parent));
mark_acc(acc); if (acc) {
xaccAccountRecomputeBalance(acc); g_object_set(acc, "sort-dirty", TRUE, "balance-dirty", TRUE, NULL);
xaccAccountRecomputeBalance(acc);
}
if (s->inst.do_free) if (s->inst.do_free)
xaccFreeSplit(s); xaccFreeSplit(s);
} }

View File

@ -79,7 +79,7 @@ gboolean
xaccAccountHasTrades (Account *acc) xaccAccountHasTrades (Account *acc)
{ {
gnc_commodity *acc_comm; gnc_commodity *acc_comm;
SplitList *node; SplitList *splits, *node;
if (!acc) return FALSE; if (!acc) return FALSE;
@ -88,7 +88,8 @@ xaccAccountHasTrades (Account *acc)
acc_comm = acc->commodity; acc_comm = acc->commodity;
for (node=acc->splits; node; node=node->next) splits = xaccAccountGetSplitList(acc);
for (node=splits; node; node=node->next)
{ {
Split *s = node->data; Split *s = node->data;
Transaction *t = s->parent; Transaction *t = s->parent;

View File

@ -31,6 +31,7 @@ TESTS = \
test-object \ test-object \
test-commodities \ test-commodities \
test-create-account \ test-create-account \
test-account-object \
test-group-vs-book \ test-group-vs-book \
test-lots \ test-lots \
test-period \ test-period \
@ -66,6 +67,7 @@ check_PROGRAMS = \
test-freq-spec \ test-freq-spec \
test-recurrence \ test-recurrence \
test-guid \ test-guid \
test-account-object \
test-group-vs-book \ test-group-vs-book \
test-load-engine \ test-load-engine \
test-period \ test-period \

View File

@ -0,0 +1,102 @@
/***************************************************************************
* test-account-object.c
*
* Copyright (C) 2007 David Hampton <hampton@employees.org>
****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* @file test-account-object.c
* @brief Minimal test of reading/writing account parameters
* @author David Hampton <hampton@employees.org>
*/
#include "config.h"
#include <unistd.h>
#include <glib.h>
#include "qof.h"
#include "Account.h"
#include "cashobjects.h"
#include "test-stuff.h"
#include "test-engine-stuff.h"
static void
run_test (void)
{
QofSession *sess;
QofBook *book;
Account *acc;
gnc_numeric *start, *end, end2, delta, zero, five;
sess = get_random_session ();
book = qof_session_get_book (sess);
do_test ((NULL != book), "create random data");
acc = get_random_account(book);
/*****/
g_object_get(acc, "start-balance", &start, "end-balance", &end, NULL);
end2 = xaccAccountGetBalance(acc);
delta = gnc_numeric_sub(*end, *start, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED);
do_test (gnc_numeric_zero_p(*start), "start balance is zero");
do_test (gnc_numeric_zero_p(*end), "end balance is zero");
do_test (gnc_numeric_zero_p(delta), "delta is zero");
do_test (gnc_numeric_zero_p(end2), "end2 balance is zero");
/*****/
five = gnc_numeric_create(5, 1);
g_object_set(acc, "start-balance", &five, NULL);
xaccAccountRecomputeBalance(acc);
g_object_get(acc, "start-balance", &start, "end-balance", &end, NULL);
end2 = xaccAccountGetBalance(acc);
delta = gnc_numeric_sub(*end, five, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED);
do_test (gnc_numeric_zero_p(delta), "end balance matches");
delta = gnc_numeric_sub(end2, five, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED);
do_test (gnc_numeric_zero_p(delta), "end2 balance matches");
/*****/
qof_session_end (sess);
}
int
main (int argc, char **argv)
{
gint i;
qof_init();
if (!cashobjects_register())
exit(1);
/* Any tests that cause an error or warning to be printed
* automatically fail! */
g_log_set_always_fatal( G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING );
/* Set up a reproducible test-case */
srand(0);
/* Run the tests */
run_test ();
print_test_results();
qof_close();
return get_rv();
}