GnuCash  5.6-150-g038405b370+
Data Structures | Macros | Enumerations | Functions
gnc-sx-instance-model.h File Reference
#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  GncSxInstances
 
struct  GncSxVariable
 
struct  GncSxInstance
 
struct  GncSxVariableNeeded
 
struct  GncSxSummary
 

Macros

#define GNC_TYPE_SX_INSTANCE_MODEL   (gnc_sx_instance_model_get_type ())
 

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

GncSxInstanceModel * gnc_sx_get_current_instances (void)
 Shorthand for 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. More...
 
GncSxInstanceModel * gnc_sx_get_select_instances (GList *sel_sxes)
 Allocates a new SxInstanceModel and fills it with generated instances for the given scheduled transactions up to now. More...
 
void gnc_sx_instance_model_update_sx_instances (GncSxInstanceModel *model, SchedXaction *sx)
 Regenerates and updates the GncSxInstances* for the given SX. More...
 
void gnc_sx_instance_model_remove_sx_instances (GncSxInstanceModel *model, SchedXaction *sx)
 
void gnc_sx_scrub_split_numerics (gpointer psplit, gpointer user)
 Fix up numerics where they've gotten out-of-sync with the formulas. More...
 
GList * gnc_sx_instance_get_variables (GncSxInstance *inst)
 
Accountgnc_sx_get_template_transaction_account (const SchedXaction *sx)
 
GHashTable * gnc_sx_instance_get_variables_for_parser (GHashTable *instance_var_hash)
 
GncSxVariablegnc_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)
 There is a constraint around a sequence of upcoming instance states. More...
 
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)
 Really ("effectively") create the transactions from the SX instances in the given model. More...
 
void gnc_sx_instance_model_summarize (GncSxInstanceModel *model, GncSxSummary *summary)
 
void gnc_sx_summary_print (const GncSxSummary *summary)
 Debug output to trace file.
 
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)
 Returns a GHashTable<GUID*, gnc_numeric*> with no destructor for the key, but a destructor for the value set. More...
 
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. More...
 
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. More...
 
GList * gnc_sx_instance_model_get_sx_instances_list (GncSxInstanceModel *model)
 Returns the list of GncSxInstances in the model (Each element in the list has type GncSxInstances) More...
 

Function Documentation

◆ gnc_g_hash_new_guid_numeric()

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 1720 of file gnc-sx-instance-model.c.

1721 {
1722  return g_hash_table_new_full (guid_hash_to_guint, guid_g_hash_table_equal,
1723  NULL, gnc_numeric_free);
1724 }
guint guid_hash_to_guint(gconstpointer ptr)
Hash function for a GUID.
Definition: guid.cpp:255
gint guid_g_hash_table_equal(gconstpointer guid_a, gconstpointer guid_b)
Equality function for two GUIDs in a GHashTable.
Definition: guid.cpp:269

◆ gnc_sx_all_instantiate_cashflow()

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 1953 of file gnc-sx-instance-model.c.

1956 {
1957  SxAllCashflow userdata;
1958  userdata.hash = map;
1959  userdata.creation_errors = creation_errors;
1960  userdata.range_start = range_start;
1961  userdata.range_end = range_end;
1962 
1963  /* The work is done in the callback for each SX */
1964  g_list_foreach(all_sxes, instantiate_cashflow_cb, &userdata);
1965 }

◆ gnc_sx_all_instantiate_cashflow_all()

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 1968 of file gnc-sx-instance-model.c.

1969 {
1970  GHashTable *result_map = gnc_g_hash_new_guid_numeric();
1971  GList *all_sxes = gnc_book_get_schedxactions(gnc_get_current_book())->sx_list;
1973  &range_start, &range_end,
1974  result_map, NULL);
1975  return result_map;
1976 }
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 va...
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<G...

◆ gnc_sx_get_instances()

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 603 of file gnc-sx-instance-model.c.

