2002-07-24 Joshua Sled <jsled@asynchronous.org>

* src/scm/fin.scm: Made the exposed calcualtion functions output
	positive values.

	* src/gnome/window-main.c (gnc_main_window_create_menus): Added
	accelerators to SX-related menu items.

	* src/gnome/druid-loan.c: Primary change: actually create the
	Scheduled Transactions which are setup by the user.  Miscellaneous
	other cleanups, text, layout and consistency changes.

	* src/gnome/dialog-sxsincelast.c: Support handling of the
	instance-count in forward-looking transaction creation.  Simplfied
	some of the internal data-representation regarding lists of items
	to be created [removed autoCreateTuple, now uses toCreateTuple].
	Removed some DEBUGging output.  Handles setting up the implicit
	'i' variable.

	* src/gnome/dialog-sx-from-trans.c (sxftd_compute_sx): Create SXes
	with an appropriate initial instance-count value.

	* src/gnome/dialog-scheduledxaction.c
	(schedXact_editor_populate): Create SXes with an appropriate
	initial instance-count value.

	* src/engine/SchedXaction.[ch]: Added support for an
	instance-count, in order to support an implicit 'i' [of N]
	variable to SX formula/function processing.

	* src/engine/SX-ttinfo.c (gnc_ttsplitinfo_free): Made the
	ttsplitinfo_free'ing a bit safer.

	* src/calculation/expression_parser.c: Added support for
	parsing/handling quoted strings.  Intended to be parameters to
	functions.  Fixed bug regarding nested handling of strings in the
	parser.

	* src/backend/file/gnc-schedxaction-xml-v2.c: Added support for
	saving/restoring instance-count field of SXes.

	* src/app-utils/test/test-exp-parser.c
	(run_parser_test): Fixed pass/fail indication check.
	(test_parser): Added tests for string params to functions.

	* ChangeLog: Added entry I forgot from last time.

	* src/app-utils/gnc-exp-parser.c (func_op): Added support for
	typed parameters to functions; params are either numerics or
	strings.  Result of function is now parsed correctly.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@7125 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Joshua Sled 2002-07-24 22:04:57 +00:00
parent 2a990a6cfd
commit 135289725c
19 changed files with 1342 additions and 2223 deletions

View File

@ -1,3 +1,54 @@
2002-07-24 Joshua Sled <jsled@asynchronous.org>
* src/scm/fin.scm: Made the exposed calcualtion functions output
positive values.
* src/gnome/window-main.c (gnc_main_window_create_menus): Added
accelerators to SX-related menu items.
* src/gnome/druid-loan.c: Primary change: actually create the
Scheduled Transactions which are setup by the user. Miscellaneous
other cleanups, text, layout and consistency changes.
* src/gnome/dialog-sxsincelast.c: Support handling of the
instance-count in forward-looking transaction creation. Simplfied
some of the internal data-representation regarding lists of items
to be created [removed autoCreateTuple, now uses toCreateTuple].
Removed some DEBUGging output. Handles setting up the implicit
'i' variable.
* src/gnome/dialog-sx-from-trans.c (sxftd_compute_sx): Create SXes
with an appropriate initial instance-count value.
* src/gnome/dialog-scheduledxaction.c
(schedXact_editor_populate): Create SXes with an appropriate
initial instance-count value.
* src/engine/SchedXaction.[ch]: Added support for an
instance-count, in order to support an implicit 'i' [of N]
variable to SX formula/function processing.
* src/engine/SX-ttinfo.c (gnc_ttsplitinfo_free): Made the
ttsplitinfo_free'ing a bit safer.
* src/calculation/expression_parser.c: Added support for
parsing/handling quoted strings. Intended to be parameters to
functions. Fixed bug regarding nested handling of strings in the
parser.
* src/backend/file/gnc-schedxaction-xml-v2.c: Added support for
saving/restoring instance-count field of SXes.
* src/app-utils/test/test-exp-parser.c
(run_parser_test): Fixed pass/fail indication check.
(test_parser): Added tests for string params to functions.
* ChangeLog: Added entry I forgot from last time.
* src/app-utils/gnc-exp-parser.c (func_op): Added support for
typed parameters to functions; params are either numerics or
strings. Result of function is now parsed correctly.
2002-07-24 Christian Stimming <stimming@tuhh.de>
* src/import-export/hbci/glade/hbci.glade: Some HBCI GUI work --
@ -13,6 +64,16 @@
* src/backend/file/gnc-backend-file.c: File permission fix by Matt
Brubeck <mbrubeck@cs.hmc.edu>
2002-07-12 Joshua Sled <jsled@asynchronous.org>
* src/gnome/glade/sched-xact.glade: Glade-side UI cleanup.
* src/gnome/druid-loan.c: Many updates; now uses GNCAccountSel,
more inter-page consistency checks. UI cleanup
* src/gnome-utils/gnc-account-sel.[ch]: Added; GTK combobox for
selecting an Account.
2002-07-11 Derek Atkins <derek@ihtfp.com>
* change gncEntry->account into gncEntry->invAccount and

View File

