GnuCash  4.901-15-g732a005710
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  GncSxInstanceModel
 
struct  GncSxInstanceModelClass
 
struct  GncSxInstances
 
struct  GncSxVariable
 
struct  GncSxInstance
 
struct  GncSxVariableNeeded
 
struct  GncSxSummary
 

Macros

#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))
 

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)
 
GncSxInstanceModelgnc_sx_get_current_instances (void)
 Shorthand for get_instances(now, FALSE);.
 
GncSxInstanceModelgnc_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...
 
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...
 

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

1675 {
1676  return g_hash_table_new_full (guid_hash_to_guint, guid_g_hash_table_equal,
1677  NULL, gnc_numeric_free);
1678 }
guint guid_hash_to_guint(gconstpointer ptr)
Hash function for a GUID.
Definition: guid.cpp:225
gint guid_g_hash_table_equal(gconstpointer guid_a, gconstpointer guid_b)
Equality function for two GUIDs in a GHashTable.
Definition: guid.cpp:244

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

1910 {
1911  SxAllCashflow userdata;
1912  userdata.hash = map;
1913  userdata.creation_errors = creation_errors;
1914  userdata.range_start = range_start;
1915  userdata.range_end = range_end;
1916 
1917  /* The work is done in the callback for each SX */
1918  g_list_foreach(all_sxes, instantiate_cashflow_cb, &userdata);
1919 }

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

1923 {
1924  GHashTable *result_map = gnc_g_hash_new_guid_numeric();
1925  GList *all_sxes = gnc_book_get_schedxactions(gnc_get_current_book())->sx_list;
1927  &range_start, &range_end,
1928  result_map, NULL);
1929  return result_map;
1930 }
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 551 of file gnc-sx-instance-model.c.

552 {
553  GList *all_sxes = gnc_book_get_schedxactions(gnc_get_current_book())->sx_list;
554  GncSxInstanceModel *instances;
555 
556  g_assert(range_end != NULL);
557  g_assert(g_date_valid(range_end));
558 
559  instances = gnc_sx_instance_model_new();
560  instances->include_disabled = include_disabled;
561  instances->range_end = *range_end;
562 
563  if (include_disabled)
564  {
565  instances->sx_instance_list = gnc_g_list_map(all_sxes, (GncGMapFunc)_gnc_sx_gen_instances, (gpointer)range_end);
566  }
567  else
568  {
569  GList *sx_iter = g_list_first(all_sxes);
570  GList *enabled_sxes = NULL;
571 
572  for (; sx_iter != NULL; sx_iter = sx_iter->next)
573  {
574  SchedXaction *sx = (SchedXaction*)sx_iter->data;
575  if (xaccSchedXactionGetEnabled(sx))
576  {
577  enabled_sxes = g_list_prepend (enabled_sxes, sx);
578  }
579  }
580  enabled_sxes = g_list_reverse (enabled_sxes);
581  instances->sx_instance_list = gnc_g_list_map(enabled_sxes, (GncGMapFunc)_gnc_sx_gen_instances, (gpointer)range_end);
582  g_list_free(enabled_sxes);
583  }
584 
585  return instances;
586 }
GList * gnc_g_list_map(GList *list, GncGMapFunc fn, gpointer user_data)

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

459 {
460  GList *vars = NULL;
461  g_hash_table_foreach(inst->variable_bindings, _build_list_from_hash_elts, &vars);
462  return g_list_sort (vars, _compare_GncSxVariables);
463 }
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 209 of file gnc-sx-instance-model.c.

210 {
211  GHashTable *parser_vars;
212 
213  parser_vars = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
214  g_hash_table_foreach(instance_var_hash, (GHFunc)_sx_var_to_raw_numeric, parser_vars);
215  return parser_vars;
216 }

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

1514 {
1515  if (instance->state == new_state)
1516  return;
1517 
1518  instance->state = new_state;
1519 
1520  // ensure 'remind' constraints are met:
1521  {
1522  GList *inst_iter;
1523  inst_iter = g_list_find(instance->parent->instance_list, instance);
1524  g_assert(inst_iter != NULL);
1525  if (instance->state != SX_INSTANCE_STATE_REMINDER)
1526  {
1527  // iterate backwards, making sure reminders are changed to 'postponed'
1528  for (inst_iter = inst_iter->prev; inst_iter != NULL; inst_iter = inst_iter->prev)
1529  {
1530  GncSxInstance *prev_inst = (GncSxInstance*)inst_iter->data;
1531  if (prev_inst->state != SX_INSTANCE_STATE_REMINDER)
1532  continue;
1533  prev_inst->state = SX_INSTANCE_STATE_POSTPONED;
1534  }
1535  }
1536  else
1537  {
1538  // iterate forward, make sure transactions are set to 'remind'
1539  for (inst_iter = inst_iter->next; inst_iter != NULL; inst_iter = inst_iter->next)
1540  {
1541  GncSxInstance *next_inst = (GncSxInstance*)inst_iter->data;
1542  if (next_inst->state == SX_INSTANCE_STATE_REMINDER)
1543  continue;
1544  next_inst->state = SX_INSTANCE_STATE_REMINDER;
1545  }
1546  }
1547  }
1548 
1549  g_signal_emit_by_name(model, "updated", (gpointer)instance->parent->sx);
1550 }
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 1572 of file gnc-sx-instance-model.c.

