2002-08-06 Joshua Sled <jsled@asynchronous.org>

* src/gnome/dialog-scheduledxaction.c (gnc_sxed_check_consistent):
	The pre-defined variable 'i' no longer blocks transactions from
	being created "auto-create".

	* src/calculation/expression_parser.c: Added documentation for
	function support in the expression parser.

	* src/gnome/dialog-sxsincelast.c (create_each_transaction_helper):
	Scrub created splits so they get setup correctly, fixing the
	"incorrect-running-balance" problem [Bug#89879].
	Wrote the oft-procrastinated memory-cleanup code; ensured [most]
	other dynamic memory allocation is clean.  Removed some dead
	code/debugging.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@7144 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Joshua Sled
2002-08-06 22:46:58 +00:00
parent 7e36d8b42a
commit 8a034757cd
4 changed files with 250 additions and 226 deletions

View File

@@ -1,3 +1,19 @@
2002-08-06 Joshua Sled <jsled@asynchronous.org>
* src/gnome/dialog-scheduledxaction.c (gnc_sxed_check_consistent):
The pre-defined variable 'i' no longer blocks transactions from
being created "auto-create".
* src/calculation/expression_parser.c: Added documentation for
function support in the expression parser.
* src/gnome/dialog-sxsincelast.c (create_each_transaction_helper):
Scrub created splits so they get setup correctly, fixing the
"incorrect-running-balance" problem [Bug#89879].
Wrote the oft-procrastinated memory-cleanup code; ensured [most]
other dynamic memory allocation is clean. Removed some dead
code/debugging.
2002-08-06 David Hampton <hampton@employees.org>
* doc/sgml/*/Makefile.am: Tweak for newer versions of db2html.

View File

@@ -20,6 +20,8 @@
* 6-21-2000
*/
/* Modified to support functions - Summer, 2002 -- jsled@asynchronous.org */
/* expression parser/evaluator use:
*
* Before describing the parser per se, I want to describe the
@@ -43,6 +45,9 @@
* "value" variable points to a user defined structure containing the
* numeric value of the variable.
*
* As well, variables now have a VarStoreType, to distinguish between numeric
* and string values, as we want string arguments to functions.
*
* In designing and writing the parser, I decided early on that the
* parser should be an "expression parser/evaluator" and that the
* actual arithmetic was the responsibility of the caller/user.
@@ -117,6 +122,8 @@
* 4: free_numeric - this function is responsible for freeing memory
* used by the internal numeric representation.
*
* 5: func_op - this function is repsonsible for handling function calls.
*
* I have included the file "numeric_ops.c" containing the above
* functions for the usual "double" and "int" representation of
* numerics. The functions perform integer or floating point
@@ -173,6 +180,12 @@
* is responsible for freeing any memory used by the "pre-defined"
* variables and their final numeric representation.
*
* There may also be strings in the expression, by quoting them in '"'
* characters. These are intended to be passed literally into functions; the
* result of using a string in a numeric operation is undefined. Presently,
* the expression-parser code does not check the variable types during
* parsing or evaluation.
*
* A second design goal of the parser was that it should be callable
* concurrently by multiple modules independently. That each module
* should be capable of using differing "pre-defined" variables and
@@ -249,6 +262,14 @@
* After parsing the above expressions the variables nni, jk, tyh and
* tgh would all be defined.
*
* Functiosn are invoked with expressions of the format
*
* [_a-zA-Z]( <argument_0> : <argument_1> : ... : <argument_n> )
*
* where each argument can itself be a sub-expression [arithmetic operation
* or function call].
*
*
* There are six parser functions needed to use the parser/evaluator:
*
* Note: in the last five functions, in the function paramter (void
@@ -265,7 +286,8 @@
* void *left_value,
* void *right_value),
* void *negate_numeric(void *value),
* void free_numeric(void *numeric_value));
* void free_numeric(void *numeric_value),
* void *func_op(const char *fname, int argc, void **argv));
*
* This function is called by the module/function/whatever to
* initialize the parser. The parser returns a pointer to a

View File

@@ -458,7 +458,7 @@ static
gboolean
gnc_sxed_check_consistent( SchedXactionEditorDialog *sxed )
{
gboolean ttHasVars;
gint ttVarCount;
FreqSpec *fs;
/* FIXMEs...
@@ -480,7 +480,7 @@ gnc_sxed_check_consistent( SchedXactionEditorDialog *sxed )
* right... ]
*/
ttHasVars = FALSE;
ttVarCount = 0;
{
static const int NUM_ITERS_WITH_VARS = 5;
static const int NUM_ITERS_NO_VARS = 1;
@@ -493,6 +493,7 @@ gnc_sxed_check_consistent( SchedXactionEditorDialog *sxed )
Split *s;
gnc_numeric creditSum, debitSum, tmp;
gboolean unbalanceable;
gpointer unusedKey, unusedValue;
unbalanceable = FALSE; /* innocent until proven guilty */
vars = g_hash_table_new( g_str_hash, g_str_equal );
@@ -513,8 +514,8 @@ gnc_sxed_check_consistent( SchedXactionEditorDialog *sxed )
/* numeric-formulas-get-balanced determination */
sxsl_get_sx_vars( sxed->sx, vars );
ttHasVars = (g_hash_table_size( vars ) != 0);
if ( g_hash_table_size( vars ) != 0 ) {
ttVarCount = g_hash_table_size( vars );
if ( ttVarCount != 0 ) {
/* balance with random variable bindings some number
* of times in an attempt to ferret out
* un-balanceable transactions.
@@ -585,6 +586,13 @@ gnc_sxed_check_consistent( SchedXactionEditorDialog *sxed )
}
#endif /* DEBUG */
}
/* Subtract out pre-defined vars */
if ( g_hash_table_lookup_extended( vars, "i",
&unusedKey, &unusedValue ) ) {
ttVarCount -= 1;
}
g_hash_table_foreach( vars, free_var_numeric, (gpointer)vars );
g_hash_table_destroy( vars );
@@ -649,17 +657,17 @@ gnc_sxed_check_consistent( SchedXactionEditorDialog *sxed )
{
gboolean autocreateState, notifyState;
autocreateState = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(sxed->autocreateOpt) );
notifyState = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(sxed->notifyOpt) );
autocreateState =
gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(sxed->autocreateOpt) );
notifyState =
gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(sxed->notifyOpt) );
if ( ttHasVars && autocreateState ) {
/* FIXME: Wow... that's a mouthful. Reword. */
if ( (ttVarCount > 0) && autocreateState ) {
gnc_warning_dialog_parented( sxed->dialog,
_("You attempted to create a \"Create "
"Automatically\" "
"Scheduled Transaction which has Variables, "
"which is not allowed.\nPlease remove the "
"Create Automatically flag and try again.") );
_("Scheduled Transactions with variables\n"
"cannot be automatically created.") );
return FALSE;
}
}

