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

1672 {
1673  return g_hash_table_new_full (guid_hash_to_guint, guid_g_hash_table_equal,
1674  NULL, gnc_numeric_free);
1675 }
guint guid_hash_to_guint(gconstpointer ptr)
Hash function for a GUID.
Definition: guid.cpp:228
gint guid_g_hash_table_equal(gconstpointer guid_a, gconstpointer guid_b)
Equality function for two GUIDs in a GHashTable.
Definition: guid.cpp:247

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

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

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

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

569 {
570  GList *all_sxes = gnc_book_get_schedxactions(gnc_get_current_book())->sx_list;
571  GncSxInstanceModel *instances;
572 
573  g_assert(range_end != NULL);
574  g_assert(g_date_valid(range_end));
575 
576  instances = gnc_sx_instance_model_new();
577  instances->include_disabled = include_disabled;
578  instances->range_end = *range_end;
579 
580  if (include_disabled)
581  {
582  instances->sx_instance_list = gnc_g_list_map(all_sxes, (GncGMapFunc)_gnc_sx_gen_instances, (gpointer)range_end);
583  }
584  else
585  {
586  GList *sx_iter = g_list_first(all_sxes);
587  GList *enabled_sxes = NULL;
588 
589  for (; sx_iter != NULL; sx_iter = sx_iter->next)
590  {
591  SchedXaction *sx = (SchedXaction*)sx_iter->data;
592  if (xaccSchedXactionGetEnabled(sx))
593  {
594  enabled_sxes = g_list_prepend (enabled_sxes, sx);
595  }
596  }
597  enabled_sxes = g_list_reverse (enabled_sxes);
598  instances->sx_instance_list = gnc_g_list_map(enabled_sxes, (GncGMapFunc)_gnc_sx_gen_instances, (gpointer)range_end);
599  g_list_free(enabled_sxes);
600  }
601 
602  return instances;
603 }
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 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 1508 of file gnc-sx-instance-model.c.

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

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

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

1930 {
1931  return model->sx_instance_list;
1932 }

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

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

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