more backend/book cleanup, rework the account clone function.

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@6047 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Linas Vepstas 2001-11-25 06:43:25 +00:00
parent 04e7830d26
commit e4f1cef9b6
9 changed files with 167 additions and 129 deletions

View File

@ -1,7 +1,7 @@
/********************************************************************\
* Account.c -- Account data structure implementation *
* Copyright (C) 1997 Robin D. Clark *
* Copyright (C) 1997, 1998, 1999, 2000 Linas Vepstas *
* Copyright (C) 1997-2001 Linas Vepstas <linas@linas.org> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
@ -51,7 +51,8 @@ static short module = MOD_ENGINE;
* of the internals of the Account in one file. *
\********************************************************************/
static void xaccAccountBringUpToDate(Account *acc);
static void xaccAccountBringUpToDate (Account *);
static void gemini (kvp_frame *, const GUID *, const GUID *, time_t);
/********************************************************************\
\********************************************************************/
@ -105,6 +106,7 @@ xaccInitAccount (Account * acc, GNCBook *book)
acc->core_dirty = FALSE;
acc->do_free = FALSE;
acc->book = book;
acc->entity_table = gnc_book_get_entity_table (book);
xaccGUIDNew(&acc->guid, book);
@ -136,10 +138,12 @@ xaccCloneAccountSimple(const Account *from, GNCBook *book)
{
Account *ret;
ret = xaccMallocAccount (book);
ret = g_new (Account, 1);
g_return_val_if_fail (ret, NULL);
xaccInitAccount (ret, book);
xaccAccountBeginEdit (ret);
ret->type = from->type;
ret->accountName = g_strdup(from->accountName);
@ -150,9 +154,102 @@ xaccCloneAccountSimple(const Account *from, GNCBook *book)
xaccAccountSetCommodity (ret, from->commodity);
gnc_engine_generate_event (&ret->guid, GNC_EVENT_CREATE);
xaccAccountCommitEdit (ret);
return ret;
}
Account *
xaccCloneAccount (const Account *from, GNCBook *book)
{
time_t now;
Account *ret;
ret = g_new (Account, 1);
g_return_val_if_fail (ret, NULL);
now = time(0);
xaccInitAccount (ret, book);
xaccAccountBeginEdit (ret);
ret->type = from->type;
ret->accountName = g_strdup(from->accountName);
ret->accountCode = g_strdup(from->accountCode);
ret->description = g_strdup(from->description);
ret->kvp_data = kvp_frame_copy(from->kvp_data);
xaccAccountSetCommodity (ret, from->commodity);
/* make a note of where the copy came from */
gemini (ret->kvp_data, &from->guid, &from->book->guid, now);
gemini (from->kvp_data, &ret->guid, &book->guid, now);
gnc_engine_generate_event (&ret->guid, GNC_EVENT_CREATE);
xaccAccountCommitEdit (ret);
return ret;
}
/********************************************************************\
\********************************************************************/
/* mark the guid and date of the copy, using kvp. The info will be
* places in /gemini/ncopies, /gemini/<n>/acct_guid, /gemini/<n>/book_guid,
* /gemini/<n>/date, where <n> = ncopies-1.
*/
static void
gemini (kvp_frame *kvp_root, const GUID *acct_guid,
const GUID *book_guid, time_t secs)
{
char buff[80];
kvp_frame *cwd, *pwd;
kvp_value *v_ncopies, *vvv;
gint64 ncopies = 0;
Timespec ts;
/* cwd == 'current working directory' */
pwd = kvp_frame_get_frame (kvp_root, "gemini");
if (!pwd)
{
pwd = kvp_frame_new();
kvp_frame_set_slot_nc (kvp_root,
"gemini", kvp_value_new_frame(pwd));
}
/* find, increment, store number of copies */
v_ncopies = kvp_frame_get_slot (pwd, "ncopies");
if (v_ncopies)
{
ncopies = kvp_value_get_gint64 (v_ncopies);
}
ncopies ++;
v_ncopies = kvp_value_new_gint64 (ncopies);
kvp_frame_set_slot_nc (pwd, "ncopies", v_ncopies);
/* OK, now create subdirectory and put the actual data */
--ncopies;
sprintf (buff, "%lld", ncopies);
cwd = kvp_frame_new();
kvp_frame_set_slot_nc(pwd, buff, kvp_value_new_frame(cwd));
vvv = kvp_value_new_guid (acct_guid);
kvp_frame_set_slot_nc (cwd, "acct_guid", vvv);
vvv = kvp_value_new_guid (book_guid);
kvp_frame_set_slot_nc (cwd, "book_guid", vvv);
ts.tv_sec = secs;
ts.tv_nsec = 0;
vvv = kvp_value_new_timespec (ts);
kvp_frame_set_slot_nc (cwd, "date", vvv);
}
/********************************************************************\
\********************************************************************/
@ -1239,10 +1336,6 @@ update_split_commodity(Account * acc)
/********************************************************************\
\********************************************************************/
/* This is an experimental implementation of set commodity. In the
* long haul, it will need to set the one and only commodity field.
* But in the interim phase, we try to guess right ...
*/
void
xaccAccountSetCommodity (Account * acc, gnc_commodity * com)