View File

@@ -53,10 +53,12 @@
#include <gnome.h>
#include <glib.h>
#include "Account.h"
#include "Group.h"
#include "Query.h"
#include "SchedXaction.h"
#include "Transaction.h"
#include "Scrub.h"
#include "dialog-utils.h"
#include "finvar.h"
#include "gnc-book.h"
@@ -166,8 +168,7 @@ typedef struct _sxSinceLastData {
/** A HashTable of SX mapped to initial temporal data. */
GHashTable /* <SchedXaction*,void*> */ *sxInitStates;
/** The list of removed SXes, in case we need to revert/cancel. */
GList /* <toDeleteTuple*> */ *removedList;
/** The list of the GUIDs of _all_ transactions we've created. */
GList /* <GUID*> */ *createdTxnGUIDList;
@@ -226,7 +227,6 @@ typedef struct reminderInstanceTuple_ {
typedef struct toDeleteTuple_ {
SchedXaction *sx;
GDate *endDate;
gchar *freq_info;
gboolean isSelected;
} toDeleteTuple;
@@ -312,7 +312,11 @@ static void sx_obsolete_unselect_all_clicked( GtkButton *button,
gpointer user_data );
static void gnc_sxsld_free_tci( toCreateInstance *tci );
static void gnc_sxsld_free_toCreateTuple_list( GList *l );
static void gnc_sxsld_free_sxState( gpointer key,
gpointer value,
gpointer userdata );
static void gnc_sxsld_free_entry_numeric( GtkObject *o, gpointer ud );
/**
* Used to wrap for the book-open hook, where the book filename is given.
@@ -987,27 +991,19 @@ gnc_sxsld_finish( GnomeDruidPage *druid_page,
if ( g_list_length( cl->selection ) > 0 ) {
sxList = gnc_book_get_schedxactions( gnc_get_current_book() );
gnc_suspend_gui_refresh();
for ( toDelPtr = cl->selection;
toDelPtr;
toDelPtr = toDelPtr->next ) {
row = (gint)toDelPtr->data;
tdt = (toDeleteTuple*)gtk_clist_get_row_data( cl, row );
{
elt = g_list_find( sxList, tdt->sx );
sxList = g_list_remove_link( sxList, elt );
sxsld->removedList = g_list_concat( sxsld->removedList, elt );
}
{
elt = g_list_find( sxsld->toRemoveList, tdt );
sxsld->toRemoveList =
g_list_remove_link( sxsld->toRemoveList, elt );
g_list_free_1(elt);
}
g_date_free( tdt->endDate );
g_free( tdt );
elt = g_list_find( sxList, tdt->sx );
sxList = g_list_remove_link( sxList, elt );
xaccSchedXactionFree( (SchedXaction*)elt->data );
}
gnc_resume_gui_refresh();
gnc_book_set_schedxactions( gnc_get_current_book(), sxList );
}
@@ -1043,10 +1039,7 @@ cancel_check( GnomeDruidPage *druid_page,
"Are you sure you want to lose all "
"Scheduled Transaction changes?" );
DEBUG( "cancel_check" );
if ( g_list_length( sxsld->removedList ) == 0
&& g_list_length( sxsld->createdTxnGUIDList ) == 0 ) {
if ( g_list_length( sxsld->createdTxnGUIDList ) == 0 ) {
/* There's nothing to cancel, so just do so... */
return FALSE;
}
@@ -1056,7 +1049,6 @@ cancel_check( GnomeDruidPage *druid_page,
return TRUE;
}
DEBUG( "reverting SX changes...\n" );
/* Cancel policy:
* . deleted SXes
* . reborn
@@ -1069,47 +1061,20 @@ cancel_check( GnomeDruidPage *druid_page,
* . reminders -> created
* . Trans deleted
* . SXes reset
*
* SXes reset:
* SXes reset [we use the temporal-state-data to take care of this]
* . end_date || num_remain_instances
* . last_occur_date
*/
gnc_suspend_gui_refresh();
/* rebirth deleted SXes */
DEBUG( "There are %d SXes on the 'removedList' to re-birth",
g_list_length( sxsld->removedList ) );
if ( g_list_length( sxsld->removedList ) > 0 ) {
GList *sxList =
gnc_book_get_schedxactions( gnc_get_current_book () );
for ( l = sxsld->removedList; l; l = l->next ) {
DEBUG( "re-birthing SX \"%s\"",
xaccSchedXactionGetName( (SchedXaction*)l->data ) );
sxList = g_list_append( sxList,
(SchedXaction*)l->data );
}
gnc_book_set_schedxactions( gnc_get_current_book(),
sxList );
}
/* delete created transactions */
DEBUG( "length( sxsld->createdTxnGUIDList ): %d",
g_list_length( sxsld->createdTxnGUIDList ) );
/* destroy created transactions */
if ( g_list_length( sxsld->createdTxnGUIDList ) > 0 ) {
Transaction *t = NULL;
for ( l = sxsld->createdTxnGUIDList; l; l = l->next ) {
t = xaccTransLookup( (GUID*)l->data,
gnc_get_current_book() );
if ( t == NULL ) {
char *guidStr;
guidStr =
guid_to_string( (GUID*)l->data );
PERR( "We thought we created Transaction "
"\"%s\", but can't "
"xaccTransLookup(...) it now.",
guidStr );
free(guidStr);
break;
}
g_assert( t );
xaccTransBeginEdit( t );
xaccTransDestroy( t );
xaccTransCommitEdit( t );
@@ -1255,7 +1220,6 @@ generate_instances( SchedXaction *sx,
reminderTuple *rt;
reminderInstanceTuple *rit;
void *seqStateData;
char tmpBuf[GNC_D_BUF_WIDTH];
g_assert( g_date_valid(end) );
g_assert( g_date_valid(reminderEnd) );
@@ -1322,24 +1286,6 @@ generate_instances( SchedXaction *sx,
seqStateData = NULL;
}
#if 0
static void
free_gdate_list_elts( gpointer data, gpointer user_data )
{
g_date_free( (GDate*)data );
}
#endif
#if 0
static void
_free_reminderTuple_list_elts( gpointer data, gpointer user_data )
{
/* FIXME: endDate? */
g_date_free( ((reminderTuple*)data)->occurDate );
g_free( (reminderTuple*)data );
}
#endif
static void
_free_varBindings_hash_elts( gpointer key, gpointer value, gpointer data )
{
@@ -1413,8 +1359,9 @@ process_auto_create_list( GList *autoCreateList, sxSinceLastData *sxsld )
tci = (toCreateInstance*)instances->data;
thisGUID = createdGUIDs = NULL;
create_transactions_on( tct->sx,
(GDate*)tci->date,
NULL, &createdGUIDs );
tci->date,
tci,
&createdGUIDs );
count++;
gtk_progress_set_value( GTK_PROGRESS(sxsld->prog), count );
@@ -1449,7 +1396,6 @@ add_to_create_list_to_gui( GList *toCreateList, sxSinceLastData *sxsld )
GtkCTreeNode *sxNode;
char *rowText[ TO_CREATE_LIST_WIDTH ];
GList *insts;
gpointer unusedkey, unusedvalue;
ct = GTK_CTREE( glade_xml_get_widget( sxsld->gxml, TO_CREATE_LIST ) );
@@ -1532,6 +1478,8 @@ add_reminders_to_gui( GList *reminderList, sxSinceLastData *sxsld )
NULL, NULL, NULL, NULL, /* pixmaps */
FALSE, /* leafP */
TRUE ); /* expandedP */
g_string_free( freqSpecStr, TRUE );
/* The SX node itself isn't selectable; only the
* instances. */
gtk_ctree_node_set_selectable( ctree, sxNode, FALSE );
@@ -1568,7 +1516,6 @@ add_reminders_to_gui( GList *reminderList, sxSinceLastData *sxsld )
g_free( rowText[0] );
g_free( rowText[2] );
}
g_string_free( freqSpecStr, TRUE );
}
}
@@ -1581,18 +1528,18 @@ add_dead_list_to_gui(GList *removeList, sxSinceLastData *sxsld)
GString *tmp_str;
toDeleteTuple *tdt;
FreqSpec *fs;
rowtext[2] = g_new0(gchar, GNC_D_BUF_WIDTH );
cl = GTK_CLIST( glade_xml_get_widget( sxsld->gxml,
SX_OBSOLETE_CLIST ));
tmp_str = g_string_new(NULL);
rowtext[2] = g_new0(gchar, GNC_D_BUF_WIDTH );
gtk_clist_freeze( cl );
gtk_clist_clear( cl );
gtk_signal_handler_block_by_func( GTK_OBJECT(cl),
sxsld_obsolete_row_toggle,
sxsld );
for ( row = 0; removeList;
row++, removeList = removeList->next ) {
tdt = (toDeleteTuple*)removeList->data;
@@ -1608,6 +1555,7 @@ add_dead_list_to_gui(GList *removeList, sxSinceLastData *sxsld)
* last valid one. :( Or, even better, the reason for
* obsolesence. */
/*g_date_strftime( rowtext[2], GNC_D_WIDTH, GNC_D_FMT, tdt->endDate ); */
strcpy( rowtext[2], "obsolete" );
gtk_clist_insert( cl, row, rowtext );
@@ -1672,7 +1620,8 @@ processSelectedReminderList( GList *goodList, sxSinceLastData *sxsld )
tci = g_new0( toCreateInstance, 1 );
tci->dirty = FALSE;
tci->parentTCT = tct;
tci->date = rit->occurDate;
tci->date = g_date_new();
*tci->date = *rit->occurDate;
tci->varBindings = NULL;
tci->instanceNum = rit->instanceNum;
tci->node = NULL;
@@ -1790,22 +1739,6 @@ sxsincelast_populate( sxSinceLastData *sxsld )
return showIt;
}
static void
clean_sincelast_dlg( sxSinceLastData *sxsld )
{
GtkWidget *w;
/* . clean out to-create clist
* . free associated memories.
*
* FIXME: other dlg stuff to clean?
*/
clean_variable_table( sxsld );
w = glade_xml_get_widget( sxsld->gxml, TO_CREATE_LIST );
gtk_clist_clear( GTK_CLIST(w) );
}
static void
sxsincelast_close_handler( gpointer ud )
{
@@ -1813,9 +1746,8 @@ sxsincelast_close_handler( gpointer ud )
gtk_widget_hide( sxsld->sincelast_window );
sxsincelast_save_size( sxsld );
clean_sincelast_dlg( sxsld );
gtk_widget_destroy( sxsld->sincelast_window );
clean_sincelast_data( sxsld );
/* The data will be cleaned up in the destroy handler. */
}
static void
@@ -1858,8 +1790,10 @@ sxsincelast_entry_changed( GtkEditable *e, gpointer ud )
"gnc_numeric-parseable", entryText );
num = NULL;
} else {
#if 0 /* 0 -- this is fine. */
DEBUG( "\"%s\" parses as \"%f\"", entryText,
gnc_numeric_to_double( *num ) );
#endif /* 0 -- this is fine. */
}
g_hash_table_destroy( dummyVarHash );
@@ -1879,9 +1813,8 @@ sxsincelast_entry_changed( GtkEditable *e, gpointer ud )
if ( maybeValue ) {
g_free( maybeValue );
}
/* FIXME: Does the maybeKey need to be freed? */
}
g_hash_table_insert( tci->varBindings, maybeKey, ourNum );
g_hash_table_insert( tci->varBindings, varName, ourNum );
tci->dirty = TRUE;
}
@@ -1902,18 +1835,21 @@ sxsincelast_destroy( GtkObject *o, gpointer ud )
{
sxSinceLastData *sxsld = (sxSinceLastData*)ud;
gnc_unregister_gui_component_by_data( DIALOG_SXSINCELAST_CM_CLASS,
sxsld->sincelast_window );
/* appropriate place to destroy data structures */
clean_sincelast_data( sxsld );
/* FIXME: need more freeing for ledgers? why do these result in
* "gnc_close_gui_component: component not found" messages? */
gnc_ledger_display_close( sxsld->ac_ledger );
/* FIXME: need more freeing for ac_ledger? */
sxsld->ac_ledger = NULL;
gnc_ledger_display_close( sxsld->created_ledger );
/* FIXME: need more freeing for created_ledger? */
sxsld->created_ledger = NULL;
gnc_unregister_gui_component_by_data( DIALOG_SXSINCELAST_CM_CLASS,
sxsld->sincelast_window );
g_free( sxsld );
}
@@ -1982,24 +1918,9 @@ create_each_transaction_helper( Transaction *t, void *d )
/* FIXME: when we copy the trans_onto_trans, we don't want to copy
the Split's kvp_frames... */
/* FIXME: This should setup the predefined variables 'i' and 'N' */
createUD = (createData*)d;
tci = createUD->tci;
actualVars = g_hash_table_new( g_str_hash, g_str_equal );
if ( tci->varBindings != NULL ) {
g_hash_table_foreach( tci->varBindings,
gnc_sxsl_copy_ea_hash, actualVars );
}
varIValue = g_new0( gnc_numeric, 1 );
*varIValue = gnc_numeric_create( tci->instanceNum, 1 );
/* It's really important that we strdup "i" here, so we can
* generically cleanup with a simple 'foreach' that blindly frees the
* keys, below. */
g_hash_table_insert( actualVars, g_strdup("i"), varIValue );
newT = xaccMallocTransaction(gnc_get_current_book ());
xaccTransBeginEdit( newT );
/* the action and description/memo are in the template */
@@ -2015,26 +1936,41 @@ create_each_transaction_helper( Transaction *t, void *d )
sList = xaccTransGetSplitList( newT );
if ( (osList == NULL) || (sList == NULL) ) {
PERR( "\tseen transaction w/o splits. :(" );
/* FIXME: we've allocated things we need to cleanup... */
xaccTransDestroy( newT );
xaccTransCommitEdit( newT );
return FALSE;
}
/* Setup the predefined variables for credit/debit formula
* processing. */
actualVars = g_hash_table_new( g_str_hash, g_str_equal );
if ( tci->varBindings != NULL ) {
g_hash_table_foreach( tci->varBindings,
gnc_sxsl_copy_ea_hash, actualVars );
}
varIValue = g_new0( gnc_numeric, 1 );
*varIValue = gnc_numeric_create( tci->instanceNum, 1 );
/* It's really important that we strdup "i" here, so we can
* generically cleanup with a simple 'foreach' that blindly frees the
* keys, below. */
g_hash_table_insert( actualVars, g_strdup("i"), varIValue );
for ( ; sList && osList ;
sList = sList->next, osList = osList->next ) {
split = (Split*)sList->data;
Account *acct;
/* FIXME: Ick. This assumes that the split lists will be
ordered identically. :( I think it's fair to say they
will, but I'd rather not have to count on it. --jsled */
split_kvpf = xaccSplitGetSlots( (Split*)osList->data );
/* from-transaction of splits */
/* FIXME: is this true? -- seems like it should be the other
* way around; perhaps this is the reason for Bug#89879? */
/* This needs to be before the value setting [below] so the
* balance calculations can work. */
{
GUID *acct_guid;
Account *acct;
/* contains the guid of the split's actual account. */
kvp_val = kvp_frame_get_slot_path( split_kvpf,
GNC_SX_ID,
@@ -2060,10 +1996,8 @@ create_each_transaction_helper( Transaction *t, void *d )
commonCommodity = xaccAccountGetCommodity( acct );
xaccAccountBeginEdit( acct );
xaccAccountInsertSplit( acct, split );
xaccAccountCommitEdit( acct );
}
/* commonCommodity = xaccTransGetCurrency( t ); */
/* credit/debit formulas */
{
@@ -2133,9 +2067,9 @@ create_each_transaction_helper( Transaction *t, void *d )
#endif /* 0 -- debug */
xaccSplitSetValue( split, final );
xaccSplitScrub( split );
}
#if 0
/* NOT [YET] USED */
kvp_val = kvp_frame_get_slot_path( split_kvpf,
@@ -2149,8 +2083,10 @@ create_each_transaction_helper( Transaction *t, void *d )
NULL);
#endif /* 0 */
xaccAccountCommitEdit( acct );
}
/* Cleanup actualVars table. */
{
g_hash_table_foreach( actualVars,
@@ -2216,47 +2152,15 @@ create_transactions_on( SchedXaction *sx,
toCreateTuple *tct;
gboolean createdTCT;
#if 0
{
char tmpBuf[GNC_D_WIDTH];
g_date_strftime( tmpBuf, GNC_D_WIDTH, GNC_D_FMT, gd );
DEBUG( "Creating transactions on %s for %s",
tmpBuf, xaccSchedXactionGetName( sx ) );
}
#endif /* 0 */
if ( tci != NULL
&& g_date_compare( gd, tci->date ) != 0 ) {
PERR( "GDate and TCI date aren't equal, "
"which isn't a Good Thing." );
return;
}
tct = NULL;
createdTCT = FALSE;
if ( tci == NULL ) {
/* Create a faux tct for the creation-helper. */
tct = g_new0( toCreateTuple, 1 );
tci = g_new0( toCreateInstance, 1 );
/* FIXME: add instance num */
tct->sx = sx;
tct->instanceList =
g_list_append( tct->instanceList, tci );
tci->dirty = FALSE;
tci->date = gd;
tci->node = NULL;
tci->parentTCT = tct;
createdTCT = TRUE;
if ( tci ) {
g_assert( g_date_compare( gd, tci->date ) == 0 );
}
ag = gnc_book_get_template_group( gnc_get_current_book () );
id = guid_to_string( xaccSchedXactionGetGUID(sx) );
if(ag && id)
{
if ( ag && id ) {
acct = xaccGetAccountFromName( ag, id );
if(acct)
{
if ( acct ) {
createUD.tci = tci;
createUD.createdGUIDs = createdGUIDs;
xaccAccountForEachTransaction( acct,
@@ -2265,8 +2169,7 @@ create_transactions_on( SchedXaction *sx,
}
}
if (id)
{
if (id) {
g_free( id );
}
@@ -2282,14 +2185,6 @@ create_transactions_on( SchedXaction *sx,
xaccSchedXactionSetRemOccur( sx, tmp-1 );
}
}
if ( createdTCT ) {
g_free( tci );
g_list_free( tct->instanceList );
g_free( tct );
tci = NULL;
tct = NULL;
}
}
static void
@@ -2393,7 +2288,7 @@ tct_table_entry_key_handle( GtkWidget *widget, GdkEventKey *event, gpointer ud )
gtk_entry_set_text( ent, str->str );
g_string_free( str, TRUE );
/* Next, deal with tab-ordering in this page... */
/* FIXME: Next, deal with tab-ordering in this page... */
// if ( entry isn't last in table )
// return (normal)FALSE
@@ -2514,6 +2409,9 @@ sxsincelast_tc_row_sel( GtkCTree *ct,
gtk_signal_connect( GTK_OBJECT(entry), "changed",
GTK_SIGNAL_FUNC( sxsincelast_entry_changed ),
sxsld );
gtk_signal_connect( GTK_OBJECT(entry), "destroy",
GTK_SIGNAL_FUNC(gnc_sxsld_free_entry_numeric),
sxsld );
gtk_table_attach( varTable, label,
0, 1, tableIdx, tableIdx + 1,
@@ -2531,19 +2429,15 @@ static void
clean_variable_table( sxSinceLastData *sxsld )
{
GtkTable *table;
GList *children, *toFree;
GList *children, *toFree, *l;
GtkTableChild *child;
table = GTK_TABLE( glade_xml_get_widget( sxsld->gxml,
VARIABLE_TABLE ) );
children = table->children;
toFree = NULL;
if ( children == NULL ) {
PERR( "The variable-binding table should always have at "
"least 2 children... something's amiss." );
return;
}
g_assert( children );
toFree = NULL;
for( ; children ; children = children->next ) {
/* Destroy all children after the first [label-continaing]
row... ie, leave the labels in place. */
@@ -2555,9 +2449,8 @@ clean_variable_table( sxSinceLastData *sxsld )
gtk_table_resize( table, 1, 2 );
while ( toFree != NULL ) {
gtk_widget_destroy( (GtkWidget*)toFree->data );
toFree = toFree->next;
for ( l = toFree; l; l = l->next ) {
gtk_widget_destroy( (GtkWidget*)l->data );
}
g_list_free( toFree );
}
@@ -2572,7 +2465,8 @@ sxsincelast_tc_row_unsel( GtkCTree *ct,
sxsld = (sxSinceLastData*)user_data;
clean_variable_table( sxsld );
/* FIXME: need to cleanup the gnc_numerics we allocated */
/* we cleanup the gnc_numerics we allocated in the "destroy" signal
* handler of the entry [where we attached them] */
}
void
@@ -2598,6 +2492,7 @@ parse_vars_from_formula( const char *formula,
num = g_new0( gnc_numeric, 1 );
}
toRet = 0;
if ( ! gnc_exp_parser_parse_separate_vars( formula, num,
&errLoc, varHash ) ) {
#if 0 /* just too verbose, as "Numeric errors" are acceptable in this
@@ -2606,11 +2501,8 @@ parse_vars_from_formula( const char *formula,
errLoc, gnc_exp_parser_error_string() );
#endif /* 0 */
toRet = -1;
goto cleanup;
}
toRet = 0;
cleanup:
if ( !result ) {
g_free( num );
}
@@ -2778,14 +2670,17 @@ gnc_sxsld_revert_reminders( sxSinceLastData *sxsld,
xaccSchedXactionGetAutoCreate( rit->parentRT->sx,
&autoCreateState,
&notifyState );
correctList = NULL;
if ( autoCreateState ) {
correctList = &sxsld->autoCreateList;
if ( notifyState ) {
correctList = &sxsld->autoCreateList;
}
} else {
correctList = &sxsld->toCreateList;
}
*correctList = g_list_remove( *correctList, tct );
if ( correctList )
*correctList = g_list_remove( *correctList, tct );
}
/* destroy any created transactions. */
@@ -2793,18 +2688,22 @@ gnc_sxsld_revert_reminders( sxSinceLastData *sxsld,
for ( m = tci->createdTxnGUIDs; m; m = m->next ) {
Transaction *t;
sxsld->createdTxnGUIDList =
g_list_remove( sxsld->createdTxnGUIDList,
(GUID*)m->data );
t = xaccTransLookup( (GUID*)m->data,
gnc_get_current_book() );
g_assert( t );
xaccTransBeginEdit(t);
xaccTransDestroy(t);
xaccTransCommitEdit(t);
}
gnc_resume_gui_refresh();
/* FIXME: Free the now-dead TCI; this is buggy and causing
/* Free the now-dead TCI; this is buggy and causing
* problems... */
//gnc_sxsld_free_tci( tci );
gnc_sxsld_free_tci( tci );
rit->resultantTCI = NULL;
}
}
@@ -2887,7 +2786,7 @@ inform_or_add( reminderTuple *rt, gboolean okFlag,
if ( okFlag ) {
/* Add selected instances of this rt to
okay-to-add-to-toCreateList list. */
* okay-to-add-to-toCreateList list. */
for ( instances = rt->instanceList;
instances;
instances = instances->next ) {
@@ -2899,6 +2798,7 @@ inform_or_add( reminderTuple *rt, gboolean okFlag,
}
} else {
/* [Add to list for later] dialog issuance to user. */
userMsg = g_string_sized_new( 128 );
g_string_sprintf( userMsg,
"You cannot skip instances of Scheduled Transactions.\n"
@@ -2907,6 +2807,7 @@ inform_or_add( reminderTuple *rt, gboolean okFlag,
xaccSchedXactionGetName( rt->sx ) );
g_list_foreach( badList, create_bad_reminders_msg, userMsg );
gnc_error_dialog( userMsg->str );
g_string_free( userMsg, TRUE );
}
return okFlag;
@@ -3040,25 +2941,59 @@ sxsld_ledger_get_parent( GNCLedgerDisplay *ld )
static void
clean_sincelast_data( sxSinceLastData *sxsld )
{
/* FIXME: much more to go, here. */
g_list_foreach( sxsld->toCreateList, _free_toCreate_list_elts, NULL );
if ( sxsld->toCreateList ) {
g_list_free( sxsld->toCreateList );
sxsld->toCreateList = NULL;
GList *l, *m;
/* Free the reminder list */
for ( l = sxsld->reminderList; l; l = l->next ) {
reminderTuple *rt;
reminderInstanceTuple *rit;
rt = (reminderTuple*)l->data;
for ( m = rt->instanceList; m; m = m->next ) {
rit = (reminderInstanceTuple*)m->data;
g_date_free( rit->endDate );
g_date_free( rit->occurDate );
g_free( rit );
}
g_list_free( rt->instanceList );
rt->instanceList = NULL;
g_free( rt );
}
#if 0
g_list_foreach( autoCreateList, free_gdate_list_elts, NULL );
g_list_free( autoCreateList );
autoCreateList = NULL;
g_list_free( sxsld->reminderList );
/* We have moved the GDates over to the toCreateList in
* sxsld, so we don't free them here. */
g_list_free( toCreateList );
toCreateList = NULL;
g_list_free( instanceList );
instanceList = NULL;
#endif /* 0 */
/* Free the auto-create and to-create lists */
gnc_sxsld_free_toCreateTuple_list( sxsld->autoCreateList );
g_list_free( sxsld->autoCreateList );
sxsld->autoCreateList = NULL;
gnc_sxsld_free_toCreateTuple_list( sxsld->toCreateList );
g_list_free( sxsld->toCreateList );
sxsld->toCreateList = NULL;
/* Free the to-remove list */
for ( l = sxsld->toRemoveList; l; l = l->next ) {
toDeleteTuple *tdt;
tdt = (toDeleteTuple*)l->data;
g_date_free( tdt->endDate );
tdt->endDate = NULL;
g_free( tdt );
}
g_list_free( sxsld->toRemoveList );
sxsld->toRemoveList = NULL;
/* free the created-txn-guid list */
g_list_free( sxsld->createdTxnGUIDList );
sxsld->createdTxnGUIDList = NULL;
/* Free the saved SX temporal states */
g_hash_table_foreach( sxsld->sxInitStates,
gnc_sxsld_free_sxState,
NULL );
g_hash_table_destroy( sxsld->sxInitStates );
sxsld->sxInitStates = NULL;
}
@@ -3072,7 +3007,9 @@ gnc_sxsld_free_tci( toCreateInstance *tci )
}
if ( tci->varBindings ) {
/* FIXME: free keys/values, too. */
g_hash_table_foreach( tci->varBindings,
_free_varBindings_hash_elts,
NULL );
g_hash_table_destroy( tci->varBindings );
tci->varBindings = NULL;
}
@@ -3086,3 +3023,44 @@ gnc_sxsld_free_tci( toCreateInstance *tci )
g_free( tci );
}
/**
* Frees a list of toCreateTuples, like the autoCreateList and
* toCreateList.
**/
static
void
gnc_sxsld_free_toCreateTuple_list( GList *l )
{
GList *m;
toCreateTuple *tct;
for ( ; l; l = l->next ) {
tct = (toCreateTuple*)l->data;
for ( m = tct->instanceList; m; m = m->next ) {
gnc_sxsld_free_tci( (toCreateInstance*)m->data );
}
g_list_free( tct->instanceList );
tct->instanceList = NULL;
g_free( tct );
}
}
static
void
gnc_sxsld_free_sxState( gpointer key,
gpointer value,
gpointer userdata )
{
gnc_sx_destroy_temporal_state_snapshot( (void*)value );
}
static
void
gnc_sxsld_free_entry_numeric( GtkObject *o, gpointer ud )
{
gnc_numeric *num;
num = (gnc_numeric*)gtk_object_get_data( o, "numeric" );
g_free( num );
}