604 {
605  GList *all_sxes = gnc_book_get_schedxactions(gnc_get_current_book())->sx_list;
606  GncSxInstanceModel *instances;
607 
608  g_assert(range_end != NULL);
609  g_assert(g_date_valid(range_end));
610 
611  instances = gnc_sx_instance_model_new();
612  instances->include_disabled = include_disabled;
613  instances->range_end = *range_end;
614 
615  if (include_disabled)
616  {
617  instances->sx_instance_list = gnc_g_list_map(all_sxes, (GncGMapFunc)_gnc_sx_gen_instances, (gpointer)range_end);
618  }
619  else
620  {
621  GList *sx_iter = g_list_first(all_sxes);
622  GList *enabled_sxes = NULL;
623 
624  for (; sx_iter != NULL; sx_iter = sx_iter->next)
625  {
626  SchedXaction *sx = (SchedXaction*)sx_iter->data;
627  if (xaccSchedXactionGetEnabled(sx))
628  {
629  enabled_sxes = g_list_prepend (enabled_sxes, sx);
630  }
631  }
632  enabled_sxes = g_list_reverse (enabled_sxes);
633  instances->sx_instance_list = gnc_g_list_map(enabled_sxes, (GncGMapFunc)_gnc_sx_gen_instances, (gpointer)range_end);
634  g_list_free(enabled_sxes);
635  }
636 
637  return instances;
638 }
GList * gnc_g_list_map(GList *list, GncGMapFunc fn, gpointer user_data)

◆ gnc_sx_get_select_instances()

GncSxInstanceModel* gnc_sx_get_select_instances ( GList *  sel_sxes)

Allocates a new SxInstanceModel and fills it with generated instances for the given scheduled transactions up to now.

If no instance exists for a given scheduled transaction, the next instance is generated.

The caller must unref the returned object by g_object_unref(G_OBJECT(inst_model)); when no longer in use.

Definition at line 641 of file gnc-sx-instance-model.c.

642 {
643  GncSxInstanceModel *instances;
644  GDate now;
645 
646  g_date_clear(&now, 1);
647  gnc_gdate_set_time64(&now, gnc_time(NULL));
648 
649  instances = gnc_sx_instance_model_new();
650  instances->include_disabled = TRUE;
651  instances->range_end = now;
652 
653  instances->sx_instance_list = gnc_g_list_map(sel_sxes, (GncGMapFunc)sx_gen_select_instances, (gpointer)&now);
654 
655  return instances;
656 }
GList * gnc_g_list_map(GList *list, GncGMapFunc fn, gpointer user_data)
void gnc_gdate_set_time64(GDate *gd, time64 time)
Set a GDate to a time64.
Definition: gnc-date.cpp:1314
time64 gnc_time(time64 *tbuf)
get the current time
Definition: gnc-date.cpp:262

◆ gnc_sx_instance_get_variables()

GList* gnc_sx_instance_get_variables ( GncSxInstance inst)
Returns
GList<GncSxVariable*>. Caller owns the list, but not the items.

Definition at line 475 of file gnc-sx-instance-model.c.

476 {
477  GList *vars = NULL;
478  g_hash_table_foreach(inst->variable_bindings, _build_list_from_hash_elts, &vars);
479  return g_list_sort (vars, _compare_GncSxVariables);
480 }
GHashTable * variable_bindings
variable bindings.

◆ gnc_sx_instance_get_variables_for_parser()

GHashTable* gnc_sx_instance_get_variables_for_parser ( GHashTable *  instance_var_hash)
Returns
caller-owned data struct.
caller-owned.

Definition at line 225 of file gnc-sx-instance-model.c.

226 {
227  GHashTable *parser_vars;
228 
229  parser_vars = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
230  g_hash_table_foreach(instance_var_hash, (GHFunc)_sx_var_to_raw_numeric, parser_vars);
231  return parser_vars;
232 }

◆ gnc_sx_instance_model_change_instance_state()

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 1557 of file gnc-sx-instance-model.c.

1560 {
1561  if (instance->state == new_state)
1562  return;
1563 
1564  instance->state = new_state;
1565 
1566  // ensure 'remind' constraints are met:
1567  {
1568  GList *inst_iter;
1569  inst_iter = g_list_find(instance->parent->instance_list, instance);
1570  g_assert(inst_iter != NULL);
1571  if (instance->state != SX_INSTANCE_STATE_REMINDER)
1572  {
1573  // iterate backwards, making sure reminders are changed to 'postponed'
1574  for (inst_iter = inst_iter->prev; inst_iter != NULL; inst_iter = inst_iter->prev)
1575  {
1576  GncSxInstance *prev_inst = (GncSxInstance*)inst_iter->data;
1577  if (prev_inst->state != SX_INSTANCE_STATE_REMINDER)
1578  continue;
1579  prev_inst->state = SX_INSTANCE_STATE_POSTPONED;
1580  }
1581  }
1582  else
1583  {
1584  // iterate forward, make sure transactions are set to 'remind'
1585  for (inst_iter = inst_iter->next; inst_iter != NULL; inst_iter = inst_iter->next)
1586  {
1587  GncSxInstance *next_inst = (GncSxInstance*)inst_iter->data;
1588  if (next_inst->state == SX_INSTANCE_STATE_REMINDER)
1589  continue;
1590  next_inst->state = SX_INSTANCE_STATE_REMINDER;
1591  }
1592  }
1593  }
1594 
1595  g_signal_emit_by_name(model, "updated", (gpointer)instance->parent->sx);
1596 }
GncSxInstances * parent
the parent instances collection.
GncSxInstanceState state
the current state of the instance (during editing)
GList * instance_list
GList<GncSxInstance*>