@ -350,6 +350,8 @@ func_op( const char *fname,
{
SCM scmFn, scmArgs, scmTmp;
int i;
var_store *vs;
gchar *str;
gnc_numeric n, *result;
GString *realFnName;
@ -365,15 +367,37 @@ func_op( const char *fname,
scmArgs = gh_list( SCM_UNDEFINED );
for ( i=0; i<argc; i++ ) {
/* cons together back-to-front. */
n = *(gnc_numeric*)argv[argc - i - 1];
scmTmp = gh_double2scm( gnc_numeric_to_double( n ) );
vs = (var_store*)argv[argc - i - 1];
switch ( vs->type ) {
case VST_NUMERIC:
n = *(gnc_numeric*)(vs->value);
scmTmp = gh_double2scm( gnc_numeric_to_double( n ) );
break;
case VST_STRING:
str = (char*)(vs->value);
scmTmp = gh_str2scm( str, strlen(str) );
break;
default:
/* FIXME: error */
printf( "argument %d not a numeric or string [type = %d]\n",
i, vs->type );
return NULL;
break; /* notreached */
}
scmArgs = gh_cons( scmTmp, scmArgs );
}
scmTmp = gh_apply( scmFn, scmArgs );
result = g_new0( gnc_numeric, 1 );
*result = double_to_gnc_numeric( gh_scm2double(scmTmp), 1,
GNC_DENOM_SIGFIG | (6<<8) );
*result = double_to_gnc_numeric( gh_scm2double(scmTmp),
GNC_DENOM_AUTO,
GNC_DENOM_SIGFIGS(6) | GNC_RND_ROUND );
/* I'm not sure why this explicit negation step is necessary, but it
* doesn't seem like it should be. */
if ( gh_scm2double( scmTmp ) < 0 ) {
*result = gnc_numeric_neg( *result );
}
/* FIXME: cleanup scmArgs = gh_list, cons'ed cells? */
return (void*)result;
}

View File

@ -8,6 +8,8 @@
#include "gnc-numeric.h"
#include "test-stuff.h"
void real_main (int argc, char **argv);
static GList *tests = NULL;
typedef struct
@ -62,12 +64,12 @@ run_parser_test (TestNode *node)
succeeded = gnc_exp_parser_parse (node->exp, &result, &error_loc);
{
int pass;
pass = succeeded;
pass ^= node->should_succeed;
pass = !pass;
printf( "%0.2f [%s]\n",
( ( pass && node->should_succeed ) ?
gnc_numeric_to_double( result ) : 0.0 ),
pass = (succeeded == node->should_succeed);
if ( pass && node->should_succeed ) {
pass &= gnc_numeric_equal( result, node->expected_result );
}
printf( "%0.4f [%s]\n",
gnc_numeric_to_double( result ),
(pass ? "PASS" : "FAIL" ) );
}
@ -139,7 +141,7 @@ test_parser (void)
"- 42.72 + 13.32 + 15.48 + 23.4 + 115.4",
gnc_numeric_create(35897, 100) );
gh_eval_str( "(define (plus a b) (+ a b))" );
gh_eval_str( "(define (gnc:plus a b) (+ a b))" );
add_pass_test( "plus( 1 : 2 ) + 3", NULL, gnc_numeric_create( 6, 1 ) );
add_pass_test( "plus( 1 : 2 ) * 3", NULL, gnc_numeric_create( 9, 1 ) );
add_pass_test( "plus( 1 + 2 : 3 ) * 5", NULL, gnc_numeric_create( 30, 1 ) );
@ -148,14 +150,31 @@ test_parser (void)
add_pass_test( "plus( plus( 1 : 2 ) : 3 )", NULL, gnc_numeric_create( 6, 1 ) );
add_pass_test( "plus( 4 : plus( plus( 1 : 2 ) : 3))", NULL, gnc_numeric_create( 10, 1 ) );
gh_eval_str( "(define (foo a b) (+ a b))" );
add_pass_test( "foo( 1 : 2 ) + 4", NULL, gnc_numeric_create( 7, 1 ) );
gh_eval_str( "(define (gnc:foo a b) (- a b))" );
add_pass_test( "foo( 1 : 2 ) + 4", NULL, gnc_numeric_create( 3, 1 ) );
add_pass_test( "foo( (1 + 2 * 3) : 4 ) + 5",
NULL, gnc_numeric_create( 16, 1 ) );
NULL, gnc_numeric_create( 8, 1 ) );
add_pass_test( "foo( 1 : 2 ) + foo( 3 : 4 ) + 5",
NULL, gnc_numeric_create( 15, 1 ) );
add_pass_test( "foo( a = 42 : foo( foo( 1 : 2 ) : 6 * 7 )) + a",
NULL, gnc_numeric_create( 129, 1 ) );
NULL, gnc_numeric_create( 3, 1 ) );
add_pass_test( "foo( a = 42 : foo( plus( 1 : 2 ) : 6 * 7 )) + a",
NULL, gnc_numeric_create( 123, 1 ) );
gh_eval_str( "(define (gnc:test_str str b)"
" (+ b (cond ((equal? str \"one\") 1)"
" ((equal? str \"two\") 2)"
" ((equal? str \"three\") 3)"
" (0))))" );
add_pass_test( "test_str( \"one\" : 1 )", NULL, gnc_numeric_create( 2, 1 ) );
add_pass_test( "test_str( \"two\" : 2 )", NULL, gnc_numeric_create( 4, 1 ) );
add_fail_test( "test_str( 3 : \"three\" )", NULL, 0 );
add_pass_test( "test_str( \"asdf\" : 1 )", NULL, gnc_numeric_create( 1, 1 ) );
add_fail_test( "\"asdf\" + 0", NULL, 0 );
gh_eval_str( "(define (gnc:blindreturn val) val)" );
add_pass_test( "blindreturn( 123.1 )", NULL, gnc_numeric_create( 1231, 10 ) );
add_pass_test( "blindreturn( 123.01 )", NULL, gnc_numeric_create( 12301, 100 ) );
add_pass_test( "blindreturn( 123.001 )", NULL, gnc_numeric_create( 123001, 1000 ) );
run_parser_tests ();
@ -163,7 +182,7 @@ test_parser (void)
success ("shutdown expression parser");
}
int
void
real_main (int argc, char **argv)
{
/* set_should_print_success (TRUE); */
@ -176,5 +195,5 @@ int main( int argc, char **argv )
{
/* do things this way so we can test scheme function calls from expressions */
gh_enter( argc, argv, real_main );
return 0;
}

View File

@ -59,6 +59,7 @@ static short module = MOD_SX;
* <sx:autoCreateNotify>n</sx:autoCreateNotify>
* <sx:advanceCreateDays>0</sx:advanceCreateDays>
* <sx:advanceRemindDays>5</sx:advanceRemindDays>
* <sx:instanceCount>100</sx:instanceCount>
* <sx:lastOccur>
* <gdate>2001-02-28</gdate>
* </sx:lastOccur>
@ -80,6 +81,7 @@ static short module = MOD_SX;
* <sx:end type="date">
* <gdate>2004-03-20</gdate>
* </sx:end>
* <sx:instanceCount>100</sx:instanceCount>
* <sx:freq>
* <!-- freqspec tree -->
* </sx:freq>
@ -88,6 +90,7 @@ static short module = MOD_SX;
* <sx:id type="guid">...</sx:id>
* <sx:name>Loan 2</sx:name>
* <sx:manual-conf>f</sx:manual-conf>
* <sx:instanceCount>100</sx:instanceCount>
* <sx:start>
* <gdate>2000-12-31</gdate>
* </sx:start>
@ -113,6 +116,7 @@ static short module = MOD_SX;
#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"
@ -139,6 +143,7 @@ gnc_schedXaction_dom_tree_create(SchedXaction *sx)
xmlNodePtr ret;
xmlNodePtr fsNode;
GDate *date;
gint instCount;
const GUID *templ_acc_guid;
templ_acc_guid = xaccAccountGetGUID(sx->template_acct);
@ -163,6 +168,10 @@ gnc_schedXaction_dom_tree_create(SchedXaction *sx)
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) ) );
@ -318,6 +327,22 @@ sx_set_date( xmlNodePtr node, SchedXaction *sx,
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 )
@ -436,6 +461,7 @@ struct dom_tree_handler sx_dom_handlers[] = {
{ 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 },

View File

@ -388,7 +388,7 @@ typedef struct parser_env
const char *parse_str;
char radix_point;
char group_char;
char name[50];
char name[128];
char Token;
char asn_op;
@ -417,6 +417,7 @@ parser_env;
#define ARG_TOKEN ':'
#define VAR_TOKEN 'V'
#define NUM_TOKEN 'I'
#define STR_TOKEN '"'
#define STACK_INIT 50
@ -671,6 +672,7 @@ get_named_var (parser_env_ptr pe)
else
bv->next_var = retp;
retp->variable_name = g_strdup (pe->name);
retp->type = VST_NUMERIC;
retp->value =
pe->trans_numeric ("0", pe->radix_point, pe->group_char, NULL);
}
@ -691,6 +693,7 @@ get_unnamed_var (parser_env_ptr pe)
retp = &(pe->unnamed_vars[cntr]);
retp->variable_name = NULL;
retp->use_flag = USED_VAR;
retp->type = VST_NUMERIC;
if (retp->value)
{
pe->free_numeric (retp->value);
@ -756,8 +759,8 @@ next_token (parser_env_ptr pe)
add_token (pe, *str_parse++);
if (*str_parse == ASN_OP)
{
/* BUG/FIXME: this allows '(=' and ')=' [?], neither of which make
* sense. */
/* BUG/FIXME: this seems to allow '(=' and ')=' [?], neither of which
* make sense. */
if (pe->Token != ASN_OP)
{
str_parse++;
@ -768,6 +771,18 @@ next_token (parser_env_ptr pe)
pe->error_code = UNDEFINED_CHARACTER;
} /* endif */
}
/* test for string */
else if ( *str_parse == '"' ) {
nstr = pe->name;
/* skip over the '"'. */
str_parse++;
do {
*nstr++ = *str_parse++;
} while ( *str_parse != '"' );
*nstr = EOS;
str_parse++;
add_token( pe, STR_TOKEN );
}
/* test for name */
else if (isalpha (*str_parse)
|| (*str_parse == '_'))
@ -818,15 +833,6 @@ next_token (parser_env_ptr pe)
pe->parse_str = str_parse;
} /* next_token */
/* evaluate function operators
* <name>( arg0, arg1, ... )
*/
static void
function_op( parser_env_ptr pe )
{
}
/* evaluate assignment operators,
* =
* +=
@ -834,6 +840,7 @@ function_op( parser_env_ptr pe )
* \=
* *=
*/
/* FIXME: add non-numeric checking. */
static void
assignment_op (parser_env_ptr pe)
{
@ -913,6 +920,7 @@ assignment_op (parser_env_ptr pe)
} /* assignment_op */
/* evaluate addition, subtraction operators */
/* FIXME: add non-numeric checking. */
static void
add_sub_op (parser_env_ptr pe)
{
@ -972,6 +980,7 @@ add_sub_op (parser_env_ptr pe)
} /* add_sub_op */
/* evaluate multiplication, division operators */
/* FIXME: add non-numeric checking. */
static void
multiply_divide_op (parser_env_ptr pe)
{
@ -1036,15 +1045,25 @@ multiply_divide_op (parser_env_ptr pe)
* numerics
* grouped expressions, "()"
* functions [ <name>( [exp, exp, ..., exp] ) ]
* strings
*/
static void
primary_exp (parser_env_ptr pe)
{
var_store_ptr rslt = NULL;
char *fnIdent;
char *ident = NULL;
int funcArgCount;
char LToken = pe->Token;
/* If we are in a state where the non-stacked 'pe->name' is valuable, then
* save it before we process the next token. */
switch ( LToken ) {
case FN_TOKEN:
case STR_TOKEN:
ident = g_strdup( pe->name );
break;
}
next_token (pe);
if (pe->error_code)
return;
@ -1099,7 +1118,6 @@ primary_exp (parser_env_ptr pe)
break;
case FN_TOKEN:
fnIdent = pe->name;
funcArgCount = 0;
do {
@ -1126,18 +1144,28 @@ primary_exp (parser_env_ptr pe)
argv = g_new0( void*, funcArgCount );
for ( i=0; i<funcArgCount; i++ ) {
/* fill back-to-front */
/* fill, in back-to-front order, the funcArgCount tokens we just
* parsed out of the expression into a argument list to hand back
* to the caller's func_op callback. */
val = pop(pe);
argv[funcArgCount - i - 1] = val->value;
argv[funcArgCount - i - 1] = val;
}
rslt = get_unnamed_var(pe);
rslt->value = (*pe->func_op)( fnIdent, funcArgCount, argv );
rslt->value = (*pe->func_op)( ident, funcArgCount, argv );
for ( i=0; i<funcArgCount; i++ ) {
free_var( argv[i], pe );
}
g_free( argv );
g_free( ident );
if ( rslt->value == NULL ) {
pe->error_code = NOT_A_FUNC;
add_token( pe, EOS );
return;
}
}
next_token(pe);
@ -1146,6 +1174,11 @@ primary_exp (parser_env_ptr pe)
case VAR_TOKEN:
rslt = get_named_var (pe);
break;
case STR_TOKEN:
rslt = get_unnamed_var( pe );
rslt->type = VST_STRING;
rslt->value = ident;
break;
} /* endswitch */
if (rslt != NULL)

View File

@ -69,11 +69,18 @@ ParseError;
*/
typedef struct var_store *var_store_ptr;
/* the type of entity contained in the var_store */
typedef enum {
VST_NUMERIC = 0,
VST_STRING
} VarStoreType;
typedef struct var_store
{
char *variable_name; /* variable name if variable, NULL otherwise */
char use_flag; /* flag if variable has been assigned to */
char assign_flag; /* flag if variable is used */
VarStoreType type;
void *value; /* pointer to implementation defined numeric value */
var_store_ptr next_var; /* pointer to next variable in linked list */
}

View File

@ -476,7 +476,6 @@ http://www.interest.com/hugh/calc/mort_links.html
Druid Feedback:
<Wilddev> jsled: <auspex> Wilddev: The labels need colons, mnemonics, and right-alignment.
<Wilddev> <auspex> Wilddev: It may be worthwhile for gnucash to create GtkSpinButton subclasses which show the percent symbol and others within the field.
<Wilddev> <auspex> Wilddev: I don't know how complicated that will be.
@ -495,3 +494,29 @@ Druid Feedback:
<jsled> Hmm. Okay. The between-transaction period is a frequency editor on the Repayment page.
<Wilddev> <auspex> I'm wondering if "Original Principal" should be a vulgate
such as "Loan Amount"
----------
Expression changes, round 2
We need the following abilities in order to get mortgage/loan repayment
working:
. Ability to get the original value of an account
. [perhaps, ability to reference an external value?]
. Ability to get the present value of an account
. Ability to get the current i in an "i-of-N" sequence
As well, it'd be nice to have:
. some sort of signature checking on functions in expressions
. safe[r] error handling?
We decide that the original/present value of the account should be handled in
scheme, and thus we actually need a way to reference accounts down to the
scheme expressions. We decide to use the Quote symbols to refer to a string
literal. The expression parser should be modified to parse this.
----------
The current 'i' and 'N' are going to be handled by having a list of
predefined variables which the user cannot have access to. For the time
being, this is 'i' and 'N'.

View File

@ -191,10 +191,14 @@ gnc_ttsplitinfo_malloc(void)
void
gnc_ttsplitinfo_free(TTSplitInfo *ttsi)
{
g_free(ttsi->action);
g_free(ttsi->memo);
g_free(ttsi->credit_formula);
g_free(ttsi->debit_formula);
if ( ttsi->action )
g_free(ttsi->action);
if ( ttsi->memo )
g_free(ttsi->memo);
if ( ttsi->credit_formula )
g_free(ttsi->credit_formula);
if ( ttsi->debit_formula )
g_free(ttsi->debit_formula);
g_free(ttsi);
return;
}

View File

@ -47,7 +47,6 @@ void gnc_ttinfo_set_num(TTInfo *tti, const char *num);
/* this one points to a persistent pointer so ownership isn't relevant */
void gnc_ttinfo_set_currency(TTInfo *tti, gnc_commodity *common_currency);

View File

@ -51,6 +51,7 @@ typedef struct _temporalStateData {
GDate end_date;
gint num_occur_total;
gint num_occur_rem;
gint num_inst;
} temporalStateData;
/** Local Prototypes *****/
@ -80,6 +81,7 @@ xaccSchedXactionInit( SchedXaction *sx, GNCBook *book)
sx->autoCreateNotify = FALSE;
sx->advanceCreateDays = 0;
sx->advanceRemindDays = 0;
sx->instance_num = 0;
sx->dirty = TRUE;
/* create a new template account for our splits */
@ -507,6 +509,29 @@ xaccSchedXactionGetInstanceAfter( SchedXaction *sx,
return next_occur;
}
gint
gnc_sx_get_instance_count( SchedXaction *sx, void *stateData )
{
gint toRet = -1;
temporalStateData *tsd;
if ( stateData ) {
tsd = (temporalStateData*)stateData;
toRet = tsd->num_inst;
} else {
toRet = sx->instance_num;
}
return toRet;
}
void
gnc_sx_set_instance_count( SchedXaction *sx, gint instanceNum )
{
g_return_if_fail( sx );
sx->instance_num = instanceNum;
}
GList *
xaccSchedXactionGetSplits( SchedXaction *sx )
{
@ -642,10 +667,11 @@ void
xaccSchedXactionIncrSequenceState( SchedXaction *sx,
void *stateData )
{
temporalStateData *tsd = (temporalStateData*)stateData;
if ( xaccSchedXactionHasOccurDef( sx ) ) {
temporalStateData *tsd = (temporalStateData*)stateData;
tsd->num_occur_rem -= 1;
}
tsd->num_inst += 1;
}
void
@ -663,6 +689,7 @@ gnc_sx_create_temporal_state_snapshot( SchedXaction *sx )
toRet->end_date = sx->end_date;
toRet->num_occur_total = sx->num_occurances_total;
toRet->num_occur_rem = sx->num_occurances_remain;
toRet->num_inst = sx->instance_num;
return (void*)toRet;
}
@ -675,6 +702,7 @@ gnc_sx_revert_to_temporal_state_snapshot( SchedXaction *sx, void *stateData )
sx->end_date = tsd->end_date;
sx->num_occurances_total = tsd->num_occur_total;
sx->num_occurances_remain = tsd->num_occur_rem;
sx->instance_num = tsd->num_inst;
sx->dirty = TRUE;
}

