gnucash/src/backend/xml/gnc-schedxaction-xml-v2.c
Geert Janssens eb409ecd35 Refactor file backend settings to no longer depend on gconf
This affects many other components as well, including the
python bindings

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@22942 57a11ea4-9604-0410-9ed3-97b8803252fd
2013-05-03 12:03:38 +00:00

946 lines
27 KiB
C

/********************************************************************
* gnc-schedxactions-xml-v2.c -- xml routines for transactions *
* Copyright (C) 2001,2007 Joshua Sled <jsled@asynchronous.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, contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
* Boston, MA 02110-1301, USA gnu@gnu.org *
* *
*******************************************************************/
#include "config.h"
#include <glib.h>
#include <string.h>
#include "SX-book.h"
#include "gnc-xml-helper.h"
#include "sixtp.h"
#include "sixtp-utils.h"
#include "sixtp-parsers.h"
#include "sixtp-utils.h"
#include "sixtp-dom-parsers.h"
#include "sixtp-dom-generators.h"
#include "gnc-xml.h"
#include "io-gncxml-v2.h"
#include "io-gncxml-gen.h"
#include "sixtp-dom-parsers.h"
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "gnc.backend.file.sx"
#define SX_ID "sx:id"
#define SX_NAME "sx:name"
#define SX_ENABLED "sx:enabled"
#define SX_AUTOCREATE "sx:autoCreate"
#define SX_AUTOCREATE_NOTIFY "sx:autoCreateNotify"
#define SX_ADVANCE_CREATE_DAYS "sx:advanceCreateDays"
#define SX_ADVANCE_REMIND_DAYS "sx:advanceRemindDays"
#define SX_INSTANCE_COUNT "sx:instanceCount"
#define SX_START "sx:start"
#define SX_LAST "sx:last"
#define SX_NUM_OCCUR "sx:num-occur"
#define SX_REM_OCCUR "sx:rem-occur"
#define SX_END "sx:end"
#define SX_TEMPL_ACCT "sx:templ-acct"
#define SX_FREQSPEC "sx:freqspec"
#define SX_SCHEDULE "sx:schedule"
#define SX_SLOTS "sx:slots"
#define SX_DEFER_INSTANCE "sx:deferredInstance"
/*
* FIXME: These should be defined in a header somewhere
*/
#define GNC_ACCOUNT_TAG "gnc:account"
#define GNC_TRANSACTION_TAG "gnc:transaction"
#define GNC_SCHEDXACTION_TAG "gnc:schedxaction"
const gchar *schedxaction_version_string = "1.0.0";
const gchar *schedxaction_version2_string = "2.0.0";
xmlNodePtr
gnc_schedXaction_dom_tree_create(SchedXaction *sx)
{
xmlNodePtr ret;
const GDate *date;
gint instCount;
const GncGUID *templ_acc_guid;
gboolean allow_2_2_incompat = TRUE;
templ_acc_guid = xaccAccountGetGUID(sx->template_acct);
/* FIXME: this should be the same as the def in io-gncxml-v2.c */
ret = xmlNewNode( NULL, BAD_CAST GNC_SCHEDXACTION_TAG );
if (allow_2_2_incompat)
xmlSetProp(ret, BAD_CAST "version", BAD_CAST schedxaction_version2_string);
else
xmlSetProp(ret, BAD_CAST "version", BAD_CAST schedxaction_version_string);
xmlAddChild( ret,
guid_to_dom_tree(SX_ID,
xaccSchedXactionGetGUID(sx)) );
xmlNewTextChild( ret, NULL, BAD_CAST SX_NAME, BAD_CAST xaccSchedXactionGetName(sx) );
if (allow_2_2_incompat)
{
xmlNewTextChild( ret, NULL, BAD_CAST SX_ENABLED,
BAD_CAST ( sx->enabled ? "y" : "n" ) );
}
xmlNewTextChild( ret, NULL, BAD_CAST SX_AUTOCREATE,
BAD_CAST ( sx->autoCreateOption ? "y" : "n" ) );
xmlNewTextChild( ret, NULL, BAD_CAST SX_AUTOCREATE_NOTIFY,
BAD_CAST ( sx->autoCreateNotify ? "y" : "n" ) );
xmlAddChild(ret, int_to_dom_tree(SX_ADVANCE_CREATE_DAYS,
sx->advanceCreateDays));
xmlAddChild(ret, int_to_dom_tree(SX_ADVANCE_REMIND_DAYS,
sx->advanceRemindDays));
instCount = gnc_sx_get_instance_count( sx, NULL );
xmlAddChild( ret, int_to_dom_tree( SX_INSTANCE_COUNT,
instCount ) );
xmlAddChild( ret,
gdate_to_dom_tree( SX_START,
xaccSchedXactionGetStartDate(sx) ) );
date = xaccSchedXactionGetLastOccurDate(sx);
if ( g_date_valid( date ) )
{
xmlAddChild( ret, gdate_to_dom_tree( SX_LAST, date ) );
}
if ( xaccSchedXactionHasOccurDef(sx) )
{
xmlAddChild(ret, int_to_dom_tree( SX_NUM_OCCUR,
xaccSchedXactionGetNumOccur(sx)));
xmlAddChild(ret, int_to_dom_tree( SX_REM_OCCUR,
xaccSchedXactionGetRemOccur(sx)));
}
else if ( xaccSchedXactionHasEndDate(sx) )
{
xmlAddChild( ret,
gdate_to_dom_tree( SX_END,
xaccSchedXactionGetEndDate(sx) ) );
}
/* output template account GncGUID */
xmlAddChild( ret,
guid_to_dom_tree(SX_TEMPL_ACCT,
templ_acc_guid));
if (allow_2_2_incompat)
{
xmlNodePtr schedule_node = xmlNewNode(NULL,
BAD_CAST "sx:schedule");
GList *schedule = gnc_sx_get_schedule(sx);
for (; schedule != NULL; schedule = schedule->next)
{
xmlAddChild(schedule_node, recurrence_to_dom_tree("gnc:recurrence", (Recurrence*)schedule->data));
}
xmlAddChild(ret, schedule_node);
}
/* Output deferred-instance list. */
{
xmlNodePtr instNode;
SXTmpStateData *tsd;
GList *l;
for ( l = gnc_sx_get_defer_instances( sx ); l; l = l->next )
{
tsd = (SXTmpStateData*)l->data;
instNode = xmlNewNode( NULL, BAD_CAST SX_DEFER_INSTANCE );
if ( g_date_valid( &tsd->last_date ) )
{
xmlAddChild( instNode, gdate_to_dom_tree( SX_LAST,
&tsd->last_date ) );
}
xmlAddChild( instNode, int_to_dom_tree( SX_REM_OCCUR,
tsd->num_occur_rem ) );
xmlAddChild( instNode, int_to_dom_tree( SX_INSTANCE_COUNT,
tsd->num_inst ) );
xmlAddChild( ret, instNode );
}
}
/* output kvp_frame */
{
xmlNodePtr kvpnode =
kvp_frame_to_dom_tree( SX_SLOTS,
xaccSchedXactionGetSlots(sx) );
if ( kvpnode )
{
xmlAddChild(ret, kvpnode);
}
}
return ret;
}
struct sx_pdata
{
SchedXaction *sx;
QofBook *book;
gboolean saw_freqspec;
gboolean saw_recurrence;
};
static
gboolean
sx_id_handler( xmlNodePtr node, gpointer sx_pdata )
{
struct sx_pdata *pdata = sx_pdata;
SchedXaction *sx = pdata->sx;
GncGUID *tmp = dom_tree_to_guid( node );
g_return_val_if_fail( tmp, FALSE );
xaccSchedXactionSetGUID(sx, tmp);
g_free( tmp );
return TRUE;
}
static
gboolean
sx_name_handler( xmlNodePtr node, gpointer sx_pdata )
{
struct sx_pdata *pdata = sx_pdata;
SchedXaction *sx = pdata->sx;
gchar *tmp = dom_tree_to_text( node );
g_debug("sx named [%s]", tmp);
g_return_val_if_fail( tmp, FALSE );
xaccSchedXactionSetName( sx, tmp );
g_free( tmp );
return TRUE;
}
static gboolean
sx_enabled_handler( xmlNodePtr node, gpointer sx_pdata )
{
struct sx_pdata *pdata = sx_pdata;
SchedXaction *sx = pdata->sx;
gchar *tmp = dom_tree_to_text( node );
sx->enabled = (g_strcmp0( tmp, "y" ) == 0 ? TRUE : FALSE );
return TRUE;
}
static gboolean
sx_autoCreate_handler( xmlNodePtr node, gpointer sx_pdata )
{
struct sx_pdata *pdata = sx_pdata;
SchedXaction *sx = pdata->sx;
gchar *tmp = dom_tree_to_text( node );
sx->autoCreateOption = (g_strcmp0( tmp, "y" ) == 0 ? TRUE : FALSE );
return TRUE;
}
static gboolean
sx_notify_handler( xmlNodePtr node, gpointer sx_pdata )
{
struct sx_pdata *pdata = sx_pdata;
SchedXaction *sx = pdata->sx;
gchar *tmp = dom_tree_to_text( node );
sx->autoCreateNotify = (g_strcmp0( tmp, "y" ) == 0 ? TRUE : FALSE );
return TRUE;
}
static gboolean
sx_advCreate_handler( xmlNodePtr node, gpointer sx_pdata )
{
struct sx_pdata *pdata = sx_pdata;
SchedXaction *sx = pdata->sx;
gint64 advCreate;
if ( ! dom_tree_to_integer( node, &advCreate ) )
{
return FALSE;
}
xaccSchedXactionSetAdvanceCreation( sx, advCreate );
return TRUE;
}
static gboolean
sx_advRemind_handler( xmlNodePtr node, gpointer sx_pdata )
{
struct sx_pdata *pdata = sx_pdata;
SchedXaction *sx = pdata->sx;
gint64 advRemind;
if ( ! dom_tree_to_integer( node, &advRemind ) )
{
return FALSE;
}
xaccSchedXactionSetAdvanceReminder( sx, advRemind );
return TRUE;
}
static
gboolean
sx_set_date( xmlNodePtr node, SchedXaction *sx,
void (*settor)( SchedXaction *sx, const GDate *d ) )
{
GDate *date;
date = dom_tree_to_gdate( node );
g_return_val_if_fail( date, FALSE );
(*settor)( sx, date );
g_date_free( date );
return TRUE;
}
static
gboolean
sx_instcount_handler( xmlNodePtr node, gpointer sx_pdata )
{
struct sx_pdata *pdata = sx_pdata;
SchedXaction *sx = pdata->sx;
gint64 instanceNum;
if ( ! dom_tree_to_integer( node, &instanceNum ) )
{
return FALSE;
}
gnc_sx_set_instance_count( sx, instanceNum );
return TRUE;
}
static
gboolean
sx_start_handler( xmlNodePtr node, gpointer sx_pdata )
{
struct sx_pdata *pdata = sx_pdata;
SchedXaction *sx = pdata->sx;
return sx_set_date( node, sx, xaccSchedXactionSetStartDate );
}
static
gboolean
sx_last_handler( xmlNodePtr node, gpointer sx_pdata )
{
struct sx_pdata *pdata = sx_pdata;
SchedXaction *sx = pdata->sx;
return sx_set_date( node, sx, xaccSchedXactionSetLastOccurDate );
}
static
gboolean
sx_end_handler( xmlNodePtr node, gpointer sx_pdata )
{
struct sx_pdata *pdata = sx_pdata;
SchedXaction *sx = pdata->sx;
return sx_set_date( node, sx, xaccSchedXactionSetEndDate );
}
static void
_fixup_recurrence_start_dates(const GDate *sx_start_date, GList *schedule)
{
GList *iter;
for (iter = schedule; iter != NULL; iter = iter->next)
{
Recurrence *r;
GDate start, next;
r = (Recurrence*)iter->data;
start = *sx_start_date;
g_date_subtract_days(&start, 1);
g_date_clear(&next, 1);
recurrenceNextInstance(r, &start, &next);
g_return_if_fail(g_date_valid(&next));
{
gchar date_str[128];
gchar *sched_str;
g_date_strftime(date_str, 127, "%x", &next);
sched_str = recurrenceToString(r);
g_debug("setting recurrence [%s] start date to [%s]",
sched_str, date_str);
g_free(sched_str);
}
recurrenceSet(r,
recurrenceGetMultiplier(r),
recurrenceGetPeriodType(r),
&next,
recurrenceGetWeekendAdjust(r));
}
if (g_list_length(schedule) == 1
&& recurrenceGetPeriodType((Recurrence*)g_list_nth_data(schedule, 0)) == PERIOD_ONCE)
{
char date_buf[128];
Recurrence *fixup = (Recurrence*)g_list_nth_data(schedule, 0);
g_date_strftime(date_buf, 127, "%x", sx_start_date);
recurrenceSet(fixup, 1, PERIOD_ONCE, sx_start_date, WEEKEND_ADJ_NONE);
g_debug("fixed up period=ONCE Recurrence to date [%s]", date_buf);
}
}
static gboolean
sx_freqspec_handler( xmlNodePtr node, gpointer sx_pdata )
{
struct sx_pdata *pdata = sx_pdata;
SchedXaction *sx = pdata->sx;
GList *schedule;
gchar* debug_str;
g_return_val_if_fail( node, FALSE );
schedule = dom_tree_freqSpec_to_recurrences(node, pdata->book);
gnc_sx_set_schedule(sx, schedule);
debug_str = recurrenceListToString(schedule);
g_debug("parsed from freqspec [%s]", debug_str);
g_free(debug_str);
_fixup_recurrence_start_dates(xaccSchedXactionGetStartDate(sx), schedule);
pdata->saw_freqspec = TRUE;
return TRUE;
}
static gboolean
sx_schedule_recurrence_handler(xmlNodePtr node, gpointer parsing_data)
{
GList **schedule = (GList**)parsing_data;
gchar* sched_str;
Recurrence *r = dom_tree_to_recurrence(node);
g_return_val_if_fail(r, FALSE);
sched_str = recurrenceToString(r);
g_debug("parsed recurrence [%s]", sched_str);
g_free(sched_str);
*schedule = g_list_append(*schedule, r);
return TRUE;
}
struct dom_tree_handler sx_recurrence_list_handlers[] =
{
{ "gnc:recurrence", sx_schedule_recurrence_handler, 0, 0 },
{ NULL, NULL, 0, 0 }
};
static gboolean
sx_recurrence_handler(xmlNodePtr node, gpointer _pdata)
{
struct sx_pdata *parsing_data = _pdata;
GList *schedule = NULL;
gchar* debug_str;
g_return_val_if_fail(node, FALSE);
if (!dom_tree_generic_parse(node, sx_recurrence_list_handlers, &schedule))
return FALSE;
// g_return_val_if_fail(schedule, FALSE);
debug_str = recurrenceListToString(schedule);
g_debug("setting freshly-parsed schedule: [%s]", debug_str);
g_free(debug_str);
gnc_sx_set_schedule(parsing_data->sx, schedule);
parsing_data->saw_recurrence = TRUE;
return TRUE;
}
static
gboolean
sx_defer_last_handler( xmlNodePtr node, gpointer gpTSD )
{
GDate *gd;
SXTmpStateData *tsd = (SXTmpStateData*)gpTSD;
g_return_val_if_fail( node, FALSE );
gd = dom_tree_to_gdate( node );
g_return_val_if_fail( gd, FALSE );
tsd->last_date = *gd;
g_date_free( gd );
return TRUE;
}
static
gboolean
sx_defer_rem_occur_handler( xmlNodePtr node, gpointer gpTSD )
{
gint64 remOccur;
SXTmpStateData *tsd = (SXTmpStateData*)gpTSD;
g_return_val_if_fail( node, FALSE );
if ( ! dom_tree_to_integer( node, &remOccur ) )
{
return FALSE;
}
tsd->num_occur_rem = remOccur;
return TRUE;
}
static
gboolean
sx_defer_inst_count_handler( xmlNodePtr node, gpointer gpTSD )
{
gint64 instCount;
SXTmpStateData *tsd = (SXTmpStateData*)gpTSD;
g_return_val_if_fail( node, FALSE );
if ( ! dom_tree_to_integer( node, &instCount ) )
{
return FALSE;
}
tsd->num_inst = instCount;
return TRUE;
}
struct dom_tree_handler sx_defer_dom_handlers[] =
{
/* tag name, handler, opt, ? */
{ SX_LAST, sx_defer_last_handler, 1, 0 },
{ SX_REM_OCCUR, sx_defer_rem_occur_handler, 1, 0 },
{ SX_INSTANCE_COUNT, sx_defer_inst_count_handler, 1, 0 },
{ NULL, NULL, 0, 0 }
};
static
gboolean
sx_defer_inst_handler( xmlNodePtr node, gpointer sx_pdata )
{
struct sx_pdata *pdata = sx_pdata;
SchedXaction *sx = pdata->sx;
SXTmpStateData *tsd;
g_return_val_if_fail( node, FALSE );
tsd = g_new0( SXTmpStateData, 1 );
g_assert( sx_defer_dom_handlers != NULL );
if ( !dom_tree_generic_parse( node,
sx_defer_dom_handlers,
tsd ) )
{
xmlElemDump(stdout, NULL, node);
g_free( tsd );
tsd = NULL;
return FALSE;
}
/* We assume they were serialized in sorted order, here. */
sx->deferredList = g_list_append( sx->deferredList, tsd );
return TRUE;
}
static
gboolean
sx_numOccur_handler( xmlNodePtr node, gpointer sx_pdata )
{
struct sx_pdata *pdata = sx_pdata;
SchedXaction *sx = pdata->sx;
gint64 numOccur;
if ( ! dom_tree_to_integer( node, &numOccur ) )
{
return FALSE;
}
xaccSchedXactionSetNumOccur( sx, numOccur );
return TRUE;
}
static
gboolean
sx_templ_acct_handler( xmlNodePtr node, gpointer sx_pdata)
{
struct sx_pdata *pdata = sx_pdata;
SchedXaction *sx = pdata->sx;
GncGUID *templ_acct_guid = dom_tree_to_guid(node);
Account *account;
if (!templ_acct_guid)
{
return FALSE;
}
account = xaccAccountLookup(templ_acct_guid, pdata->book);
sx_set_template_account(sx, account);
g_free(templ_acct_guid);
return TRUE;
}
static
gboolean
sx_remOccur_handler( xmlNodePtr node, gpointer sx_pdata )
{
struct sx_pdata *pdata = sx_pdata;
SchedXaction *sx = pdata->sx;
gint64 remOccur;
if ( ! dom_tree_to_integer( node, &remOccur ) )
{
return FALSE;
}
xaccSchedXactionSetRemOccur( sx, remOccur );
return TRUE;
}
static
gboolean
sx_slots_handler( xmlNodePtr node, gpointer sx_pdata )
{
struct sx_pdata *pdata = sx_pdata;
SchedXaction *sx = pdata->sx;
return dom_tree_to_kvp_frame_given( node, xaccSchedXactionGetSlots (sx) );
}
struct dom_tree_handler sx_dom_handlers[] =
{
{ SX_ID, sx_id_handler, 1, 0 },
{ SX_NAME, sx_name_handler, 1, 0 },
{ SX_ENABLED, sx_enabled_handler, 0, 0 },
{ SX_AUTOCREATE, sx_autoCreate_handler, 1, 0 },
{ SX_AUTOCREATE_NOTIFY, sx_notify_handler, 1, 0 },
{ SX_ADVANCE_CREATE_DAYS, sx_advCreate_handler, 1, 0 },
{ SX_ADVANCE_REMIND_DAYS, sx_advRemind_handler, 1, 0 },
{ SX_INSTANCE_COUNT, sx_instcount_handler, 0, 0 },
{ SX_START, sx_start_handler, 1, 0 },
{ SX_LAST, sx_last_handler, 0, 0 },
{ SX_NUM_OCCUR, sx_numOccur_handler, 0, 0 },
{ SX_REM_OCCUR, sx_remOccur_handler, 0, 0 },
{ SX_END, sx_end_handler, 0, 0 },
{ SX_TEMPL_ACCT, sx_templ_acct_handler, 0, 0 },
{ SX_FREQSPEC, sx_freqspec_handler, 0, 0 },
{ SX_SCHEDULE, sx_recurrence_handler, 0, 0 },
{ SX_DEFER_INSTANCE, sx_defer_inst_handler, 0, 0 },
{ SX_SLOTS, sx_slots_handler, 0, 0 },
{ NULL, NULL, 0, 0 }
};
static gboolean
gnc_schedXaction_end_handler(gpointer data_for_children,
GSList* data_from_children, GSList* sibling_data,
gpointer parent_data, gpointer global_data,
gpointer *result, const gchar *tag)
{
SchedXaction *sx;
gboolean successful = FALSE;
xmlNodePtr tree = (xmlNodePtr)data_for_children;
gxpf_data *gdata = (gxpf_data*)global_data;
struct sx_pdata sx_pdata;
if ( parent_data )
{
return TRUE;
}
if ( !tag )
{
return TRUE;
}
g_return_val_if_fail( tree, FALSE );
sx = xaccSchedXactionMalloc( gdata->bookdata );
memset(&sx_pdata, 0, sizeof(sx_pdata));
sx_pdata.sx = sx;
sx_pdata.book = gdata->bookdata;
g_assert( sx_dom_handlers != NULL );
successful = dom_tree_generic_parse( tree, sx_dom_handlers, &sx_pdata );
if (!successful)
{
g_critical("failed to parse scheduled xaction");
xmlElemDump( stdout, NULL, tree );
gnc_sx_begin_edit( sx );
xaccSchedXactionDestroy( sx );
goto done;
}
if (tree->properties)
{
gchar *sx_name = xaccSchedXactionGetName(sx);
xmlAttr *attr;
for (attr = tree->properties; attr != NULL; attr = attr->next)
{
xmlChar *attr_value = attr->children->content;
g_debug("sx attribute name[%s] value[%s]", attr->name, attr_value);
if (strcmp((const char *)attr->name, "version") != 0)
{
g_warning("unknown sx attribute [%s]", attr->name);
continue;
}
// if version == 1.0.0: ensure freqspec, no recurrence
// if version == 2.0.0: ensure recurrence, no freqspec.
if (strcmp((const char *)attr_value,
schedxaction_version_string) == 0)
{
if (!sx_pdata.saw_freqspec)
g_critical("did not see freqspec in version 1 sx [%s]", sx_name);
if (sx_pdata.saw_recurrence)
g_warning("saw recurrence in supposedly version 1 sx [%s]", sx_name);
}
if (strcmp((const char *)attr_value,
schedxaction_version2_string) == 0)
{
if (sx_pdata.saw_freqspec)
g_warning("saw freqspec in version 2 sx [%s]", sx_name);
if (!sx_pdata.saw_recurrence)
g_critical("did not find recurrence in version 2 sx [%s]", sx_name);
}
}
}
// generic_callback -> book_callback: insert the SX in the book
gdata->cb( tag, gdata->parsedata, sx );
/* FIXME: this should be removed somewhere near 1.8 release time. */
if ( sx->template_acct == NULL )
{
Account *ra = NULL;
const char *id = NULL;
Account *acct = NULL;
sixtp_gdv2 *sixdata = gdata->parsedata;
QofBook *book;
book = sixdata->book;
/* We're dealing with a pre-200107<near-end-of-month> rgmerk
change re: storing template accounts. */
/* Fix: get account with name of our GncGUID from the template
accounts. Make that our template_acct pointer. */
/* THREAD-UNSAFE */
id = guid_to_string( xaccSchedXactionGetGUID( sx ) );
ra = gnc_book_get_template_root(book);
if ( ra == NULL )
{
g_warning( "Error getting template root account from being-parsed Book." );
xmlFreeNode( tree );
return FALSE;
}
acct = gnc_account_lookup_by_name( ra, id );
if ( acct == NULL )
{
g_warning("no template account with name [%s]", id);
xmlFreeNode( tree );
return FALSE;
}
g_debug("template account name [%s] for SX with GncGUID [%s]",
xaccAccountGetName( acct ), id );
/* FIXME: free existing template account.
* HUH????? We only execute this if there isn't
* currently an existing template account, don't we?
* <rgmerk>
*/
sx->template_acct = acct;
}
done:
xmlFreeNode( tree );
return successful;
}
sixtp*
gnc_schedXaction_sixtp_parser_create(void)
{
return sixtp_dom_parser_new( gnc_schedXaction_end_handler, NULL, NULL );
}
static
gboolean
tt_act_handler( xmlNodePtr node, gpointer data )
{
gnc_template_xaction_data *txd = data;
Account *acc;
gnc_commodity *com;
acc = dom_tree_to_account(node, txd->book);
if ( acc == NULL )
{
return FALSE;
}
else
{
xaccAccountBeginEdit (acc);
/* Check for the lack of a commodity [signifying that the
pre-7/11/2001-CIT-change SX template Account was parsed [but
incorrectly]. */
if ( xaccAccountGetCommodity( acc ) == NULL )
{
#if 1
gnc_commodity_table* table;
table = gnc_commodity_table_get_table( txd->book );
com = gnc_commodity_table_lookup( table,
"template", "template" );
#else
/* FIXME: This should first look in the table of the
book, maybe? The right thing happens [WRT file
load/save] if we just _new all the time, but it
doesn't seem right. This whole block should go
away at some point, but the same concern still
applies for
SchedXaction.c:xaccSchedXactionInit... */
com = gnc_commodity_new( txd->book,
"template", "template",
"template", "template",
1 );
#endif
xaccAccountSetCommodity( acc, com );
}
txd->accts = g_list_append( txd->accts, acc );
}
return TRUE;
}
static
gboolean
tt_trn_handler( xmlNodePtr node, gpointer data )
{
gnc_template_xaction_data *txd = data;
Transaction *trn;
trn = dom_tree_to_transaction( node, txd->book );
if ( trn == NULL )
{
return FALSE;
}
else
{
txd->transactions = g_list_append( txd->transactions, trn );
}
return TRUE;
}
struct dom_tree_handler tt_dom_handlers[] =
{
{ GNC_ACCOUNT_TAG, tt_act_handler, 0, 0 },
{ GNC_TRANSACTION_TAG, tt_trn_handler, 0, 0 },
{ NULL, NULL, 0, 0 },
};
static gboolean
gnc_template_transaction_end_handler(gpointer data_for_children,
GSList* data_from_children,
GSList* sibling_data,
gpointer parent_data,
gpointer global_data,
gpointer *result,
const gchar *tag)
{
gboolean successful = FALSE;
xmlNodePtr tree = data_for_children;
gxpf_data *gdata = global_data;
QofBook *book = gdata->bookdata;
GList *n;
gnc_template_xaction_data txd;
txd.book = book;
txd.accts = NULL;
txd.transactions = NULL;
/* the DOM tree will have an account tree [the template
accounts] and a list of transactions [which will be members
of the template account].
we want to parse through the dom trees for each, placing
the null-parent account in the book's template-group slot,
the others under it, and the transactions as normal. */
if ( parent_data )
{
return TRUE;
}
if ( !tag )
{
return TRUE;
}
g_return_val_if_fail( tree, FALSE );
successful = dom_tree_generic_parse( tree, tt_dom_handlers, &txd );
if ( successful )
{
gdata->cb( tag, gdata->parsedata, &txd );
}
else
{
g_warning("failed to parse template transaction");
xmlElemDump( stdout, NULL, tree );
}
/* cleanup */
for ( n = txd.accts; n; n = n->next )
{
n->data = NULL;
}
for ( n = txd.transactions; n; n = n->next )
{
n->data = NULL;
}
g_list_free( txd.accts );
g_list_free( txd.transactions );
xmlFreeNode( tree );
return successful;
}
sixtp*
gnc_template_transaction_sixtp_parser_create( void )
{
return sixtp_dom_parser_new( gnc_template_transaction_end_handler,
NULL, NULL );
}