◆ gnc_sx_instance_model_check_variables()

GList* gnc_sx_instance_model_check_variables ( GncSxInstanceModel *  model)
Returns
List<GncSxVariableNeeded> of unbound {instance,variable} pairs; the caller owns the list and the items.

Definition at line 1618 of file gnc-sx-instance-model.c.

1619 {
1620  GList *rtn = NULL;
1621  GList *sx_iter, *inst_iter, *var_list = NULL, *var_iter;
1622 
1623  for (sx_iter = model->sx_instance_list; sx_iter != NULL; sx_iter = sx_iter->next)
1624  {
1625  GncSxInstances *instances = (GncSxInstances*)sx_iter->data;
1626  for (inst_iter = instances->instance_list; inst_iter != NULL; inst_iter = inst_iter->next)
1627  {
1628  GncSxInstance *inst = (GncSxInstance*)inst_iter->data;
1629 
1630  if (inst->state != SX_INSTANCE_STATE_TO_CREATE)
1631  continue;
1632 
1633  g_hash_table_foreach(inst->variable_bindings, (GHFunc)_list_from_hash_elts, &var_list);
1634  for (var_iter = var_list; var_iter != NULL; var_iter = var_iter->next)
1635  {
1636  GncSxVariable *var = (GncSxVariable*)var_iter->data;
1637  if (gnc_numeric_check(var->value) != GNC_ERROR_OK)
1638  {
1639  GncSxVariableNeeded *need = g_new0(GncSxVariableNeeded, 1);
1640  need->instance = inst;
1641  need->variable = var;
1642  rtn = g_list_prepend (rtn, need);
1643  }
1644  }
1645  g_list_free(var_list);
1646  var_list = NULL;
1647  }
1648  }
1649  return rtn;
1650 }
GHashTable * variable_bindings
variable bindings.
gnc_numeric value
only numeric values are supported.
GncSxInstanceState state
the current state of the instance (during editing)
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
Check for error signal in value.
GList * instance_list
GList<GncSxInstance*>
No error.
Definition: gnc-numeric.h:223

◆ gnc_sx_instance_model_effect_change()

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 1446 of file gnc-sx-instance-model.c.