1573 {
1574  GList *rtn = NULL;
1575  GList *sx_iter, *inst_iter, *var_list = NULL, *var_iter;
1576 
1577  for (sx_iter = model->sx_instance_list; sx_iter != NULL; sx_iter = sx_iter->next)
1578  {
1579  GncSxInstances *instances = (GncSxInstances*)sx_iter->data;
1580  for (inst_iter = instances->instance_list; inst_iter != NULL; inst_iter = inst_iter->next)
1581  {
1582  GncSxInstance *inst = (GncSxInstance*)inst_iter->data;
1583 
1584  if (inst->state != SX_INSTANCE_STATE_TO_CREATE)
1585  continue;
1586 
1587  g_hash_table_foreach(inst->variable_bindings, (GHFunc)_list_from_hash_elts, &var_list);
1588  for (var_iter = var_list; var_iter != NULL; var_iter = var_iter->next)
1589  {
1590  GncSxVariable *var = (GncSxVariable*)var_iter->data;
1591  if (gnc_numeric_check(var->value) != GNC_ERROR_OK)
1592  {
1593  GncSxVariableNeeded *need = g_new0(GncSxVariableNeeded, 1);
1594  need->instance = inst;
1595  need->variable = var;
1596  rtn = g_list_prepend (rtn, need);
1597  }
1598  }
1599  g_list_free(var_list);
1600  var_list = NULL;
1601  }
1602  }
1603  return rtn;
1604 }
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 in)
Check for error signal in value.
GList * instance_list
GList<GncSxInstance*>
No error.
Definition: gnc-numeric.h:225

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

1410 {
1411  GList *iter;
1412 
1413  if (qof_book_is_readonly(gnc_get_current_book()))
1414  {
1415  /* Is the book read-only? Then don't change anything here. */
1416  return;
1417  }
1418 
1419  for (iter = model->sx_instance_list; iter != NULL; iter = iter->next)
1420  {
1421  GList *instance_iter;
1422  GncSxInstances *instances = (GncSxInstances*)iter->data;
1423  GDate *last_occur_date;
1424  gint instance_count = 0;
1425  gint remain_occur_count = 0;
1426 
1427  // If there are no instances, then skip; specifically, skip
1428  // re-setting SchedXaction fields, which will dirty the book
1429  // spuriously.
1430  if (g_list_length(instances->instance_list) == 0)
1431  continue;
1432 
1433  last_occur_date = (GDate*) xaccSchedXactionGetLastOccurDate(instances->sx);
1434  instance_count = gnc_sx_get_instance_count(instances->sx, NULL);
1435  remain_occur_count = xaccSchedXactionGetRemOccur(instances->sx);
1436 
1437  for (instance_iter = instances->instance_list; instance_iter != NULL; instance_iter = instance_iter->next)
1438  {
1439  GncSxInstance *inst = (GncSxInstance*)instance_iter->data;
1440  gboolean sx_is_auto_create;
1441  GList *instance_errors = NULL;
1442 
1443  xaccSchedXactionGetAutoCreate(inst->parent->sx, &sx_is_auto_create, NULL);
1444  if (auto_create_only && !sx_is_auto_create)
1445  {
1446  if (inst->state != SX_INSTANCE_STATE_TO_CREATE)
1447  {
1448  break;
1449  }
1450  continue;
1451  }
1452 
1453  if (inst->orig_state == SX_INSTANCE_STATE_POSTPONED
1454  && inst->state != SX_INSTANCE_STATE_POSTPONED)
1455  {
1456  // remove from postponed list
1457  g_assert(inst->temporal_state != NULL);
1459  inst->temporal_state);
1460  }
1461 
1462  switch (inst->state)
1463  {
1464  case SX_INSTANCE_STATE_CREATED:
1465  // nop: we've already processed this.
1466  break;
1467  case SX_INSTANCE_STATE_IGNORED:
1468  increment_sx_state(inst, &last_occur_date, &instance_count, &remain_occur_count);
1469  break;
1470  case SX_INSTANCE_STATE_POSTPONED:
1471  if (inst->orig_state != SX_INSTANCE_STATE_POSTPONED)
1472  {
1473  gnc_sx_add_defer_instance(instances->sx,
1475  }
1476  increment_sx_state(inst, &last_occur_date, &instance_count, &remain_occur_count);
1477  break;
1478  case SX_INSTANCE_STATE_TO_CREATE:
1479  create_transactions_for_instance (inst,
1480  created_transaction_guids,
1481  &instance_errors);
1482  if (instance_errors == NULL)
1483  {
1484  increment_sx_state (inst, &last_occur_date,
1485  &instance_count,
1486  &remain_occur_count);
1488  (model, inst, SX_INSTANCE_STATE_CREATED);
1489  }
1490  else
1491  *creation_errors = g_list_concat (*creation_errors,
1492  instance_errors);
1493  break;
1494  case SX_INSTANCE_STATE_REMINDER:
1495  // do nothing
1496  // assert no non-remind instances after this?
1497  break;
1498  default:
1499  g_assert_not_reached();
1500  break;
1501  }
1502  }
1503 
1504  xaccSchedXactionSetLastOccurDate(instances->sx, last_occur_date);
1505  gnc_sx_set_instance_count(instances->sx, instance_count);
1506  xaccSchedXactionSetRemOccur(instances->sx, remain_occur_count);
1507  }
1508 }
void gnc_sx_set_instance_count(SchedXaction *sx, gint instance_num)
Sets the instance count to something other than the default.
Definition: SchedXaction.c:980
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:499
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.
Definition: SchedXaction.c:961

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