View File

@ -118,11 +118,27 @@ void xaccSchedXactionSetNumOccur( SchedXaction *sx, gint numNum );
gint xaccSchedXactionGetRemOccur( SchedXaction *sx );
void xaccSchedXactionSetRemOccur( SchedXaction *sx, gint numRemain );
/**
* Set the instance count. This is incremented by one for every created
* instance of the SX.
* @param stateData may be NULL.
**/
gint gnc_sx_get_instance_count( SchedXaction *sx, void *stateData );
/**
* Sets the instance count to something other than the default. As the
* default is the incorrect value '0', callers should DTRT here.
**/
void gnc_sx_set_instance_count( SchedXaction *sx, gint instanceNum );
GList *xaccSchedXactionGetSplits( SchedXaction *sx );
void xaccSchedXactionSetSplits( SchedXaction *sx, GList *newSplits );
void xaccSchedXactionGetAutoCreate( SchedXaction *sx, gboolean *outAutoCreate, gboolean *outNotify );
void xaccSchedXactionSetAutoCreate( SchedXaction *sx, gboolean newAutoCreate, gboolean newNotify );
void xaccSchedXactionGetAutoCreate( SchedXaction *sx,
gboolean *outAutoCreate,
gboolean *outNotify );
void xaccSchedXactionSetAutoCreate( SchedXaction *sx,
gboolean newAutoCreate,
gboolean newNotify );
gint xaccSchedXactionGetAdvanceCreation( SchedXaction *sx );
void xaccSchedXactionSetAdvanceCreation( SchedXaction *sx, gint createDays );
@ -177,6 +193,9 @@ void xaccSchedXactionSetGUID( SchedXaction *sx, GUID g );
* looking at reminders... and generally thinking about not wanting the
* caller to know every possible thing that needs to be kept track of in a
* forward-looking sequence of SXes.
*
* THESE (3) FUNCTIONS ARE DEPRECATED. See/Use the
* 'temporal_state_snapshot' functions below.
**/
void *xaccSchedXactionCreateSequenceState( SchedXaction *sx );
void xaccSchedXactionIncrSequenceState( SchedXaction *sx, void *stateData );
@ -194,7 +213,8 @@ void xaccSchedXactionDestroySequenceState( void *stateData );
* SX without having to rollback all the individual state changes.
*
* NOTE that this is similar to the above SequenceState interface, and
* perhaps can be seen as entailing the above interface.
* perhaps can be seen as entailing the above interface. In fact, the above
* interface is deprecated in favor of this one.
**/
void *gnc_sx_create_temporal_state_snapshot( SchedXaction *sx );
void gnc_sx_revert_to_temporal_state_snapshot( SchedXaction *sx, void *stateData );