View File

@ -1,7 +1,7 @@
/********************************************************************\
* Account.h -- Account handling public routines *
* Copyright (C) 1997 Robin D. Clark *
* Copyright (C) 1997-2000 Linas Vepstas <linas@linas.org> *
* Copyright (C) 1997-2001 Linas Vepstas <linas@linas.org> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
@ -131,9 +131,14 @@ gboolean xaccAccountTypesCompatible (GNCAccountType parent_type,
* it does not copy splits/transactions. Note also that it
* does NOT use the 'gemini' kvp value to indicate where it
* was copied from.
*
* The xaccCloneAccount() does teh same as above, except that it
* also uses the 'gemini' kvp value to mark the account from
* which it was copied.
*/
Account * xaccMallocAccount (GNCBook *book);
Account * xaccCloneAccountSimple(const Account *from, GNCBook *book);
Account * xaccCloneAccount (const Account *from, GNCBook *book);
Account * xaccCloneAccountSimple (const Account *from, GNCBook *book);
void xaccAccountBeginEdit (Account *account);
void xaccAccountCommitEdit (Account *account);

View File

@ -46,8 +46,8 @@
#include "Account.h"
#include "GNCIdP.h"
#include "Transaction.h"
#include "gnc-commodity.h"
#include "gnc-engine.h"
#include "gnc-numeric.h"
#include "kvp_frame.h"
@ -66,6 +66,7 @@ struct account_s
* by being here ??? Do we ahve another reason ??? */
GNCEntityTable *entity_table; /* Entity table this account is
* stored in. */
GNCBook *book;
/* The accountName is an arbitrary string assigned by the user.
* It is intended to a short, 5 to 30 character long string that

View File

@ -64,7 +64,6 @@ xaccBackendGetError (Backend *be)
return err;
}
/********************************************************************\
* Fetch the backend *
\********************************************************************/
@ -72,15 +71,25 @@ xaccBackendGetError (Backend *be)
Backend *
xaccAccountGetBackend (Account * acc)
{
AccountGroup * grp;
if (!acc || !acc->book) return NULL;
return acc->book->backend;
}
if (!acc) return NULL;
grp = xaccAccountGetRoot (acc);
Backend *
xaccGroupGetBackend (AccountGroup *grp)
{
grp = xaccGroupGetRoot (grp);
if (!grp || !grp->book) return NULL;
return grp->book->backend;
}
Backend *
xaccPriceDBGetBackend (GNCPriceDB *prdb)
{
if (!prdb || !prdb->book) return NULL;
return prdb->book->backend;
}
/********************************************************************\
* Fetch the backend *
\********************************************************************/
@ -123,36 +132,6 @@ xaccTransactionGetBackend (Transaction *trans)
return xaccAccountGetBackend (xaccSplitGetAccount(s));
}
/********************************************************************\
* Set the backend *
\********************************************************************/
Backend *
xaccGroupGetBackend (AccountGroup *grp)
{
grp = xaccGroupGetRoot (grp);
if (!grp || !grp->book) return NULL;
return grp->book->backend;
}
/********************************************************************\
* Set the backend *
\********************************************************************/
void
xaccPriceDBSetBackend (GNCPriceDB *prdb, Backend *be)
{
if (!prdb) return;
prdb->backend = be;
}
Backend *
xaccPriceDBGetBackend (GNCPriceDB *prdb)
{
if (!prdb) return NULL;
return prdb->backend;
}
/***********************************************************************/
/* Get a clean backend */
void