1608 {
1609  GList *sx_iter, *inst_iter;
1610 
1611  g_return_if_fail(model != NULL);
1612  g_return_if_fail(summary != NULL);
1613 
1614  summary->need_dialog = FALSE;
1615  summary->num_instances = 0;
1616  summary->num_to_create_instances = 0;
1617  summary->num_auto_create_instances = 0;
1619 
1620  for (sx_iter = model->sx_instance_list; sx_iter != NULL; sx_iter = sx_iter->next)
1621  {
1622  GncSxInstances *instances = (GncSxInstances*)sx_iter->data;
1623  gboolean sx_is_auto_create = FALSE, sx_notify = FALSE;
1624  xaccSchedXactionGetAutoCreate(instances->sx, &sx_is_auto_create, &sx_notify);
1625  for (inst_iter = instances->instance_list; inst_iter != NULL; inst_iter = inst_iter->next)
1626  {
1627  GncSxInstance *inst = (GncSxInstance*)inst_iter->data;
1628  summary->num_instances++;
1629 
1630  if (inst->state == SX_INSTANCE_STATE_TO_CREATE)
1631  {
1632  if (sx_is_auto_create)
1633  {
1634  if (!sx_notify)
1635  {
1637  }
1638  else
1639  {
1640  summary->num_auto_create_instances++;
1641  }
1642  }
1643  else
1644  {
1645  summary->num_to_create_instances++;
1646  }
1647  }
1648  }
1649  }
1650 
1651  // if all the instances are 'auto-create, no-notify', then we don't need
1652  // the dialog.
1653  summary->need_dialog
1654  = (summary->num_instances != 0
1655  && summary->num_auto_create_no_notify_instances != summary->num_instances);
1656 }
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 859 of file gnc-sx-instance-model.c.