View File

@ -64,6 +64,9 @@ struct gncp_SchedXaction
gint num_occurances_total;
/* reminaing occurances are as-of the 'last_date'. */
gint num_occurances_remain;
/* the current instance-count of the SX. */
gint instance_num;
gboolean autoCreateOption;
gboolean autoCreateNotify;

View File

@ -465,6 +465,7 @@ gnc_sxed_check_consistent( SchedXactionEditorDialog *sxed )
* Do checks on validity and such, interrupting the user if
* things aren't right.
*
* . support formulas [?!]
* . balancing the SX if contain numeric-only formula data.
* . agreement with create-automagically/notification controls
* X the 'will ever be valid' check should take num-occur vals into
@ -1429,6 +1430,10 @@ schedXact_editor_populate( SchedXactionEditorDialog *sxed )
(gfloat)daysInAdvance );
}
if ( sxed->newsxP ) {
gnc_sx_set_instance_count( sxed->sx, 1 );
}
/* populate the ledger */
{
/* create the split list */

View File

@ -387,6 +387,8 @@ sxftd_compute_sx(SXFromTransInfo *sxfti)
break;
}
gnc_sx_set_instance_count( sx, 1 );
sxftd_add_template_trans( sxfti );
return sxftd_errno;

View File

@ -140,10 +140,10 @@ typedef struct _sxSinceLastData {
GtkProgressBar *prog;
/* Multi-stage processing-related stuff... */
GList /* <autoCreateTuple*> */ *autoCreateList;
GList /* <toCreateTuple*> */ *toCreateList;
GList /* <reminderTuple*> */ *reminderList;
GList /* <toDeleteTuple*> */ *toRemoveList;
GList /* <toCreateTuple*> */ *autoCreateList;
GList /* <toCreateTuple*> */ *toCreateList;
GList /* <reminderTuple*> */ *reminderList;
GList /* <toDeleteTuple*> */ *toRemoveList;
/********** "Cancel"-related stuff... **********/
@ -165,12 +165,6 @@ typedef struct _sxSinceLastData {
} sxSinceLastData;
typedef struct autoCreateTuple_ {
SchedXaction *sx;
GList /* <GDate*> */ *instanceList;
} autoCreateTuple;
typedef struct toCreateTuple_ {
SchedXaction *sx;
GList /* <toCreateInstance*> */ *instanceList;
@ -179,6 +173,7 @@ typedef struct toCreateTuple_ {
typedef struct toCreateInstance_ {
GDate *date;
GHashTable *varBindings;
gint instanceNum;
GtkCTreeNode *node;
toCreateTuple *parentTCT;
} toCreateInstance;
@ -197,6 +192,7 @@ typedef struct reminderTuple_ {
typedef struct reminderInstanceTuple_ {
GDate *endDate;
GDate *occurDate;
gint instanceNum;
gboolean isSelected;
reminderTuple *parentRT;
} reminderInstanceTuple;
@ -453,7 +449,6 @@ reminders_page_prep( sxSinceLastData *sxsld )
if ( g_list_length( sxsld->reminderList ) == 0 ) {
w = glade_xml_get_widget( sxsld->gxml,
AUTO_CREATE_NOTIFY_PG );
DEBUG( "Going to auto_create_notify page" );
gnome_druid_set_page( sxsld->sincelast_druid,
GNOME_DRUID_PAGE(w) );
return;
@ -510,7 +505,6 @@ auto_create_prep( GnomeDruidPage *druid_page,
sxSinceLastData *sxsld = (sxSinceLastData*)ud;
if ( ! sxsld->autoCreatedSomething ) {
DEBUG( "Going to to_create page" );
w = glade_xml_get_widget( sxsld->gxml, TO_CREATE_PG );
gnome_druid_set_page( sxsld->sincelast_druid,
GNOME_DRUID_PAGE(w) );
@ -526,7 +520,6 @@ created_prep( GnomeDruidPage *druid_page,
sxSinceLastData *sxsld = (sxSinceLastData*)ud;
if ( !sxsld->createdSomething ) {
DEBUG( "Going to obsolete page" );
w = glade_xml_get_widget( sxsld->gxml, OBSOLETE_PG );
gnome_druid_set_page( sxsld->sincelast_druid,
GNOME_DRUID_PAGE(w) );
@ -541,7 +534,6 @@ obsolete_prep( GnomeDruidPage *druid_page,
GtkWidget *w;
sxSinceLastData *sxsld = (sxSinceLastData*)ud;
if ( g_list_length( sxsld->toRemoveList ) == 0 ) {
DEBUG( "Going to finish page" );
w = glade_xml_get_widget( sxsld->gxml, FINISH_PG );
gnome_druid_set_page( sxsld->sincelast_druid,
GNOME_DRUID_PAGE(w) );
@ -560,7 +552,6 @@ obsolete_next( GnomeDruidPage *druid_page,
toDeleteTuple *tdt;
sxSinceLastData *sxsld = (sxSinceLastData*)ud;
DEBUG( "obsolete_next" );
sxList = gnc_book_get_schedxactions( gnc_get_current_book() );
cl = GTK_CLIST( glade_xml_get_widget( sxsld->gxml,
SX_OBSOLETE_CLIST ) );
@ -569,11 +560,7 @@ obsolete_next( GnomeDruidPage *druid_page,
toDelPtr;
toDelPtr = toDelPtr->next ) {
row = (gint)toDelPtr->data;
DEBUG( "getting row data for SX_OBSOLETE_CLIST row %d",
row );
tdt = (toDeleteTuple*)gtk_clist_get_row_data( cl, row );
DEBUG( "got tdt with sx with name \"%s\"",
xaccSchedXactionGetName( tdt->sx ) );
{
elt = g_list_find( sxList, tdt->sx );
sxList = g_list_remove_link( sxList, elt );
@ -699,8 +686,6 @@ to_create_next( GnomeDruidPage *druid_page,
}
}
DEBUG( "Done with creation; updating created ledger." );
oldQuery = gnc_ledger_display_get_query( sxsld->created_ledger );
newQuery = xaccQueryMerge( oldQuery, q, QUERY_AND );
gnc_ledger_display_set_query( sxsld->created_ledger, newQuery );
@ -925,7 +910,7 @@ sxsincelast_init( sxSinceLastData *sxsld )
}
}
//reminders_page_prep( sxsld );
/*reminders_page_prep( sxsld );*/
gtk_widget_show_all( sxsld->sincelast_window );
process_auto_create_list( sxsld->autoCreateList, sxsld );
@ -952,7 +937,8 @@ generate_instances( SchedXaction *sx,
GList **reminderList,
GList **deadList )
{
GDate gd, *gdToReturn;
GDate gd;
toCreateInstance *tci;
reminderTuple *rt;
reminderInstanceTuple *rit;
void *seqStateData;
@ -966,9 +952,13 @@ generate_instances( SchedXaction *sx,
g_date_strftime( tmpBuf, GNC_D_WIDTH, GNC_D_FMT, &gd );
gdToReturn = g_date_new();
*gdToReturn = gd;
*instanceList = g_list_append( *instanceList, gdToReturn );
tci = g_new0( toCreateInstance, 1 );
tci->date = g_date_new();
*tci->date = gd;
tci->instanceNum = gnc_sx_get_instance_count( sx, seqStateData );
*instanceList = g_list_append( *instanceList, tci );
xaccSchedXactionIncrSequenceState( sx, seqStateData );
gd = xaccSchedXactionGetInstanceAfter( sx, &gd, seqStateData );
@ -990,14 +980,17 @@ generate_instances( SchedXaction *sx,
rt->instanceList = NULL;
while ( g_date_valid(&gd)
&& g_date_compare( &gd, reminderEnd ) <= 0 ) {
g_date_strftime( tmpBuf, GNC_D_WIDTH, GNC_D_FMT, &gd );
rit = g_new0( reminderInstanceTuple, 1 );
rit->endDate = g_date_new();
*rit->endDate = *end;
rit->occurDate = g_date_new();
*rit->occurDate = gd;
rit->isSelected = FALSE;
rit->parentRT = rt;
rit->endDate = g_date_new();
*rit->endDate = *end;
rit->occurDate = g_date_new();
*rit->occurDate = gd;
rit->isSelected = FALSE;
rit->parentRT = rt;
rit->instanceNum = gnc_sx_get_instance_count( sx, seqStateData );
rt->instanceList = g_list_append( rt->instanceList, rit );
@ -1072,7 +1065,8 @@ process_auto_create_list( GList *autoCreateList, sxSinceLastData *sxsld )
{
GList *createdGUIDs = NULL;
GList *thisGUID;
autoCreateTuple *act;
toCreateTuple *tct;
toCreateInstance *tci;
gboolean autoCreateState, notifyState;
Query *q, *dlQuery, *newQuery;
GList *instances;
@ -1084,18 +1078,19 @@ process_auto_create_list( GList *autoCreateList, sxSinceLastData *sxsld )
gtk_progress_configure( GTK_PROGRESS(sxsld->prog), 0, 0,
g_list_length( autoCreateList ) );
for ( ; autoCreateList ; autoCreateList = autoCreateList->next ) {
act = (autoCreateTuple*)autoCreateList->data;
tct = (toCreateTuple*)autoCreateList->data;
xaccSchedXactionGetAutoCreate( act->sx,
xaccSchedXactionGetAutoCreate( tct->sx,
&autoCreateState,
&notifyState );
for ( instances = act->instanceList;
for ( instances = tct->instanceList;
instances;
instances = instances->next ) {
tci = (toCreateInstance*)instances->data;
thisGUID = createdGUIDs = NULL;
create_transactions_on( act->sx,
(GDate*)instances->data,
create_transactions_on( tct->sx,
(GDate*)tci->date,
NULL, &createdGUIDs );
count += g_list_length( createdGUIDs );
@ -1121,7 +1116,7 @@ process_auto_create_list( GList *autoCreateList, sxSinceLastData *sxsld )
}
}
DEBUG( "Finished creating transactions; updating ledger" );
/*DEBUG( "Finished creating transactions; updating ledger" );*/
dlQuery = gnc_ledger_display_get_query( sxsld->ac_ledger );
newQuery = xaccQueryMerge( dlQuery, q, QUERY_AND );
@ -1141,6 +1136,8 @@ add_to_create_list_to_gui( GList *toCreateList, sxSinceLastData *sxsld )
GtkCTreeNode *sxNode;
char *rowText[ TO_CREATE_LIST_WIDTH ];
GList *insts;
int htSize;
gpointer unusedkey, unusedvalue;
ct = GTK_CTREE( glade_xml_get_widget( sxsld->gxml, TO_CREATE_LIST ) );
@ -1170,7 +1167,13 @@ add_to_create_list_to_gui( GList *toCreateList, sxSinceLastData *sxsld )
g_date_strftime( rowText[0], GNC_D_WIDTH, GNC_D_FMT, tci->date );
sxsl_get_sx_vars( tci->parentTCT->sx, tci->varBindings );
if ( g_hash_table_size( tci->varBindings ) == 0 ) {
htSize = g_hash_table_size( tci->varBindings );
if ( g_hash_table_lookup_extended( tci->varBindings, "i",
&unusedkey,
&unusedvalue ) ) {
htSize -= 1;
}
if ( htSize == 0 ) {
rowText[1] = "y";
} else {
rowText[1] = "n";
@ -1299,41 +1302,45 @@ processSelectedReminderList( GList *goodList, sxSinceLastData *sxsld )
{
GList *list = NULL;
reminderInstanceTuple *rit;
autoCreateTuple *act;
toCreateTuple *tct;
toCreateInstance *tci;
gboolean autoCreateOpt, notifyOpt;
tct = NULL;
act = NULL;
for ( ; goodList ; goodList = goodList->next ) {
rit = (reminderInstanceTuple*)goodList->data;
DEBUG( "Processing selected reminder \"%s\"",
xaccSchedXactionGetName( rit->parentRT->sx ) );
xaccSchedXactionGetAutoCreate( rit->parentRT->sx,
&autoCreateOpt, &notifyOpt );
if ( autoCreateOpt ) {
for ( list = sxsld->autoCreateList;
list;
list = list->next ) {
act = (autoCreateTuple*)list->data;
// Find any already-existing toCreateTuples to add to...
if ( act->sx == rit->parentRT->sx ) {
tct = (toCreateTuple*)list->data;
/* Find any already-existing toCreateTuples to add to...*/
if ( tct->sx == rit->parentRT->sx ) {
break;
}
}
if ( !list ) {
act = g_new0( autoCreateTuple, 1 );
act->sx = rit->parentRT->sx;
tct = g_new0( toCreateTuple, 1 );
tct->sx = rit->parentRT->sx;
sxsld->autoCreateList =
g_list_append( sxsld->autoCreateList, act );
g_list_append( sxsld->autoCreateList, tct );
}
act->instanceList = g_list_append( act->instanceList,
rit->occurDate );
tci = g_new0( toCreateInstance, 1 );
tci->parentTCT = tct;
tci->date = rit->occurDate;
tci->varBindings = NULL;
tci->instanceNum = rit->instanceNum;
tci->node = NULL;
tct->instanceList =
g_list_append( tct->instanceList, tci );
list = NULL;
list = g_list_append( list, act );
list = g_list_append( list, tct );
process_auto_create_list( list, sxsld );
list = NULL;
} else {
@ -1341,7 +1348,7 @@ processSelectedReminderList( GList *goodList, sxSinceLastData *sxsld )
list;
list = list->next ) {
tct = (toCreateTuple*)list->data;
// Find any already-existing toCreateTuples to add to...
/* Find any already-existing toCreateTuples to add to...*/
if ( tct->sx == rit->parentRT->sx ) {
break;
}
@ -1353,10 +1360,11 @@ processSelectedReminderList( GList *goodList, sxSinceLastData *sxsld )
g_list_append( sxsld->toCreateList, tct );
}
tci = g_new0( toCreateInstance, 1 );
tci->parentTCT = tct;
tci->date = rit->occurDate;
tci->node = NULL;
tci->parentTCT = tct;
tci->date = rit->occurDate;
tci->node = NULL;
tci->varBindings = NULL;
tci->instanceNum = rit->instanceNum;
tct->instanceList =
g_list_append( tct->instanceList, tci );
@ -1377,11 +1385,9 @@ sxsincelast_populate( sxSinceLastData *sxsld )
SchedXaction *sx;
void *sx_state;
GDate end, endPlusReminders;
GDate *instDate;
gint daysInAdvance;
gboolean autocreateState, notifyState;
gboolean showIt;
autoCreateTuple *act;
toCreateTuple *tct;
toCreateInstance *tci;
@ -1432,27 +1438,24 @@ sxsincelast_populate( sxSinceLastData *sxsld )
xaccSchedXactionGetAutoCreate( sx, &autocreateState,
&notifyState );
if ( autocreateState ) {
act = g_new0( autoCreateTuple, 1 );
act->sx = sx;
tct = g_new0( toCreateTuple, 1 );
tct->sx = sx;
for ( ; instanceList; instanceList = instanceList->next ) {
instDate = (GDate*)instanceList->data;
act->instanceList =
g_list_append( act->instanceList,
instDate );
tci = (toCreateInstance*)instanceList->data;
tci->parentTCT = tct;
tct->instanceList =
g_list_append( tct->instanceList,
tci );
}
sxsld->autoCreateList =
g_list_append( sxsld->autoCreateList,
act );
tct );
} else {
tct = g_new0( toCreateTuple, 1 );
tct->sx = sx;
for ( ; instanceList; instanceList = instanceList->next ) {
instDate = (GDate*)instanceList->data;
tci = g_new0( toCreateInstance, 1 );
tci = (toCreateInstance*)instanceList->data;
tci->parentTCT = tct;
tci->date = instDate;
tci->node = NULL;
tci->varBindings = NULL;
tct->instanceList =
g_list_append( tct->instanceList, tci );
}
@ -1508,8 +1511,7 @@ static void
sxsincelast_close_handler( gpointer ud )
{
sxSinceLastData *sxsld = (sxSinceLastData*)ud;
DEBUG( "sxsincelast_close_handler" );
gtk_widget_hide( sxsld->sincelast_window );
sxsincelast_save_size( sxsld );
clean_sincelast_dlg( sxsld );
@ -1521,7 +1523,9 @@ static void
andequal_numerics_set( gpointer key, gpointer value, gpointer data )
{
gboolean *allVarsBound = data;
*allVarsBound &= (value != NULL);
if ( strcmp( (gchar*)key, "i" ) != 0 ) {
*allVarsBound &= (value != NULL);
}
}
static void
@ -1598,7 +1602,6 @@ sxsincelast_destroy( GtkObject *o, gpointer ud )
{
sxSinceLastData *sxsld = (sxSinceLastData*)ud;
DEBUG( "sxsincelast_destroy called\n" );
gnc_unregister_gui_component_by_data( DIALOG_SXSINCELAST_CM_CLASS,
sxsld->sincelast_window );
@ -1614,6 +1617,40 @@ sxsincelast_destroy( GtkObject *o, gpointer ud )
g_free( sxsld );
}
/**
* Used to copy the varBinding GHashTable.
**/
static
void
gnc_sxsl_copy_ea_hash( gpointer key,
gpointer value,
gpointer user_data )
{
gchar *name = (gchar*)key;
gnc_numeric *val = (gnc_numeric*)value;
gnc_numeric *newVal;
GHashTable *table = (GHashTable*)user_data;
newVal = g_new0( gnc_numeric, 1 );
*newVal = gnc_numeric_error( -2 );
if ( val )
*newVal = *val;
g_hash_table_insert( table,
(gpointer)g_strdup( name ),
(gpointer)newVal );
}
static
void
gnc_sxsl_del_vars_table_ea( gpointer key,
gpointer value,
gpointer user_data )
{
g_free( (gchar*)key );
g_free( (gnc_numeric*)value );
}
static gboolean
create_each_transaction_helper( Transaction *t, void *d )
{
@ -1627,6 +1664,8 @@ create_each_transaction_helper( Transaction *t, void *d )
createData *createUD;
toCreateInstance *tci;
gnc_commodity *commonCommodity = NULL;
GHashTable *actualVars;
gnc_numeric *varIValue;
errFlag = FALSE;
@ -1637,15 +1676,25 @@ 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 );
g_hash_table_insert( actualVars, "i", varIValue );
newT = xaccMallocTransaction(gnc_get_current_book ());
xaccTransBeginEdit( newT );
/* the action and description/memo are in the template */
gnc_copy_trans_onto_trans( t, newT, FALSE, FALSE );
/* the date is new [by definition :)] */
xaccTransSetDate( newT,
g_date_day( tci->date ),
g_date_month( tci->date ),
@ -1658,7 +1707,8 @@ create_each_transaction_helper( Transaction *t, void *d )
PERR( "\tseen transaction w/o splits. :(" );
return FALSE;
}
do {
for ( ; sList && osList ;
sList = sList->next, osList = osList->next ) {
split = (Split*)sList->data;
/* FIXME: Ick. This assumes that the split lists will be
ordered identically. :( I think it's fair to say they
@ -1683,10 +1733,10 @@ create_each_transaction_helper( Transaction *t, void *d )
acct_guid = kvp_value_get_guid( kvp_val );
acct = xaccAccountLookup( acct_guid,
gnc_get_current_book ());
#if 0
#if 0 /* debug */
DEBUG( "Got account with name \"%s\"",
xaccAccountGetName( acct ) );
#endif /* 0 */
#endif /* 0 -- debug */
if ( commonCommodity != NULL ) {
if ( commonCommodity != xaccAccountGetCommodity( acct ) ) {
PERR( "Common-commodity difference: old=%s, new=%s\n",
@ -1701,7 +1751,7 @@ create_each_transaction_helper( Transaction *t, void *d )
}
/*commonCommodity = xaccTransGetCurrency( t );*/
/* commonCommodity = xaccTransGetCurrency( t ); */
/* credit/debit formulas */
{
char *str, *parseErrorLoc;
@ -1717,17 +1767,18 @@ create_each_transaction_helper( Transaction *t, void *d )
if ( str != NULL
&& strlen(str) != 0 ) {
if ( ! gnc_exp_parser_parse_separate_vars( str, &credit_num,
&parseErrorLoc, tci->varBindings ) ) {
&parseErrorLoc,
actualVars ) ) {
PERR( "Error parsing credit formula \"%s\" at \"%s\": %s",
str, parseErrorLoc, gnc_exp_parser_error_string() );
errFlag = TRUE;
break;
}
#if 0
#if 0 /* debug */
DEBUG( "gnc_numeric::credit: \"%s\" -> %s [%s]",
str, gnc_numeric_to_string( credit_num ),
gnc_numeric_to_string( gnc_numeric_reduce( credit_num ) ) );
#endif /* 0 */
#endif /* 0 -- debug */
}
kvp_val = kvp_frame_get_slot_path( split_kvpf,
@ -1740,18 +1791,19 @@ create_each_transaction_helper( Transaction *t, void *d )
if ( str != NULL
&& strlen(str) != 0 ) {
if ( ! gnc_exp_parser_parse_separate_vars( str, &debit_num,
&parseErrorLoc, tci->varBindings ) ) {
&parseErrorLoc,
actualVars ) ) {
PERR( "Error parsing debit_formula \"%s\" at \"%s\": %s",
str, parseErrorLoc, gnc_exp_parser_error_string() );
errFlag = TRUE;
break;
}
#if 0
#if 0 /* debug */
DEBUG( "gnc_numeric::debit: \"%s\" -> %s [%s]",
str, gnc_numeric_to_string( debit_num ),
gnc_numeric_to_string( gnc_numeric_reduce( debit_num ) ) );
#endif /* 0 */
#endif /* 0 -- debug */
}
final = gnc_numeric_sub_fixed( debit_num, credit_num );
@ -1762,12 +1814,15 @@ create_each_transaction_helper( Transaction *t, void *d )
errFlag = TRUE;
break;
}
#if 0
#if 0 /* debug */
DEBUG( "gnc_numeric::final: \"%s\"",
gnc_numeric_to_string( final ) );
#endif /* 0 */
xaccSplitSetBaseValue( split, final, commonCommodity );
#endif /* 0 -- debug */
xaccSplitSetValue( split, final );
}
#if 0
/* NOT [YET] USED */
kvp_val = kvp_frame_get_slot_path( split_kvpf,
@ -1780,12 +1835,17 @@ create_each_transaction_helper( Transaction *t, void *d )
GNC_SX_AMNT,
NULL);
#endif /* 0 */
/* FIXME:
* . We'd like to store the variable bindings, but this might be
* problematic [if the formulas change in the SX] [?]
*/
} while ( (sList = sList->next) && (osList = osList->next) );
}
/* Cleanup actualVars table. */
{
g_hash_table_foreach( actualVars,
gnc_sxsl_del_vars_table_ea,
NULL );
g_hash_table_destroy( actualVars );
actualVars = NULL;
}
/* set the balancing currency. */
if ( commonCommodity == NULL ) {
@ -1797,7 +1857,7 @@ create_each_transaction_helper( Transaction *t, void *d )
{
kvp_frame *txn_frame;
/* set a kvp-frame element in the transaction indicating and
pointing-to the SX this was created from. */
* pointing-to the SX this was created from. */
txn_frame = xaccTransGetSlots( newT );
if ( txn_frame == NULL ) {
txn_frame = kvp_frame_new();
@ -1875,7 +1935,6 @@ create_transactions_on( SchedXaction *sx,
createdTCT = TRUE;
}
gnc_suspend_gui_refresh();
ag = gnc_book_get_template_group( gnc_get_current_book () );
id = guid_to_string( xaccSchedXactionGetGUID(sx) );
if(ag && id)
@ -1895,9 +1954,19 @@ create_transactions_on( SchedXaction *sx,
{
g_free( id );
}
gnc_resume_gui_refresh();
xaccSchedXactionSetLastOccurDate( sx, tci->date );
/* Increment the SX state */
{
gint tmp;
xaccSchedXactionSetLastOccurDate( sx, tci->date );
tmp = gnc_sx_get_instance_count( sx, NULL );
gnc_sx_set_instance_count( sx, tmp+1 );
if ( xaccSchedXactionHasOccurDef( sx ) ) {
tmp = xaccSchedXactionGetRemOccur(sx);
xaccSchedXactionSetRemOccur( sx, tmp-1 );
}
}
if ( createdTCT ) {
g_free( tci );
@ -1992,7 +2061,6 @@ static gboolean
tct_table_entry_key_handle( GtkWidget *widget, GdkEventKey *event, gpointer ud )
{
gnc_numeric *num;
//gchar *entryText;
GtkEntry *ent = NULL;
GString *str;
@ -2059,8 +2127,19 @@ sxsincelast_tc_row_sel( GtkCTree *ct,
return;
}
if ( (varHashSize = g_hash_table_size( tci->varBindings )) == 0 ) {
PINFO( "No variables to deal with" );
/* Get the count of variables; potentially remove the system-defined
* variables if they're present in the expression. */
varHashSize = g_hash_table_size( tci->varBindings );
{
gpointer *foo, *bar;
if ( g_hash_table_lookup_extended( tci->varBindings, "i",
(gpointer)&foo,
(gpointer)&bar ) ) {
varHashSize -= 1;
}
}
if ( varHashSize == 0 ) {
return;
}
@ -2072,19 +2151,25 @@ sxsincelast_tc_row_sel( GtkCTree *ct,
tableIdx = 1;
for ( ; varList ; varList = varList->next ) {
gchar *varName;
GString *gstr;
const gchar *numValueStr;
gnc_numeric *numValue, *tmpNumValue;
varName = (gchar*)varList->data;
if ( strcmp( varName, "i" ) == 0 ) {
continue;
}
gstr = g_string_sized_new(16);
g_string_sprintf( gstr, "%s: ", (gchar*)varList->data );
g_string_sprintf( gstr, "%s: ", varName );
label = gtk_label_new( gstr->str );
gtk_label_set_justify( GTK_LABEL(label), GTK_JUSTIFY_RIGHT );
g_string_free( gstr, TRUE );
entry = gtk_entry_new();
gtk_object_set_data( GTK_OBJECT(entry), "varName",
varList->data );
varName );
gtk_object_set_data( GTK_OBJECT(entry), "tci", tci );
tmpNumValue = g_new0( gnc_numeric, 1 );
*tmpNumValue = gnc_numeric_create( 0, 1 );
@ -2099,7 +2184,7 @@ sxsincelast_tc_row_sel( GtkCTree *ct,
gtk_widget_set_usize( entry, 64, 0 );
numValue = (gnc_numeric*)g_hash_table_lookup( tci->varBindings,
varList->data );
varName );
if ( numValue != NULL ) {
numValueStr =
xaccPrintAmount( *numValue,
@ -2144,14 +2229,14 @@ clean_variable_table( sxSinceLastData *sxsld )
return;
}
do {
for( ; children ; children = children->next ) {
/* Destroy all children after the first [label-continaing]
row... ie, leave the labels in place. */
child = (GtkTableChild*)children->data;
if ( child->top_attach > 0 ) {
toFree = g_list_append( toFree, child->widget );
}
} while ( (children = children->next) );
}
gtk_table_resize( table, 1, 2 );
@ -2503,7 +2588,6 @@ sxsld_ledger_get_parent( GNCLedgerDisplay *ld )
sxSinceLastData *sxsld;
sxsld = (sxSinceLastData*)gnc_ledger_display_get_user_data( ld );
//return (gncUIWidget)sxsld->reg->sheet->window;
return (gncUIWidget)sxsld->sincelast_window;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -916,14 +916,14 @@ gnc_main_window_create_menus(GNCMDIInfo * maininfo)
static GnomeUIInfo gnc_sched_xaction_tools_submenu_template[] =
{
{ GNOME_APP_UI_ITEM,
N_("List and Editor"),
N_("_List and Editor"),
N_("The list of Scheduled Transactions"),
gnc_main_window_sched_xaction_cb, NULL, NULL,
GNOME_APP_PIXMAP_NONE, NULL,
0, 0, NULL
},
{ GNOME_APP_UI_ITEM,
N_("Since Last Run..."),
N_("_Since Last Run..."),
N_("Create Scheduled Transactions since the last time run."),
gnc_main_window_sched_xaction_slr_cb, NULL, NULL,
GNOME_APP_PIXMAP_NONE, NULL,
@ -931,7 +931,7 @@ gnc_main_window_create_menus(GNCMDIInfo * maininfo)
},
GNOMEUIINFO_SEPARATOR,
{ GNOME_APP_UI_ITEM,
N_( "Mortgage/Loan Repayment Setup" ),
N_( "_Mortgage/Loan Repayment Setup" ),
N_( "Setup scheduled transactions for repayment of a loan" ),
gnc_main_window_sx_loan_druid_cb, NULL, NULL,
GNOME_APP_PIXMAP_NONE, NULL,
@ -942,7 +942,7 @@ gnc_main_window_create_menus(GNCMDIInfo * maininfo)
static GnomeUIInfo gnc_actions_menu_template[] =
{
GNOMEUIINFO_SUBTREE( N_("Scheduled Transactions"),
GNOMEUIINFO_SUBTREE( N_("_Scheduled Transactions"),
gnc_sched_xaction_tools_submenu_template ),
GNOMEUIINFO_END
};

View File

@ -16,26 +16,37 @@
;; Boston, MA 02111-1307, USA gnu@gnu.org
;; Copyright 2002 Joshua Sled <jsled@asynchronous.org>
;; pretty literal copies of similar code from gnumeric-1.0.8
;;
;; pretty literal copies of similar code from gnumeric-1.0.8, except we want
;; positive values to be returned [as gnucash will handle the credit/debit
;; appropriately]
(define (gnc:ipmt rate nper per pv fv type)
(* rate
(- 0 (calc-principal pv
(calc-pmt rate nper pv fv type)
rate (- per 1))
)
)
(define (gnc:ipmt rate per nper pv fv type)
(* -1 (* rate
(- 0 (calc-principal pv
(calc-pmt rate nper pv fv type)
rate (- per 1)))
))
)
(define (gnc:ppmt rate nper per pv fv type)
(let ((pmt (calc-pmt rate nper pv fv type)))
(let ((ipmt (* rate
(- 0 (calc-principal pv pmt rate (- per 1))))))
(- pmt ipmt)))
(define (gnc:ppmt rate per nper pv fv type)
(let* ((pmt (calc-pmt rate nper pv fv type))
(ipmt (* rate
(calc-principal pv pmt rate (- per 1)))))
(* -1 (-
pmt
(* -1 ipmt))))
)
(define (gnc:pmt rate nper pv fv type)
(calc-pmt rate nper pv fv type))
(* -1 (calc-pmt rate nper pv fv type)))
(define (gnc:foobar val) val)
;;;;;
;; below: not-exposed/"private" functions, used by the "public" functions
;; above.
;;;;;
(define (calc-pmt rate nper pv fv type)
(let ((pvif (calc-pvif rate nper))