View File

@ -787,82 +787,24 @@ xaccGroupConcatGroup (AccountGroup *togrp, AccountGroup *fromgrp)
}
}
/********************************************************************\
\********************************************************************/
/* mark the guid and date of the copy, using kvp. The info will be
* places in /gemini/ncopies, /gemini/<n>/guid, /gemini/<n>/date,
* where <n> = ncopies-1.
*/
static void
gemini (kvp_frame *kvp_root, const GUID *guid, time_t secs)
{
char buff[80];
kvp_frame *cwd, *pwd;
kvp_value *v_ncopies, *vvv;
gint64 ncopies = 0;
Timespec ts;
/* cwd == 'current working directory' */
pwd = kvp_frame_get_frame (kvp_root, "gemini");
if (!pwd)
{
pwd = kvp_frame_new();
kvp_frame_set_slot_nc (kvp_root,
"gemini", kvp_value_new_frame(pwd));
}
/* find, increment, store number of copies */
v_ncopies = kvp_frame_get_slot (pwd, "ncopies");
if (v_ncopies)
{
ncopies = kvp_value_get_gint64 (v_ncopies);
}
ncopies ++;
v_ncopies = kvp_value_new_gint64 (ncopies);
kvp_frame_set_slot_nc (pwd, "ncopies", v_ncopies);
/* OK, now create subdirectory and put the actual data */
--ncopies;
sprintf (buff, "%lld", ncopies);
cwd = kvp_frame_new();
kvp_frame_set_slot_nc(pwd, buff, kvp_value_new_frame(cwd));
vvv = kvp_value_new_guid (guid);
kvp_frame_set_slot_nc (cwd, "guid", vvv);
ts.tv_sec = secs;
ts.tv_nsec = 0;
vvv = kvp_value_new_timespec (ts);
kvp_frame_set_slot_nc (cwd, "date", vvv);
}
void
xaccGroupCopyGroup (AccountGroup *to, AccountGroup *from)
{
time_t now;
GList *node;
if (!to || !from) return;
if (!from->accounts || !to->book) return;
now = time(0);
for (node = from->accounts; node; node=node->next)
{
Account *to_acc, *from_acc = node->data;
/* This will copy the basic data and the KVP. It will
* not copy any splits/transactions. */
to_acc = xaccCloneAccountSimple (from_acc, to->book);
* not copy any splits/transactions. It will gemini. */
to_acc = xaccCloneAccount (from_acc, to->book);
xaccAccountBeginEdit (to_acc);
to->accounts = g_list_append (to->accounts, to_acc);
/* put in markers giving relationships */
gemini (to_acc->kvp_data, &from_acc->guid, now);
gemini (from_acc->kvp_data, &to_acc->guid, now);
/* copy child accounts too. */
if (from_acc->children)
{

View File

@ -7,6 +7,8 @@
*
* CAUTION: this is currently a non-functioning, experimental implementation
* of the design described in src/doc/book.txt
Open questions: hwo do we deal with the backends ???
*
* HISTORY:
* created by Linas Vepstas November 2001
@ -14,8 +16,8 @@
*/
#ifndef XACC_PERIOD_H__
#define XACC_PERIOD_H__
#ifndef XACC_PERIOD_H
#define XACC_PERIOD_H
#include "gnc-book.h"
#include "gnc-engine.h"
@ -27,6 +29,11 @@
* and it moves all of the transactions returned by the query to
* the copied accounts. I
Note that this routine is 'special' in that it works hard to make sure
that the partitioned accounts, transactions and splits are really
moved to a new book -- things like entity tables must be cleared
and repopulated correctly.
An equity transfer is made ...
key-value pairs are set ...
The sched xactions are not copied ...
@ -34,7 +41,7 @@ The sched xactions are not copied ...
*/
GNCBook * gnc_book_partition (GNCBook *, Query *);
#endif XACC_PERIOD_H__
#endif XACC_PERIOD_H
#include "gnc-book-p.h"
#include "GroupP.h"
@ -44,6 +51,7 @@ GNCBook * gnc_book_partition (GNCBook *, Query *);
GNCBook *
gnc_book_partition (GNCBook *existing_book, Query *query)
{
GList * split_list;
GNCBook *partition_book;
AccountGroup *part_topgrp;
@ -53,7 +61,10 @@ gnc_book_partition (GNCBook *existing_book, Query *query)
/* first, copy all of the accounts */
xaccGroupCopyGroup (partition_book->topgroup, existing_book->topgroup);
/* next, run the query */
split_list = xaccQueryGetSplitsUniqueTrans (query);
return partition_book;
}

View File

@ -203,9 +203,7 @@ void
gnc_book_set_backend (GNCBook *book, Backend *be)
{
if (!book) return;
book->backend = be;
xaccPriceDBSetBackend (book->pricedb, be);
}
/* ---------------------------------------------------------------------- */
@ -239,9 +237,7 @@ void
gnc_book_set_pricedb(GNCBook *book, GNCPriceDB *db)
{
if(!book) return;
book->pricedb = db;
xaccPriceDBSetBackend (db, book->backend);
}
/* ---------------------------------------------------------------------- */

View File

@ -26,9 +26,9 @@
#include <glib.h>
#include "BackendP.h"
#include "GNCIdP.h"
#include "GNCId.h"
#include "gnc-book.h"
#include "gnc-engine.h"
#include "gnc-pricedb.h"
struct gnc_price_s
@ -36,6 +36,7 @@ struct gnc_price_s
/* 'public' data fields */
GUID guid; /* globally unique price id */
GNCEntityTable *entity_table; /* table in which price is stored */
GNCBook *book; /* book to which this price belongs to */
GNCPriceDB *db;
gnc_commodity *commodity;
@ -59,7 +60,7 @@ struct gnc_price_s
struct gnc_price_db_s
{
GHashTable *commodity_hash;
Backend *backend;
GNCBook *book; /* book to which this database and all the prices belong to */
gboolean dirty;
};

View File

@ -26,8 +26,9 @@
#include <glib.h>
#include <string.h>
#include "Backend.h"
#include "BackendP.h"
#include "GNCIdP.h"
#include "gnc-book-p.h"
#include "gnc-engine.h"
#include "gnc-engine-util.h"
#include "gnc-book-p.h"
@ -62,6 +63,7 @@ gnc_price_create (GNCBook *book)
p->version = 0;
p->version_check = 0;
p->book = book;
p->entity_table = gnc_book_get_entity_table (book);
xaccGUIDNew (&p->guid, book);
@ -613,7 +615,7 @@ GNCPriceDB *
gnc_pricedb_create(void)
{
GNCPriceDB * result = g_new0(GNCPriceDB, 1);
result->backend = NULL;
result->book = NULL;
result->commodity_hash = g_hash_table_new(commodity_hash, commodity_equal);
g_return_val_if_fail (result->commodity_hash, NULL);
return result;
@ -659,7 +661,7 @@ gnc_pricedb_destroy(GNCPriceDB *db)
NULL);
g_hash_table_destroy (db->commodity_hash);
db->commodity_hash = NULL;
db->backend = NULL;
db->book = NULL;
g_free(db);
}
@ -776,7 +778,7 @@ gnc_pricedb_equal (GNCPriceDB *db1, GNCPriceDB *db2)
static gboolean
add_price(GNCPriceDB *db, GNCPrice *p)
{
/* this function will use p, adding a ref, so treat p as read-only
/* This function will use p, adding a ref, so treat p as read-only
if this function succeeds. */
GList *price_list;
gnc_commodity *commodity;
@ -787,6 +789,14 @@ add_price(GNCPriceDB *db, GNCPrice *p)
ENTER ("db=%p, pr=%p not-saved=%d do-free=%d",
db, p, p->not_saved, p->do_free);
/* initialize the book pointer for teh first time, if needed */
if (NULL == db->book) db->book = p->book;
if (db->book != p->book)
{
PERR ("attempted to mix up prices across different books");
return FALSE;
}
commodity = gnc_price_get_commodity(p);
if(!commodity) {
PWARN("no commodity");
@ -935,14 +945,14 @@ gnc_pricedb_lookup_latest(GNCPriceDB *db,
ENTER ("db=%p commodity=%p currency=%p", db, commodity, currency);
if(!db || !commodity || !currency) return NULL;
if (db->backend && db->backend->price_lookup)
if (db->book && db->book->backend && db->book->backend->price_lookup)
{
GNCPriceLookup pl;
pl.type = LOOKUP_LATEST;
pl.prdb = db;
pl.commodity = commodity;
pl.currency = currency;
(db->backend->price_lookup) (db->backend, &pl);
(db->book->backend->price_lookup) (db->book->backend, &pl);
}
currency_hash = g_hash_table_lookup(db->commodity_hash, commodity);
@ -973,14 +983,14 @@ gnc_pricedb_get_prices(GNCPriceDB *db,
ENTER ("db=%p commodity=%p currency=%p", db, commodity, currency);
if(!db || !commodity || !currency) return NULL;
if (db->backend && db->backend->price_lookup)
if (db->book && db->book->backend && db->book->backend->price_lookup)
{
GNCPriceLookup pl;
pl.type = LOOKUP_ALL;
pl.prdb = db;
pl.commodity = commodity;
pl.currency = currency;
(db->backend->price_lookup) (db->backend, &pl);
(db->book->backend->price_lookup) (db->book->backend, &pl);
}
currency_hash = g_hash_table_lookup(db->commodity_hash, commodity);
@ -1011,7 +1021,7 @@ gnc_pricedb_lookup_at_time(GNCPriceDB *db,
ENTER ("db=%p commodity=%p currency=%p", db, c, currency);
if(!db || !c || !currency) return NULL;
if (db->backend && db->backend->price_lookup)
if (db->book && db->book->backend && db->book->backend->price_lookup)
{
GNCPriceLookup pl;
pl.type = LOOKUP_AT_TIME;
@ -1019,7 +1029,7 @@ gnc_pricedb_lookup_at_time(GNCPriceDB *db,
pl.commodity = c;
pl.currency = currency;
pl.date = t;
(db->backend->price_lookup) (db->backend, &pl);
(db->book->backend->price_lookup) (db->book->backend, &pl);
}
currency_hash = g_hash_table_lookup(db->commodity_hash, c);
@ -1059,7 +1069,7 @@ gnc_pricedb_lookup_nearest_in_time(GNCPriceDB *db,
ENTER ("db=%p commodity=%p currency=%p", db, c, currency);
if(!db || !c || !currency) return NULL;
if (db->backend && db->backend->price_lookup)
if (db->book && db->book->backend && db->book->backend->price_lookup)
{
GNCPriceLookup pl;
pl.type = LOOKUP_NEAREST_IN_TIME;
@ -1067,7 +1077,7 @@ gnc_pricedb_lookup_nearest_in_time(GNCPriceDB *db,
pl.commodity = c;
pl.currency = currency;
pl.date = t;
(db->backend->price_lookup) (db->backend, &pl);
(db->book->backend->price_lookup) (db->book->backend, &pl);
}
currency_hash = g_hash_table_lookup(db->commodity_hash, c);