|
GnuCash 2.4.99
|
#include "config.h"#include <glib.h>#include <glib-object.h>#include "gnc-numeric.h"#include "SchedXaction.h"Go to the source code of this file.
Data Structures | |
| struct | _GncSxInstanceModel |
| struct | _GncSxInstanceModelClass |
| struct | _GncSxInstances |
| struct | _GncSxVariable |
| struct | _GncSxInstance |
| struct | _GncSxVariableNeeded |
| struct | _GncSxSummary |
Defines | |
| #define | GNC_TYPE_SX_INSTANCE_MODEL (gnc_sx_instance_model_get_type ()) |
| #define | GNC_SX_INSTANCE_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNC_TYPE_SX_INSTANCE_MODEL, GncSxInstanceModel)) |
| #define | GNC_SX_INSTANCE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GNC_TYPE_SX_INSTANCE_MODEL, GncSxInstanceModelClass)) |
| #define | GNC_IS_SX_INSTANCE_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNC_TYPE_SX_INSTANCE_MODEL)) |
| #define | GNC_IS_SX_INSTANCE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNC_TYPE_SX_INSTANCE_MODEL)) |
| #define | GNC_SX_INSTANCE_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNC_TYPE_SX_INSTANCE_MODEL, GncSxInstanceModelClass)) |
Typedefs | |
| typedef struct _GncSxInstanceModel | GncSxInstanceModel |
|
typedef struct _GncSxInstanceModelClass | GncSxInstanceModelClass |
| typedef struct _GncSxInstances | GncSxInstances |
| typedef struct _GncSxVariable | GncSxVariable |
| typedef struct _GncSxInstance | GncSxInstance |
| typedef struct _GncSxVariableNeeded | GncSxVariableNeeded |
| typedef struct _GncSxSummary | GncSxSummary |
Enumerations | |
| enum | GncSxInstanceState { SX_INSTANCE_STATE_IGNORED, SX_INSTANCE_STATE_POSTPONED, SX_INSTANCE_STATE_TO_CREATE, SX_INSTANCE_STATE_REMINDER, SX_INSTANCE_STATE_CREATED, SX_INSTANCE_STATE_MAX_STATE } |
Functions | |
| GType | gnc_sx_instance_model_get_type (void) |
| GncSxInstanceModel * | gnc_sx_get_current_instances (void) |
| GncSxInstanceModel * | gnc_sx_get_instances (const GDate *range_end, gboolean include_disabled) |
| void | gnc_sx_instance_model_update_sx_instances (GncSxInstanceModel *model, SchedXaction *sx) |
| void | gnc_sx_instance_model_remove_sx_instances (GncSxInstanceModel *model, SchedXaction *sx) |
| GList * | gnc_sx_instance_get_variables (GncSxInstance *inst) |
| Account * | gnc_sx_get_template_transaction_account (const SchedXaction *sx) |
| GHashTable * | gnc_sx_instance_get_variables_for_parser (GHashTable *instance_var_hash) |
| GncSxVariable * | gnc_sx_variable_new_full (gchar *name, gnc_numeric value, gboolean editable) |
| void | gnc_sx_variable_free (GncSxVariable *var) |
| void | gnc_sx_instance_model_change_instance_state (GncSxInstanceModel *model, GncSxInstance *instance, GncSxInstanceState new_state) |
| void | gnc_sx_instance_model_set_variable (GncSxInstanceModel *model, GncSxInstance *instance, GncSxVariable *variable, gnc_numeric *new_value) |
| GList * | gnc_sx_instance_model_check_variables (GncSxInstanceModel *model) |
| void | gnc_sx_instance_model_effect_change (GncSxInstanceModel *model, gboolean auto_create_only, GList **created_transaction_guids, GList **creation_errors) |
| void | gnc_sx_instance_model_summarize (GncSxInstanceModel *model, GncSxSummary *summary) |
| void | gnc_sx_summary_print (const GncSxSummary *summary) |
| void | gnc_sx_get_variables (SchedXaction *sx, GHashTable *var_hash) |
| int | gnc_sx_parse_vars_from_formula (const char *formula, GHashTable *var_hash, gnc_numeric *result) |
| void | gnc_sx_randomize_variables (GHashTable *vars) |
| GHashTable * | gnc_g_hash_new_guid_numeric (void) |
| void | gnc_sx_all_instantiate_cashflow (GList *all_sxes, const GDate *range_start, const GDate *range_end, GHashTable *map, GList **creation_errors) |
| GHashTable * | gnc_sx_all_instantiate_cashflow_all (GDate range_start, GDate range_end) |
Definition in file gnc-sx-instance-model.h.
| GHashTable* gnc_g_hash_new_guid_numeric | ( | void | ) |
Returns a GHashTable<GUID*, gnc_numeric*> with no destructor for the key, but a destructor for the value set.
The returned value must be free'd with g_hash_table_destroy or g_hash_table_unref.
Definition at line 1479 of file gnc-sx-instance-model.c.
{
return g_hash_table_new_full (guid_hash_to_guint, guid_g_hash_table_equal,
NULL, gnc_numeric_free);
}
| void gnc_sx_all_instantiate_cashflow | ( | GList * | all_sxes, |
| const GDate * | range_start, | ||
| const GDate * | range_end, | ||
| GHashTable * | map, | ||
| GList ** | creation_errors | ||
| ) |
Instantiates the cash flow of all given SXs (in the given GList<SchedXAction*>) into the GHashTable<GUID*, gnc_numeric*> for the given date range. Each SX is counted with multiplicity as it has occurrences in the given date range.
The creation_errors list, if non-NULL, receive any errors that occurred during creation, similar as in gnc_sx_instance_model_effect_change().
Definition at line 1720 of file gnc-sx-instance-model.c.
{
SxAllCashflow userdata;
userdata.hash = map;
userdata.creation_errors = creation_errors;
userdata.range_start = range_start;
userdata.range_end = range_end;
/* The work is done in the callback for each SX */
g_list_foreach(all_sxes, instantiate_cashflow_cb, &userdata);
}
| GHashTable* gnc_sx_all_instantiate_cashflow_all | ( | GDate | range_start, |
| GDate | range_end | ||
| ) |
Simplified wrapper around gnc_sx_all_instantiate_cashflow(): Run that function on all SX of the current book for the given date range. Ignore any potential error messages. Returns a newly allocated GHashTable with the result, which is a GHashTable<GUID*, gnc_numeric*>, identical to what gnc_g_hash_new_guid_numeric() would return. The returned value must be free'd with g_hash_table_destroy.
Definition at line 1735 of file gnc-sx-instance-model.c.
{
GHashTable *result_map = gnc_g_hash_new_guid_numeric();
GList *all_sxes = gnc_book_get_schedxactions(gnc_get_current_book())->sx_list;
gnc_sx_all_instantiate_cashflow(all_sxes,
&range_start, &range_end,
result_map, NULL);
return result_map;
}
| GncSxInstanceModel* gnc_sx_get_current_instances | ( | void | ) |
Shorthand for get_instances(now, FALSE);
Definition at line 425 of file gnc-sx-instance-model.c.
{
GDate now;
g_date_clear(&now, 1);
g_date_set_time_t(&now, time(NULL));
return gnc_sx_get_instances(&now, FALSE);
}
| GncSxInstanceModel* gnc_sx_get_instances | ( | const GDate * | range_end, |
| gboolean | include_disabled | ||
| ) |
Allocates a new SxInstanceModel and fills it with generated instances for all scheduled transactions up to the given range_end date.
The caller must unref the returned object by g_object_unref(G_OBJECT(inst_model)); when no longer in use.
Definition at line 434 of file gnc-sx-instance-model.c.
{
GList *all_sxes = gnc_book_get_schedxactions(gnc_get_current_book())->sx_list;
GncSxInstanceModel *instances;
g_assert(range_end != NULL);
g_assert(g_date_valid(range_end));
instances = gnc_sx_instance_model_new();
instances->include_disabled = include_disabled;
instances->range_end = *range_end;
if (include_disabled)
{
instances->sx_instance_list = gnc_g_list_map(all_sxes, (GncGMapFunc)_gnc_sx_gen_instances, (gpointer)range_end);
}
else
{
GList *sx_iter = g_list_first(all_sxes);
GList *enabled_sxes = NULL;
for (; sx_iter != NULL; sx_iter = sx_iter->next)
{
SchedXaction *sx = (SchedXaction*)sx_iter->data;
if (xaccSchedXactionGetEnabled(sx))
{
enabled_sxes = g_list_append(enabled_sxes, sx);
}
}
instances->sx_instance_list = gnc_g_list_map(enabled_sxes, (GncGMapFunc)_gnc_sx_gen_instances, (gpointer)range_end);
g_list_free(enabled_sxes);
}
return instances;
}
| GList* gnc_sx_instance_get_variables | ( | GncSxInstance * | inst | ) |
Definition at line 352 of file gnc-sx-instance-model.c.
{
GList *vars = NULL;
g_hash_table_foreach(inst->variable_bindings, _build_list_from_hash_elts, &vars);
return vars;
}
| GHashTable* gnc_sx_instance_get_variables_for_parser | ( | GHashTable * | instance_var_hash | ) |
Definition at line 99 of file gnc-sx-instance-model.c.
{
GHashTable *parser_vars;
parser_vars = g_hash_table_new(g_str_hash, g_str_equal);
g_hash_table_foreach(instance_var_hash, (GHFunc)_sx_var_to_raw_numeric, parser_vars);
return parser_vars;
}
| void gnc_sx_instance_model_change_instance_state | ( | GncSxInstanceModel * | model, |
| GncSxInstance * | instance, | ||
| GncSxInstanceState | new_state | ||
| ) |
There is a constraint around a sequence of upcoming instance states. In short: the last-created state and a list of postponed instances are modeled, but upcoming reminders are not. As such, a reminder can never be before any other (modeled) instance type. For instance, the following sequences are disallowed:
[...] remind <- will be lost/skipped over; must be converted to `postponed`. to-create <- this will be the last-recorded state. [...]
[...] remind <- same as previous; will be lost/skipped; must be `postponed`. postponed [...]
remind <- same... ignore [...]
As such, the SinceLastRun model will enforce that there are no previous `remind` instances at every state change. They will be silently converted to `postponed`-state transactions.
Definition at line 1316 of file gnc-sx-instance-model.c.
{
if (instance->state == new_state)
return;
instance->state = new_state;
// ensure 'remind' constraints are met:
{
GList *inst_iter;
inst_iter = g_list_find(instance->parent->instance_list, instance);
g_assert(inst_iter != NULL);
if (instance->state != SX_INSTANCE_STATE_REMINDER)
{
// iterate backwards, making sure reminders are changed to 'postponed'
for (inst_iter = inst_iter->prev; inst_iter != NULL; inst_iter = inst_iter->prev)
{
GncSxInstance *prev_inst = (GncSxInstance*)inst_iter->data;
if (prev_inst->state != SX_INSTANCE_STATE_REMINDER)
continue;
prev_inst->state = SX_INSTANCE_STATE_POSTPONED;
}
}
else
{
// iterate forward, make sure transactions are set to 'remind'
for (inst_iter = inst_iter->next; inst_iter != NULL; inst_iter = inst_iter->next)
{
GncSxInstance *next_inst = (GncSxInstance*)inst_iter->data;
if (next_inst->state == SX_INSTANCE_STATE_REMINDER)
continue;
next_inst->state = SX_INSTANCE_STATE_REMINDER;
}
}
}
g_signal_emit_by_name(model, "updated", (gpointer)instance->parent->sx);
}
| GList* gnc_sx_instance_model_check_variables | ( | GncSxInstanceModel * | model | ) |
Definition at line 1377 of file gnc-sx-instance-model.c.
{
GList *rtn = NULL;
GList *sx_iter, *inst_iter, *var_list = NULL, *var_iter;
for (sx_iter = model->sx_instance_list; sx_iter != NULL; sx_iter = sx_iter->next)
{
GncSxInstances *instances = (GncSxInstances*)sx_iter->data;
for (inst_iter = instances->instance_list; inst_iter != NULL; inst_iter = inst_iter->next)
{
GncSxInstance *inst = (GncSxInstance*)inst_iter->data;
if (inst->state != SX_INSTANCE_STATE_TO_CREATE)
continue;
g_hash_table_foreach(inst->variable_bindings, (GHFunc)_list_from_hash_elts, &var_list);
for (var_iter = var_list; var_iter != NULL; var_iter = var_iter->next)
{
GncSxVariable *var = (GncSxVariable*)var_iter->data;
if (gnc_numeric_check(var->value) != GNC_ERROR_OK)
{
GncSxVariableNeeded *need = g_new0(GncSxVariableNeeded, 1);
need->instance = inst;
need->variable = var;
rtn = g_list_append(rtn, need);
}
}
g_list_free(var_list);
var_list = NULL;
}
}
return rtn;
}
| void gnc_sx_instance_model_effect_change | ( | GncSxInstanceModel * | model, |
| gboolean | auto_create_only, | ||
| GList ** | created_transaction_guids, | ||
| GList ** | creation_errors | ||
| ) |
Really ("effectively") create the transactions from the SX instances in the given model.
Definition at line 1232 of file gnc-sx-instance-model.c.
{
GList *iter;
for (iter = model->sx_instance_list; iter != NULL; iter = iter->next)
{
GList *instance_iter;
GncSxInstances *instances = (GncSxInstances*)iter->data;
GDate *last_occur_date;
gint instance_count = 0;
gint remain_occur_count = 0;
// If there are no instances, then skip; specifically, skip
// re-setting SchedXaction fields, which will dirty the book
// spuriously.
if (g_list_length(instances->instance_list) == 0)
continue;
last_occur_date = (GDate*) xaccSchedXactionGetLastOccurDate(instances->sx);
instance_count = gnc_sx_get_instance_count(instances->sx, NULL);
remain_occur_count = xaccSchedXactionGetRemOccur(instances->sx);
for (instance_iter = instances->instance_list; instance_iter != NULL; instance_iter = instance_iter->next)
{
GncSxInstance *inst = (GncSxInstance*)instance_iter->data;
gboolean sx_is_auto_create;
xaccSchedXactionGetAutoCreate(inst->parent->sx, &sx_is_auto_create, NULL);
if (auto_create_only && !sx_is_auto_create)
{
if (inst->state != SX_INSTANCE_STATE_TO_CREATE)
{
break;
}
continue;
}
if (inst->orig_state == SX_INSTANCE_STATE_POSTPONED
&& inst->state != SX_INSTANCE_STATE_POSTPONED)
{
// remove from postponed list
g_assert(inst->temporal_state != NULL);
gnc_sx_remove_defer_instance(inst->parent->sx, inst->temporal_state);
}
switch (inst->state)
{
case SX_INSTANCE_STATE_CREATED:
// nop: we've already processed this.
break;
case SX_INSTANCE_STATE_IGNORED:
increment_sx_state(inst, &last_occur_date, &instance_count, &remain_occur_count);
break;
case SX_INSTANCE_STATE_POSTPONED:
if (inst->orig_state != SX_INSTANCE_STATE_POSTPONED)
{
gnc_sx_add_defer_instance(instances->sx, inst->temporal_state);
}
increment_sx_state(inst, &last_occur_date, &instance_count, &remain_occur_count);
break;
case SX_INSTANCE_STATE_TO_CREATE:
create_transactions_for_instance(inst, created_transaction_guids, creation_errors);
increment_sx_state(inst, &last_occur_date, &instance_count, &remain_occur_count);
gnc_sx_instance_model_change_instance_state(model, inst, SX_INSTANCE_STATE_CREATED);
break;
case SX_INSTANCE_STATE_REMINDER:
// do nothing
// assert no non-remind instances after this?
break;
default:
g_assert_not_reached();
break;
}
}
xaccSchedXactionSetLastOccurDate(instances->sx, last_occur_date);
gnc_sx_set_instance_count(instances->sx, instance_count);
xaccSchedXactionSetRemOccur(instances->sx, remain_occur_count);
}
}
| void gnc_sx_instance_model_summarize | ( | GncSxInstanceModel * | model, |
| GncSxSummary * | summary | ||
| ) |
| summary | Caller-provided, populated with a summarization of the state of the model. Specifically, used to determine if there are SLR SXes that need either auto-creation or user-interaction. |
Definition at line 1412 of file gnc-sx-instance-model.c.
{
GList *sx_iter, *inst_iter;
g_return_if_fail(model != NULL);
g_return_if_fail(summary != NULL);
summary->need_dialog = FALSE;
summary->num_instances = 0;
summary->num_to_create_instances = 0;
summary->num_auto_create_instances = 0;
summary->num_auto_create_no_notify_instances = 0;
for (sx_iter = model->sx_instance_list; sx_iter != NULL; sx_iter = sx_iter->next)
{
GncSxInstances *instances = (GncSxInstances*)sx_iter->data;
gboolean sx_is_auto_create = FALSE, sx_notify = FALSE;
xaccSchedXactionGetAutoCreate(instances->sx, &sx_is_auto_create, &sx_notify);
for (inst_iter = instances->instance_list; inst_iter != NULL; inst_iter = inst_iter->next)
{
GncSxInstance *inst = (GncSxInstance*)inst_iter->data;
summary->num_instances++;
if (inst->state == SX_INSTANCE_STATE_TO_CREATE)
{
if (sx_is_auto_create)
{
if (!sx_notify)
{
summary->num_auto_create_no_notify_instances++;
}
else
{
summary->num_auto_create_instances++;
}
}
else
{
summary->num_to_create_instances++;
}
}
}
}
// if all the instances are 'auto-create, no-notify', then we don't need
// the dialog.
summary->need_dialog
= (summary->num_instances != 0
&& summary->num_auto_create_no_notify_instances != summary->num_instances);
}
| void gnc_sx_instance_model_update_sx_instances | ( | GncSxInstanceModel * | model, |
| SchedXaction * | sx | ||
| ) |
Regenerates and updates the GncSxInstances* for the given SX. Model consumers are probably going to call this in response to seeing the "update" signal, unless they need to be doing something else like finishing an iteration over an existing GncSxInstances*.
Definition at line 742 of file gnc-sx-instance-model.c.
{
GncSxInstances *existing, *new_instances;
GList *link;
link = g_list_find_custom(model->sx_instance_list, sx, (GCompareFunc)_gnc_sx_instance_find_by_sx);
if (link == NULL)
{
g_critical("couldn't find sx [%p]\n", sx);
return;
}
// merge the new instance data into the existing structure, mutating as little as possible.
existing = (GncSxInstances*)link->data;
new_instances = _gnc_sx_gen_instances((gpointer)sx, &model->range_end);
existing->sx = new_instances->sx;
existing->next_instance_date = new_instances->next_instance_date;
{
GList *existing_iter, *new_iter;
gboolean existing_remain, new_remain;
// step through the lists pairwise, and retain the existing
// instance if the dates align, as soon as they don't stop and
// cleanup.
existing_iter = existing->instance_list;
new_iter = new_instances->instance_list;
for (; existing_iter != NULL && new_iter != NULL; existing_iter = existing_iter->next, new_iter = new_iter->next)
{
GncSxInstance *existing_inst, *new_inst;
gboolean same_instance_date;
existing_inst = (GncSxInstance*)existing_iter->data;
new_inst = (GncSxInstance*)new_iter->data;
same_instance_date = g_date_compare(&existing_inst->date, &new_inst->date) == 0;
if (!same_instance_date)
break;
}
existing_remain = (existing_iter != NULL);
new_remain = (new_iter != NULL);
if (existing_remain)
{
// delete excess
gnc_g_list_cut(&existing->instance_list, existing_iter);
g_list_foreach(existing_iter, (GFunc)gnc_sx_instance_free, NULL);
}
if (new_remain)
{
// append new
GList *new_iter_iter;
gnc_g_list_cut(&new_instances->instance_list, new_iter);
for (new_iter_iter = new_iter; new_iter_iter != NULL; new_iter_iter = new_iter_iter->next)
{
GncSxInstance *inst = (GncSxInstance*)new_iter_iter->data;
inst->parent = existing;
existing->instance_list = g_list_append(existing->instance_list, new_iter_iter->data);
}
g_list_free(new_iter);
}
}
// handle variables
{
HashListPair removed_cb_data, added_cb_data;
GList *removed_var_names = NULL, *added_var_names = NULL;
GList *inst_iter = NULL;
removed_cb_data.hash = new_instances->variable_names;
removed_cb_data.list = NULL;
g_hash_table_foreach(existing->variable_names, (GHFunc)_find_unreferenced_vars, &removed_cb_data);
removed_var_names = removed_cb_data.list;
g_debug("%d removed variables", g_list_length(removed_var_names));
added_cb_data.hash = existing->variable_names;
added_cb_data.list = NULL;
g_hash_table_foreach(new_instances->variable_names, (GHFunc)_find_unreferenced_vars, &added_cb_data);
added_var_names = added_cb_data.list;
g_debug("%d added variables", g_list_length(added_var_names));
if (existing->variable_names != NULL)
{
g_hash_table_destroy(existing->variable_names);
}
existing->variable_names = new_instances->variable_names;
new_instances->variable_names = NULL;
for (inst_iter = existing->instance_list; inst_iter != NULL; inst_iter = inst_iter->next)
{
GList *var_iter;
GncSxInstance *inst = (GncSxInstance*)inst_iter->data;
for (var_iter = removed_var_names; var_iter != NULL; var_iter = var_iter->next)
{
gchar *to_remove_key = (gchar*)var_iter->data;
g_hash_table_remove(inst->variable_bindings, to_remove_key);
}
for (var_iter = added_var_names; var_iter != NULL; var_iter = var_iter->next)
{
gchar *to_add_key = (gchar*)var_iter->data;
if (!g_hash_table_lookup_extended(
inst->variable_bindings, to_add_key, NULL, NULL))
{
GncSxVariable *parent_var
= g_hash_table_lookup(existing->variable_names, to_add_key);
GncSxVariable *var_copy;
g_assert(parent_var != NULL);
var_copy = gnc_sx_variable_new_copy(parent_var);
g_hash_table_insert(inst->variable_bindings, g_strdup(to_add_key), var_copy);
}
}
}
}
gnc_sx_instances_free(new_instances);
}
| void gnc_sx_summary_print | ( | const GncSxSummary * | summary | ) |
Debug output to trace file
Definition at line 1464 of file gnc-sx-instance-model.c.
{
g_message("num_instances: %d", summary->num_instances);
g_message("num_to_create: %d", summary->num_to_create_instances);
g_message("num_auto_create_instances: %d", summary->num_auto_create_instances);
g_message("num_auto_create_no_notify_instances: %d", summary->num_auto_create_no_notify_instances);
g_message("need dialog? %s", summary->need_dialog ? "true" : "false");
}
1.7.4