1450 {
1451  GList *iter;
1452 
1453  if (qof_book_is_readonly(gnc_get_current_book()))
1454  {
1455  /* Is the book read-only? Then don't change anything here. */
1456  return;
1457  }
1458 
1459  for (iter = model->sx_instance_list; iter != NULL; iter = iter->next)
1460  {
1461  GList *instance_iter;
1462  GncSxInstances *instances = (GncSxInstances*)iter->data;
1463  GDate *last_occur_date;
1464  gint instance_count = 0;
1465  gint remain_occur_count = 0;
1466 
1467  // If there are no instances, then skip; specifically, skip
1468  // re-setting SchedXaction fields, which will dirty the book
1469  // spuriously.
1470  if (g_list_length(instances->instance_list) == 0)
1471  continue;
1472 
1473  last_occur_date = (GDate*) xaccSchedXactionGetLastOccurDate(instances->sx);
1474  instance_count = gnc_sx_get_instance_count(instances->sx, NULL);
1475  remain_occur_count = xaccSchedXactionGetRemOccur(instances->sx);
1476 
1477  for (instance_iter = instances->instance_list; instance_iter != NULL; instance_iter = instance_iter->next)
1478  {
1479  GncSxInstance *inst = (GncSxInstance*)instance_iter->data;
1480  gboolean sx_is_auto_create;
1481  GList *instance_errors = NULL;
1482 
1483  xaccSchedXactionGetAutoCreate(inst->parent->sx, &sx_is_auto_create, NULL);
1484  if (auto_create_only && !sx_is_auto_create)
1485  {
1486  if (inst->state != SX_INSTANCE_STATE_TO_CREATE)
1487  {
1488  break;
1489  }
1490  continue;
1491  }
1492 
1493  if (inst->orig_state == SX_INSTANCE_STATE_POSTPONED
1494  && inst->state != SX_INSTANCE_STATE_POSTPONED)
1495  {
1496  // remove from postponed list
1497  g_assert(inst->temporal_state != NULL);
1499  inst->temporal_state);
1500  }
1501 
1502  switch (inst->state)
1503  {
1504  case SX_INSTANCE_STATE_CREATED:
1505  // nop: we've already processed this.
1506  break;
1507  case SX_INSTANCE_STATE_IGNORED:
1508  increment_sx_state(inst, &last_occur_date, &instance_count, &remain_occur_count);
1509  break;
1510  case SX_INSTANCE_STATE_POSTPONED:
1511  if (inst->orig_state != SX_INSTANCE_STATE_POSTPONED)
1512  {
1513  gnc_sx_add_defer_instance(instances->sx,
1515  }
1516  increment_sx_state(inst, &last_occur_date, &instance_count, &remain_occur_count);
1517  break;
1518  case SX_INSTANCE_STATE_TO_CREATE:
1519  create_transactions_for_instance (inst,
1520  created_transaction_guids,
1521  &instance_errors);
1522  if (instance_errors == NULL)
1523  {
1524  increment_sx_state (inst, &last_occur_date,
1525  &instance_count,
1526  &remain_occur_count);
1528  (model, inst, SX_INSTANCE_STATE_CREATED);
1529  }
1530  else if (creation_errors)
1531  {
1532  *creation_errors = g_list_concat (*creation_errors,
1533  instance_errors);
1534  instance_errors = NULL;
1535  }
1536  break;
1537  case SX_INSTANCE_STATE_REMINDER:
1538  // do nothing
1539  // assert no non-remind instances after this?
1540  break;
1541  default:
1542  g_assert_not_reached();
1543  break;
1544  }
1545 
1546  if (instance_errors)
1547  g_list_free_full (instance_errors, g_free);
1548  }
1549 
1550  xaccSchedXactionSetLastOccurDate(instances->sx, last_occur_date);
1551  gnc_sx_set_instance_count(instances->sx, instance_count);
1552  xaccSchedXactionSetRemOccur(instances->sx, remain_occur_count);
1553  }
1554 }
void gnc_sx_set_instance_count(SchedXaction *sx, gint instance_num)
Sets the instance count to something other than the default.
SXTmpStateData * temporal_state
the sx creation temporal state.
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.
GncSxInstanceState orig_state
the original state at generation time.
GncSxInstances * parent
the parent instances collection.
void gnc_sx_add_defer_instance(SchedXaction *sx, void *deferStateData)
Adds an instance to the deferred list of the SX.
SXTmpStateData * gnc_sx_clone_temporal_state(SXTmpStateData *tsd)
Allocates and returns a one-by-one copy of the given temporal state.
gboolean qof_book_is_readonly(const QofBook *book)
Return whether the book is read only.
Definition: qofbook.cpp:497
GncSxInstanceState state
the current state of the instance (during editing)
void gnc_sx_remove_defer_instance(SchedXaction *sx, void *deferStateData)
Removes an instance from the deferred list.
GList * instance_list
GList<GncSxInstance*>
gint gnc_sx_get_instance_count(const SchedXaction *sx, SXTmpStateData *stateData)
Get the instance count.

◆ gnc_sx_instance_model_get_sx_instances_list()

GList* gnc_sx_instance_model_get_sx_instances_list ( GncSxInstanceModel *  model)

Returns the list of GncSxInstances in the model (Each element in the list has type GncSxInstances)

The returned list is owned by the model

Definition at line 1978 of file gnc-sx-instance-model.c.

1979 {
1980  return model->sx_instance_list;
1981 }

◆ gnc_sx_instance_model_summarize()

void gnc_sx_instance_model_summarize ( GncSxInstanceModel *  model,
GncSxSummary summary 
)
Parameters
summaryCaller-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 1653 of file gnc-sx-instance-model.c.