860 {
861  GncSxInstances *existing, *new_instances;
862  GList *link;
863 
864  link = g_list_find_custom(model->sx_instance_list, sx, (GCompareFunc)_gnc_sx_instance_find_by_sx);
865  if (link == NULL)
866  {
867  g_critical("couldn't find sx [%p]\n", sx);
868  return;
869  }
870 
871  // merge the new instance data into the existing structure, mutating as little as possible.
872  existing = (GncSxInstances*)link->data;
873  new_instances = _gnc_sx_gen_instances((gpointer)sx, &model->range_end);
874  existing->sx = new_instances->sx;
875  existing->next_instance_date = new_instances->next_instance_date;
876  {
877  GList *existing_iter, *new_iter;
878  gboolean existing_remain, new_remain;
879 
880  // step through the lists pairwise, and retain the existing
881  // instance if the dates align, as soon as they don't stop and
882  // cleanup.
883  existing_iter = existing->instance_list;
884  new_iter = new_instances->instance_list;
885  for (; existing_iter != NULL && new_iter != NULL; existing_iter = existing_iter->next, new_iter = new_iter->next)
886  {
887  GncSxInstance *existing_inst, *new_inst;
888  gboolean same_instance_date;
889  existing_inst = (GncSxInstance*)existing_iter->data;
890  new_inst = (GncSxInstance*)new_iter->data;
891 
892  same_instance_date = g_date_compare(&existing_inst->date, &new_inst->date) == 0;
893  if (!same_instance_date)
894  break;
895  }
896 
897  existing_remain = (existing_iter != NULL);
898  new_remain = (new_iter != NULL);
899 
900  if (existing_remain)
901  {
902  // delete excess
903  gnc_g_list_cut(&existing->instance_list, existing_iter);
904  g_list_foreach(existing_iter, (GFunc)gnc_sx_instance_free, NULL);
905  }
906 
907  if (new_remain)
908  {
909  // append new
910  GList *new_iter_iter;
911  gnc_g_list_cut(&new_instances->instance_list, new_iter);
912 
913  for (new_iter_iter = new_iter; new_iter_iter != NULL; new_iter_iter = new_iter_iter->next)
914  {
915  GncSxInstance *inst = (GncSxInstance*)new_iter_iter->data;
916  inst->parent = existing;
917  existing->instance_list = g_list_append(existing->instance_list, new_iter_iter->data);
918  }
919  g_list_free(new_iter);
920  }
921  }
922 
923  // handle variables
924  {
925  GList *removed_var_names = NULL, *added_var_names = NULL;
926  GList *inst_iter = NULL;
927 
928  if (existing->variable_names != NULL)
929  {
930  HashListPair removed_cb_data;
931  removed_cb_data.hash = new_instances->variable_names;
932  removed_cb_data.list = NULL;
933  g_hash_table_foreach(existing->variable_names, (GHFunc)_find_unreferenced_vars, &removed_cb_data);
934  removed_var_names = g_list_reverse (removed_cb_data.list);
935  }
936  DEBUG("%d removed variables", g_list_length(removed_var_names));
937 
938  if (new_instances->variable_names != NULL)
939  {
940  HashListPair added_cb_data;
941  added_cb_data.hash = existing->variable_names;
942  added_cb_data.list = NULL;
943  g_hash_table_foreach(new_instances->variable_names, (GHFunc)_find_unreferenced_vars, &added_cb_data);
944  added_var_names = g_list_reverse (added_cb_data.list);
945  }
946  DEBUG("%d added variables", g_list_length(added_var_names));
947 
948  if (existing->variable_names != NULL)
949  {
950  g_hash_table_destroy(existing->variable_names);
951  }
952  existing->variable_names = new_instances->variable_names;
953  new_instances->variable_names = NULL;
954 
955  for (inst_iter = existing->instance_list; inst_iter != NULL; inst_iter = inst_iter->next)
956  {
957  GList *var_iter;
958  GncSxInstance *inst = (GncSxInstance*)inst_iter->data;
959 
960  for (var_iter = removed_var_names; var_iter != NULL; var_iter = var_iter->next)
961  {
962  gchar *to_remove_key = (gchar*)var_iter->data;
963  g_hash_table_remove(inst->variable_bindings, to_remove_key);
964  }
965 
966  for (var_iter = added_var_names; var_iter != NULL; var_iter = var_iter->next)
967  {
968  gchar *to_add_key = (gchar*)var_iter->data;
969  if (!g_hash_table_lookup_extended(
970  inst->variable_bindings, to_add_key, NULL, NULL))
971  {
972  GncSxVariable *parent_var
973  = g_hash_table_lookup(existing->variable_names, to_add_key);
974  GncSxVariable *var_copy;
975 
976  g_assert(parent_var != NULL);
977  var_copy = gnc_sx_variable_new_copy(parent_var);
978  g_hash_table_insert(inst->variable_bindings, g_strdup(to_add_key), var_copy);
979  }
980  }
981  }
982  }
983  gnc_sx_instances_free(new_instances);
984 }
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 138 of file gnc-sx-instance-model.c.

139 {
140  Split *split = GNC_SPLIT (psplit);
141  Transaction *trans = xaccSplitGetParent (split);
142  GList *changes = NULL;
143  scrub_sx_split_numeric (split, TRUE, &changes);
144  scrub_sx_split_numeric (split, FALSE, &changes);
145  if (!changes)
146  return;
147 
148  xaccTransBeginEdit (trans);
149  for (GList *n = changes; n; n = n->next)
150  {
151  ScrubItem *change = n->data;
152  qof_instance_set (QOF_INSTANCE (split),
153  change->name, &change->amount,
154  NULL);
155  }
156  xaccTransCommitEdit (trans);
157  g_list_free_full (changes, g_free);
158 }
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...