GnuCash  4.11-137-g155922540d+
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 1668 of file gnc-sx-instance-model.c.

1669 {
1670  return g_hash_table_new_full (guid_hash_to_guint, guid_g_hash_table_equal,
1671  NULL, gnc_numeric_free);
1672 }
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:248

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

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

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

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

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

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

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

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

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

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