1654 {
1655  GList *sx_iter, *inst_iter;
1656 
1657  g_return_if_fail(model != NULL);
1658  g_return_if_fail(summary != NULL);
1659 
1660  summary->need_dialog = FALSE;
1661  summary->num_instances = 0;
1662  summary->num_to_create_instances = 0;
1663  summary->num_auto_create_instances = 0;
1665 
1666  for (sx_iter = model->sx_instance_list; sx_iter != NULL; sx_iter = sx_iter->next)
1667  {
1668  GncSxInstances *instances = (GncSxInstances*)sx_iter->data;
1669  gboolean sx_is_auto_create = FALSE, sx_notify = FALSE;
1670  xaccSchedXactionGetAutoCreate(instances->sx, &sx_is_auto_create, &sx_notify);
1671  for (inst_iter = instances->instance_list; inst_iter != NULL; inst_iter = inst_iter->next)
1672  {
1673  GncSxInstance *inst = (GncSxInstance*)inst_iter->data;
1674  summary->num_instances++;
1675 
1676  if (inst->state == SX_INSTANCE_STATE_TO_CREATE)
1677  {
1678  if (sx_is_auto_create)
1679  {
1680  if (!sx_notify)
1681  {
1683  }
1684  else
1685  {
1686  summary->num_auto_create_instances++;
1687  }
1688  }
1689  else
1690  {
1691  summary->num_to_create_instances++;
1692  }
1693  }
1694  }
1695  }
1696 
1697  // if all the instances are 'auto-create, no-notify', then we don't need
1698  // the dialog.
1699  summary->need_dialog
1700  = (summary->num_instances != 0
1701  && summary->num_auto_create_no_notify_instances != summary->num_instances);
1702 }
gint num_auto_create_no_notify_instances
The number of automatically-created instances that do no request notification.
gint num_to_create_instances
The number of (not-auto-create) to-create instances.
gint num_instances
The number of total instances (in any state).
gint num_auto_create_instances
The total number of auto-create instances.
GncSxInstanceState state
the current state of the instance (during editing)
GList * instance_list
GList<GncSxInstance*>
gboolean need_dialog
If the dialog needs to be displayed.

◆ gnc_sx_instance_model_update_sx_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 899 of file gnc-sx-instance-model.c.

900 {
901  GncSxInstances *existing, *new_instances;
902  GList *link;
903 
904  link = g_list_find_custom(model->sx_instance_list, sx, (GCompareFunc)_gnc_sx_instance_find_by_sx);
905  if (link == NULL)
906  {
907  g_critical("couldn't find sx [%p]\n", sx);
908  return;
909  }
910 
911  // merge the new instance data into the existing structure, mutating as little as possible.
912  existing = (GncSxInstances*)link->data;
913  new_instances = sx_instances(model, sx);
914  existing->sx = new_instances->sx;
915  existing->next_instance_date = new_instances->next_instance_date;
916  {
917  GList *existing_iter, *new_iter;
918  gboolean existing_remain, new_remain;
919 
920  // step through the lists pairwise, and retain the existing
921  // instance if the dates align, as soon as they don't stop and
922  // cleanup.
923  existing_iter = existing->instance_list;
924  new_iter = new_instances->instance_list;
925  for (; existing_iter != NULL && new_iter != NULL; existing_iter = existing_iter->next, new_iter = new_iter->next)
926  {
927  GncSxInstance *existing_inst, *new_inst;
928  gboolean same_instance_date;
929  existing_inst = (GncSxInstance*)existing_iter->data;
930  new_inst = (GncSxInstance*)new_iter->data;
931 
932  same_instance_date = g_date_compare(&existing_inst->date, &new_inst->date) == 0;
933  if (!same_instance_date)
934  break;
935  }
936 
937  existing_remain = (existing_iter != NULL);
938  new_remain = (new_iter != NULL);
939 
940  if (existing_remain)
941  {
942  // delete excess
943  gnc_g_list_cut(&existing->instance_list, existing_iter);
944  g_list_foreach(existing_iter, (GFunc)gnc_sx_instance_free, NULL);
945  }
946 
947  if (new_remain)
948  {
949  // append new
950  GList *new_iter_iter;
951  gnc_g_list_cut(&new_instances->instance_list, new_iter);
952 
953  for (new_iter_iter = new_iter; new_iter_iter != NULL; new_iter_iter = new_iter_iter->next)
954  {
955  GncSxInstance *inst = (GncSxInstance*)new_iter_iter->data;
956  inst->parent = existing;
957  existing->instance_list = g_list_append(existing->instance_list, new_iter_iter->data);
958  }
959  g_list_free(new_iter);
960  }
961  }
962 
963  // handle variables
964  {
965  GList *removed_var_names = NULL, *added_var_names = NULL;
966  GList *inst_iter = NULL;
967 
968  if (existing->variable_names != NULL)
969  {
970  HashListPair removed_cb_data;
971  removed_cb_data.hash = new_instances->variable_names;
972  removed_cb_data.list = NULL;
973  g_hash_table_foreach(existing->variable_names, (GHFunc)_find_unreferenced_vars, &removed_cb_data);
974  removed_var_names = g_list_reverse (removed_cb_data.list);
975  }
976  DEBUG("%d removed variables", g_list_length(removed_var_names));
977 
978  if (new_instances->variable_names != NULL)
979  {
980  HashListPair added_cb_data;
981  added_cb_data.hash = existing->variable_names;
982  added_cb_data.list = NULL;
983  g_hash_table_foreach(new_instances->variable_names, (GHFunc)_find_unreferenced_vars, &added_cb_data);
984  added_var_names = g_list_reverse (added_cb_data.list);
985  }
986  DEBUG("%d added variables", g_list_length(added_var_names));
987 
988  if (existing->variable_names != NULL)
989  {
990  g_hash_table_destroy(existing->variable_names);
991  }
992  existing->variable_names = new_instances->variable_names;
993  new_instances->variable_names = NULL;
994 
995  for (inst_iter = existing->instance_list; inst_iter != NULL; inst_iter = inst_iter->next)
996  {
997  GList *var_iter;
998  GncSxInstance *inst = (GncSxInstance*)inst_iter->data;
999 
1000  for (var_iter = removed_var_names; var_iter != NULL; var_iter = var_iter->next)
1001  {
1002  gchar *to_remove_key = (gchar*)var_iter->data;
1003  g_hash_table_remove(inst->variable_bindings, to_remove_key);
1004  }
1005 
1006  for (var_iter = added_var_names; var_iter != NULL; var_iter = var_iter->next)
1007  {
1008  gchar *to_add_key = (gchar*)var_iter->data;
1009  if (!g_hash_table_lookup_extended(
1010  inst->variable_bindings, to_add_key, NULL, NULL))
1011  {
1012  GncSxVariable *parent_var
1013  = g_hash_table_lookup(existing->variable_names, to_add_key);
1014  GncSxVariable *var_copy;
1015 
1016  g_assert(parent_var != NULL);
1017  var_copy = gnc_sx_variable_new_copy(parent_var);
1018  g_hash_table_insert(inst->variable_bindings, g_strdup(to_add_key), var_copy);
1019  }
1020  }
1021  }
1022  }
1023  gnc_sx_instances_free(new_instances);
1024 }
GHashTable * variable_bindings
variable bindings.
GHashTable * variable_names
<name:char*,GncSxVariable*>
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
GncSxInstances * parent
the parent instances collection.
void gnc_g_list_cut(GList **list, GList *cut_point)
Cut a GList into two parts; the cut_point is the beginning of the new list; list may need to be modif...
GDate date
the instance date.
GList * instance_list
GList<GncSxInstance*>

◆ gnc_sx_scrub_split_numerics()

void gnc_sx_scrub_split_numerics ( gpointer  psplit,
gpointer  user 
)

Fix up numerics where they've gotten out-of-sync with the formulas.

Ideally this would be done at load time, but it requires gnc_exp_parser to work and neither engine nor the backends can depend on it.

Definition at line 154 of file gnc-sx-instance-model.c.

155 {
156  Split *split = GNC_SPLIT (psplit);
157  Transaction *trans = xaccSplitGetParent (split);
158  GList *changes = NULL;
159  scrub_sx_split_numeric (split, TRUE, &changes);
160  scrub_sx_split_numeric (split, FALSE, &changes);
161  if (!changes)
162  return;
163 
164  xaccTransBeginEdit (trans);
165  for (GList *n = changes; n; n = n->next)
166  {
167  ScrubItem *change = n->data;
168  qof_instance_set (QOF_INSTANCE (split),
169  change->name, &change->amount,
170  NULL);
171  }
172  xaccTransCommitEdit (trans);
173  g_list_free_full (changes, g_free);
174 }
void qof_instance_set(QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_set Group setting multiple parameters in a single begin/commit/rollback.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...