GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gnc-commodity.c
1 /********************************************************************
2  * gnc-commodity.c -- api for tradable commodities (incl. currency) *
3  * Copyright (C) 2000 Bill Gribble *
4  * Copyright (C) 2001,2003 Linas Vepstas <[email protected]> *
5  * Copyright (c) 2006 David Hampton <[email protected]> *
6  * *
7  * This program is free software; you can redistribute it and/or *
8  * modify it under the terms of the GNU General Public License as *
9  * published by the Free Software Foundation; either version 2 of *
10  * the License, or (at your option) any later version. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License*
18  * along with this program; if not, contact: *
19  * *
20  * Free Software Foundation Voice: +1-617-542-5942 *
21  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
22  * Boston, MA 02110-1301, USA [email protected] *
23  * *
24  *******************************************************************/
25 
26 #include <config.h>
27 
28 #include <glib.h>
29 #include <glib/gi18n.h>
30 #include <ctype.h>
31 #include <limits.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <regex.h>
36 #include <qofinstance-p.h>
37 
38 #include "gnc-commodity.h"
39 #include "gnc-locale-utils.h"
40 #include "gnc-prefs.h"
41 
42 static QofLogModule log_module = GNC_MOD_COMMODITY;
43 
44 /* Parts per unit is nominal, i.e. number of 'partname' units in
45  * a 'unitname' unit. fraction is transactional, i.e. how many
46  * of the smallest-transactional-units of the currency are there
47  * in a 'unitname' unit. */
48 
49 enum
50 {
51  PROP_0,
52  PROP_NAMESPACE, /* Table */
53  PROP_FULL_NAME, /* Table */
54  PROP_MNEMONIC, /* Table */
55  PROP_PRINTNAME, /* Constructed */
56  PROP_CUSIP, /* Table */
57  PROP_FRACTION, /* Table */
58  PROP_UNIQUE_NAME, /* Constructed */
59  PROP_QUOTE_FLAG, /* Table */
60  PROP_QUOTE_SOURCE, /* Table */
61  PROP_QUOTE_TZ, /* Table */
62 };
63 
65 {
66  QofInstance inst;
67 };
68 
69 typedef struct CommodityPrivate
70 {
71  gnc_commodity_namespace *name_space;
72 
73  char * fullname;
74  char * mnemonic;
75  char * printname;
76  char * cusip; /* CUSIP or other identifying code */
77  int fraction;
78  char * unique_name;
79 
80  gboolean quote_flag; /* user wants price quotes */
81  gnc_quote_source * quote_source; /* current/old source of quotes */
82  char * quote_tz;
83 
84  /* the number of accounts using this commodity - this field is not
85  * persisted */
86  int usage_count;
87 
88  /* the default display_symbol, set in iso-4217-currencies at start-up */
89  const char * default_symbol;
91 
92 #define GET_PRIVATE(o) \
93  (G_TYPE_INSTANCE_GET_PRIVATE((o), GNC_TYPE_COMMODITY, CommodityPrivate))
94 
96 {
97  QofInstanceClass parent_class;
98 };
99 
100 static void commodity_free(gnc_commodity * cm);
101 static void gnc_commodity_set_default_symbol(gnc_commodity *, const char *);
102 
104 {
105  QofInstance inst;
106 
107  gchar * name;
108  gboolean iso4217;
109  GHashTable * cm_table;
110  GList * cm_list;
111 };
112 
114 {
115  QofInstanceClass parent_class;
116 };
117 
119 {
120  GHashTable * ns_table;
121  GList * ns_list;
122 };
123 
125 {
126  const char *old_code;
127  const char *new_code;
128 } gnc_new_iso_codes[] =
129 {
130  {"RUR", "RUB"}, /* Russian Ruble: RUR through 1997-12, RUB from 1998-01 onwards; see bug #393185 */
131  {"PLZ", "PLN"}, /* Polish Zloty */
132  {"UAG", "UAH"}, /* Ukraine Hryvnia */
133  {"NIS", "ILS"}, /* New Israeli Shekel: The informal abbreviation may be "NIS", but
134  its iso-4217 is clearly ILS and only this! Incorrectly changed
135  due to bug#152755 (Nov 2004) and changed back again by bug#492417
136  (Oct 2008). */
137  {"MXP", "MXN"}, /* Mexican (Nuevo) Peso */
138  {"TRL", "TRY"}, /* New Turkish Lira: changed 2005 */
139 
140  /* Only add currencies to this table when the old currency no longer
141  * exists in the file iso-4217-currencies.scm */
142 };
143 #define GNC_NEW_ISO_CODES \
144  (sizeof(gnc_new_iso_codes) / sizeof(struct gnc_new_iso_code))
145 
146 static gboolean fq_is_installed = FALSE;
147 
149 {
150  gboolean supported;
151  QuoteSourceType type;
152  gint index;
153  char *user_name; /* User friendly name */
154  char *old_internal_name; /* Name used internally (deprecated) */
155  char *internal_name; /* Name used internally and by finance::quote. */
156 };
157 
158 static gnc_quote_source currency_quote_source =
159 { TRUE, 0, 0, "Currency", "CURRENCY", "currency" };
160 
161 static gnc_quote_source single_quote_sources[] =
162 {
163  { FALSE, 0, 0, "Amsterdam Euronext eXchange, NL", "AEX", "aex" },
164  { FALSE, 0, 0, "AEX Futures (now in AEX)", "AEX_FUTURES", "aex_futures" },
165  { FALSE, 0, 0, "AEX Options (now in AEX)", "AEX_OPTIONS", "aex_options" },
166  { FALSE, 0, 0, "American International Assurance, HK", "AIAHK", "aiahk" },
167  { FALSE, 0, 0, "Association of Mutual Funds in India", "AMFIINDIA", "amfiindia" },
168  { FALSE, 0, 0, "Athens Stock Exchange, GR", "ASEGR", "asegr" },
169  { FALSE, 0, 0, "Australian Stock Exchange, AU", "ASX", "asx" },
170  { FALSE, 0, 0, "BMO NesbittBurns, CA", "BMONESBITTBURNS", "bmonesbittburns" },
171  { FALSE, 0, 0, "BUX/Magyar Tökepiac, HU", "BUX", "bux" },
172  { FALSE, 0, 0, "Cominvest, ex-Adig, DE", "COMINVEST", "cominvest" },
173  { FALSE, 0, 0, "Deka Investments, DE", "DEKA", "deka" },
174  { FALSE, 0, 0, "DWS, DE", "DWS", "dwsfunds" },
175  { FALSE, 0, 0, "Fidelity Direct", "FIDELITY_DIRECT", "fidelity_direct" },
176  { FALSE, 0, 0, "Finance Canada", "FINANCECANADA", "financecanada" },
177  { FALSE, 0, 0, "Finanzpartner, DE", "FINANZPARTNER", "finanzpartner" },
178  { FALSE, 0, 0, "First Trust Portfolios, US", "FTPORTFOLIOS_DIRECT", "ftportfolios_direct" },
179  { FALSE, 0, 0, "Fund Library, CA", "FUNDLIBRARY", "fundlibrary" },
180  { FALSE, 0, 0, "GoldMoney spot rates, JE", "GOLDMONEY", "goldmoney" },
181  { FALSE, 0, 0, "HElsinki stock eXchange, FI", "HEX", "hex" },
182  { FALSE, 0, 0, "Man Investments, AU", "maninv", "maninv" },
183  { FALSE, 0, 0, "Morningstar, SE", "MORNINGSTAR", "morningstar" },
184  { FALSE, 0, 0, "Motley Fool, US", "FOOL", "fool" },
185  { FALSE, 0, 0, "New Zealand stock eXchange, NZ", "NZX", "nzx" },
186  { FALSE, 0, 0, "Paris Stock Exchange/Boursorama, FR", "BOURSO", "bourso" },
187  { FALSE, 0, 0, "Paris Stock Exchange/LeRevenu, FR", "LEREVENU", "lerevenu" },
188  { FALSE, 0, 0, "Platinum Asset Management, AU", "PLATINUM", "platinum" },
189  { FALSE, 0, 0, "Skandinaviska Enskilda Banken, SE", "SEB_FUNDS", "seb_funds" },
190  { FALSE, 0, 0, "Sharenet, ZA", "ZA", "za" },
191  { FALSE, 0, 0, "StockHouse Canada", "STOCKHOUSE_FUND", "stockhousecanada_fund" },
192  { FALSE, 0, 0, "TD Waterhouse Canada", "TDWATERHOUSE", "tdwaterhouse" },
193  { FALSE, 0, 0, "TD Efunds, CA", "TDEFUNDS", "tdefunds" },
194  { FALSE, 0, 0, "TIAA-CREF, US", "TIAACREF", "tiaacref" },
195  { FALSE, 0, 0, "Toronto Stock eXchange, CA", "TSX", "tsx" },
196  { FALSE, 0, 0, "T. Rowe Price, US", "TRPRICE_DIRECT", "troweprice_direct" },
197  { FALSE, 0, 0, "Trustnet, GB", "TRUSTNET", "trustnet" },
198  { FALSE, 0, 0, "Union Investment, DE", "UNIONFUNDS", "unionfunds" },
199  { FALSE, 0, 0, "US Treasury Bonds", "usfedbonds", "usfedbonds" },
200  { FALSE, 0, 0, "US Govt. Thrift Savings Plan", "TSP", "tsp" },
201  { FALSE, 0, 0, "Vanguard", "VANGUARD", "vanguard" }, /* No module seen in F::Q 1.17. */
202  { FALSE, 0, 0, "VWD, DE (unmaintained)", "VWD", "vwd" },
203  { FALSE, 0, 0, "Yahoo USA", "YAHOO", "yahoo" },
204  { FALSE, 0, 0, "Yahoo Asia", "YAHOO_ASIA", "yahoo_asia" },
205  { FALSE, 0, 0, "Yahoo Australia", "YAHOO_AUSTRALIA", "yahoo_australia" },
206  { FALSE, 0, 0, "Yahoo Brasil", "YAHOO_BRASIL", "yahoo_brasil" },
207  { FALSE, 0, 0, "Yahoo Europe", "YAHOO_EUROPE", "yahoo_europe" },
208  { FALSE, 0, 0, "Yahoo New Zealand", "YAHOO_NZ", "yahoo_nz" },
209  { FALSE, 0, 0, "Zuerich Investments (outdated)", "ZIFUNDS", "zifunds" }, /* Removed from F::Q 1.11. */
210 };
211 static gnc_quote_source multiple_quote_sources[] =
212 {
213  { FALSE, 0, 0, "Asia (Yahoo, ...)", "ASIA", "asia" },
214  { FALSE, 0, 0, "Australia (ASX, Yahoo, ...)", "AUSTRALIA", "australia" },
215  { FALSE, 0, 0, "Brasil (Yahoo, ...)", "BRASIL", "brasil" },
216  { FALSE, 0, 0, "Canada (Yahoo, ...)", "CANADA", "canada" },
217  { FALSE, 0, 0, "Canada Mutual (Fund Library, ...)", "CANADAMUTUAL", "canadamutual" },
218  { FALSE, 0, 0, "Dutch (AEX, ...)", "DUTCH", "dutch" },
219  { FALSE, 0, 0, "Europe (Yahoo, ...)", "EUROPE", "europe" },
220  { FALSE, 0, 0, "Greece (ASE, ...)", "GREECE", "greece" },
221  { FALSE, 0, 0, "India Mutual (AMFI, ...)", "INDIAMUTUAL", "indiamutual" },
222  { FALSE, 0, 0, "Fidelity (Fidelity, ...)", "FIDELITY", "fidelity" },
223  { FALSE, 0, 0, "Finland (HEX, ...)", "FINLAND", "finland" },
224  { FALSE, 0, 0, "First Trust (First Trust, ...)", "FTPORTFOLIOS", "ftportfolios" },
225  { FALSE, 0, 0, "France (Boursorama, ...)", "FRANCE", "france" },
226  { FALSE, 0, 0, "Nasdaq (Yahoo, ...)", "NASDAQ", "nasdaq" },
227  { FALSE, 0, 0, "New Zealand (Yahoo, ...)", "NZ", "nz" },
228  { FALSE, 0, 0, "NYSE (Yahoo, ...)", "NYSE", "nyse" },
229  /* { FALSE, 0, 0, "South Africa (Sharenet, ...)", "ZA", "za" }, */
230  { FALSE, 0, 0, "T. Rowe Price", "TRPRICE", "troweprice" },
231  { FALSE, 0, 0, "U.K. Unit Trusts", "UKUNITTRUSTS", "uk_unit_trusts" },
232  { FALSE, 0, 0, "USA (Yahoo, Fool ...)", "USA", "usa" },
233 };
234 
235 static const int num_single_quote_sources =
236  sizeof(single_quote_sources) / sizeof(gnc_quote_source);
237 static const int num_multiple_quote_sources =
238  sizeof(multiple_quote_sources) / sizeof(gnc_quote_source);
239 static GList *new_quote_sources = NULL;
240 
241 
242 /********************************************************************
243  * gnc_quote_source_fq_installed
244  *
245  * This function indicates whether or not the Finance::Quote module
246  * is installed on a users computer.
247  ********************************************************************/
248 gboolean
250 {
251  return fq_is_installed;
252 }
253 
254 /********************************************************************
255  * gnc_quote_source_num_entries
256  *
257  * Return the number of entries for a given type of price source.
258  ********************************************************************/
260 {
261  if (type == SOURCE_CURRENCY)
262  return 1;
263 
264  if (type == SOURCE_SINGLE)
265  return num_single_quote_sources;
266 
267  if (type == SOURCE_MULTI)
268  return num_multiple_quote_sources;
269 
270  return g_list_length(new_quote_sources);
271 }
272 
273 /********************************************************************
274  * gnc_quote_source_init_tables
275  *
276  * Update the type/index values for prices sources.
277  ********************************************************************/
278 static void
279 gnc_quote_source_init_tables (void)
280 {
281  gint i;
282 
283  for (i = 0; i < num_single_quote_sources; i++)
284  {
285  single_quote_sources[i].type = SOURCE_SINGLE;
286  single_quote_sources[i].index = i;
287  }
288 
289  for (i = 0; i < num_multiple_quote_sources; i++)
290  {
291  multiple_quote_sources[i].type = SOURCE_MULTI;
292  multiple_quote_sources[i].index = i;
293  }
294 
295  currency_quote_source.type = SOURCE_CURRENCY;
296  currency_quote_source.index = 0;
297 }
298 
299 
300 /********************************************************************
301  * gnc_quote_source_add_new
302  *
303  * Add a new price source. Called when unknown source names are found
304  * either in the F::Q installation (a newly available source) or in
305  * the user's data file (a source that has vanished but needs to be
306  * tracked.)
307  ********************************************************************/
309 gnc_quote_source_add_new (const char *source_name, gboolean supported)
310 {
311  gnc_quote_source *new_source;
312 
313  DEBUG("Creating new source %s", (source_name == NULL ? "(null)" : source_name));
314  new_source = malloc(sizeof(gnc_quote_source));
315  new_source->supported = supported;
316  new_source->type = SOURCE_UNKNOWN;
317  new_source->index = g_list_length(new_quote_sources);
318 
319  /* This name can be changed if/when support for this price source is
320  * integrated into gnucash. */
321  new_source->user_name = g_strdup(source_name);
322 
323  /* This name is permanent and must be kept the same if/when support
324  * for this price source is integrated into gnucash (i.e. for a
325  * nice user name). */
326  new_source->old_internal_name = g_strdup(source_name);
327  new_source->internal_name = g_strdup(source_name);
328  new_quote_sources = g_list_append(new_quote_sources, new_source);
329  return new_source;
330 }
331 
332 /********************************************************************
333  * gnc_quote_source_lookup_by_xxx
334  *
335  * Lookup a price source data structure based upon various criteria.
336  ********************************************************************/
339 {
340  gnc_quote_source *source;
341  GList *node;
342 
343  ENTER("type/index is %d/%d", type, index);
344  switch (type)
345  {
346  case SOURCE_CURRENCY:
347  LEAVE("found %s", currency_quote_source.user_name);
348  return &currency_quote_source;
349  break;
350 
351  case SOURCE_SINGLE:
352  if (index < num_single_quote_sources)
353  {
354  LEAVE("found %s", single_quote_sources[index].user_name);
355  return &single_quote_sources[index];
356  }
357  break;
358 
359  case SOURCE_MULTI:
360  if (index < num_multiple_quote_sources)
361  {
362  LEAVE("found %s", multiple_quote_sources[index].user_name);
363  return &multiple_quote_sources[index];
364  }
365  break;
366 
367  case SOURCE_UNKNOWN:
368  default:
369  node = g_list_nth(new_quote_sources, index);
370  if (node)
371  {
372  source = node->data;
373  LEAVE("found %s", source->user_name);
374  return source;
375  }
376  break;
377  }
378 
379  LEAVE("not found");
380  return NULL;
381 }
382 
385 {
386  gnc_quote_source *source;
387  GList *node;
388  gint i;
389 
390  if ((name == NULL) || (g_strcmp0(name, "") == 0))
391  {
392  return NULL;
393  }
394 
395  if (g_strcmp0(name, currency_quote_source.internal_name) == 0)
396  return &currency_quote_source;
397  if (g_strcmp0(name, currency_quote_source.old_internal_name) == 0)
398  return &currency_quote_source;
399 
400  for (i = 0; i < num_single_quote_sources; i++)
401  {
402  if (g_strcmp0(name, single_quote_sources[i].internal_name) == 0)
403  return &single_quote_sources[i];
404  if (g_strcmp0(name, single_quote_sources[i].old_internal_name) == 0)
405  return &single_quote_sources[i];
406  }
407 
408  for (i = 0; i < num_multiple_quote_sources; i++)
409  {
410  if (g_strcmp0(name, multiple_quote_sources[i].internal_name) == 0)
411  return &multiple_quote_sources[i];
412  if (g_strcmp0(name, multiple_quote_sources[i].old_internal_name) == 0)
413  return &multiple_quote_sources[i];
414  }
415 
416  for (i = 0, node = new_quote_sources; node; node = node->next, i++)
417  {
418  source = node->data;
419  if (g_strcmp0(name, source->internal_name) == 0)
420  return source;
421  if (g_strcmp0(name, source->old_internal_name) == 0)
422  return source;
423  }
424 
425  DEBUG("gnc_quote_source_lookup_by_internal: Unknown source %s", name);
426  return NULL;
427 }
428 
429 /********************************************************************
430  * gnc_quote_source_get_xxx
431  *
432  * Accessor functions - get functions only. There are no set functions.
433  ********************************************************************/
436 {
437  ENTER("%p", source);
438  if (!source)
439  {
440  LEAVE("bad source");
441  return SOURCE_SINGLE;
442  }
443 
444  LEAVE("type is %d", source->type);
445  return source->type;
446 }
447 
448 gint
450 {
451  ENTER("%p", source);
452  if (!source)
453  {
454  LEAVE("bad source");
455  return 0;
456  }
457 
458  LEAVE("index is %d", source->index);
459  return source->index;
460 }
461 
462 gboolean
464 {
465  ENTER("%p", source);
466  if (!source)
467  {
468  LEAVE("bad source");
469  return FALSE;
470  }
471 
472  LEAVE("%ssupported", source && source->supported ? "" : "not ");
473  return source->supported;
474 }
475 
476 const char *
478 {
479  ENTER("%p", source);
480  if (!source)
481  {
482  LEAVE("bad source");
483  return NULL;
484  }
485  LEAVE("user name %s", source->user_name);
486  return source->user_name;
487 }
488 
489 const char *
491 {
492  ENTER("%p", source);
493  if (!source)
494  {
495  LEAVE("bad source");
496  return NULL;
497  }
498  LEAVE("internal name %s", source->internal_name);
499  return source->internal_name;
500 }
501 
502 /********************************************************************
503  * gnc_quote_source_set_fq_installed
504  *
505  * Update gnucash internal tables on what Finance::Quote sources are
506  * installed.
507  ********************************************************************/
508 void
509 gnc_quote_source_set_fq_installed (const GList *sources_list)
510 {
511  gnc_quote_source *source;
512  char *source_name;
513  const GList *node;
514 
515  ENTER(" ");
516  fq_is_installed = TRUE;
517 
518  if (!sources_list)
519  return;
520 
521  for (node = sources_list; node; node = node->next)
522  {
523  source_name = node->data;
524 
525  source = gnc_quote_source_lookup_by_internal(source_name);
526  if (source != NULL)
527  {
528  DEBUG("Found source %s: %s", source_name, source->user_name);
529  source->supported = TRUE;
530  continue;
531  }
532 
533  gnc_quote_source_add_new(source_name, TRUE);
534  }
535  LEAVE(" ");
536 }
537 
538 /********************************************************************
539  * QoF Helpers
540  ********************************************************************/
541 
542 void
543 gnc_commodity_begin_edit (gnc_commodity *cm)
544 {
545  qof_begin_edit(&cm->inst);
546 }
547 
548 static void commit_err (QofInstance *inst, QofBackendError errcode)
549 {
550  PERR ("Failed to commit: %d", errcode);
551  gnc_engine_signal_commit_error( errcode );
552 }
553 
554 static void noop (QofInstance *inst) {}
555 
556 static void
557 comm_free(QofInstance* inst)
558 {
559  commodity_free( GNC_COMMODITY(inst) );
560 }
561 
562 void
563 gnc_commodity_commit_edit (gnc_commodity *cm)
564 {
565  if (!qof_commit_edit (QOF_INSTANCE(cm))) return;
566  qof_commit_edit_part2 (&cm->inst, commit_err, noop, comm_free);
567 }
568 
569 /********************************************************************
570  * gnc_commodity_new
571  ********************************************************************/
572 
573 static void
574 mark_commodity_dirty (gnc_commodity *cm)
575 {
576  qof_instance_set_dirty(&cm->inst);
577  qof_event_gen (&cm->inst, QOF_EVENT_MODIFY, NULL);
578 }
579 
580 static void
581 reset_printname(CommodityPrivate *priv)
582 {
583  g_free(priv->printname);
584  priv->printname = g_strdup_printf("%s (%s)",
585  priv->mnemonic ? priv->mnemonic : "",
586  priv->fullname ? priv->fullname : "");
587 }
588 
589 static void
590 reset_unique_name(CommodityPrivate *priv)
591 {
593 
594  g_free(priv->unique_name);
595  ns = priv->name_space;
596  priv->unique_name = g_strdup_printf("%s::%s",
597  ns ? ns->name : "",
598  priv->mnemonic ? priv->mnemonic : "");
599 }
600 
601 /* GObject Initialization */
602 G_DEFINE_TYPE(gnc_commodity, gnc_commodity, QOF_TYPE_INSTANCE);
603 
604 static void
605 gnc_commodity_init(gnc_commodity* com)
606 {
607  CommodityPrivate* priv;
608 
609  priv = GET_PRIVATE(com);
610 
611  priv->name_space = NULL;
612  priv->fullname = CACHE_INSERT("");
613  priv->mnemonic = CACHE_INSERT("");
614  priv->cusip = CACHE_INSERT("");
615  priv->fraction = 10000;
616  priv->quote_flag = 0;
617  priv->quote_source = NULL;
618  priv->quote_tz = CACHE_INSERT("");
619 
620  reset_printname(priv);
621  reset_unique_name(priv);
622 }
623 
624 static void
625 gnc_commodity_dispose(GObject *comp)
626 {
627  G_OBJECT_CLASS(gnc_commodity_parent_class)->dispose(comp);
628 }
629 
630 static void
631 gnc_commodity_finalize(GObject* comp)
632 {
633  G_OBJECT_CLASS(gnc_commodity_parent_class)->finalize(comp);
634 }
635 /* Note that g_value_set_object() refs the object, as does
636  * g_object_get(). But g_object_get() only unrefs once when it disgorges
637  * the object, leaving an unbalanced ref, which leaks. So instead of
638  * using g_value_set_object(), use g_value_take_object() which doesn't
639  * ref the object when used in get_property().
640  */
641 static void
642 gnc_commodity_get_property (GObject *object,
643  guint prop_id,
644  GValue *value,
645  GParamSpec *pspec)
646 {
647  gnc_commodity *commodity;
648  CommodityPrivate* priv;
649 
650  g_return_if_fail(GNC_IS_COMMODITY(object));
651 
652  commodity = GNC_COMMODITY(object);
653  priv = GET_PRIVATE(commodity);
654  switch (prop_id)
655  {
656  case PROP_NAMESPACE:
657  g_value_take_object(value, priv->name_space);
658  break;
659  case PROP_FULL_NAME:
660  g_value_set_string(value, priv->fullname);
661  break;
662  case PROP_MNEMONIC:
663  g_value_set_string(value, priv->mnemonic);
664  break;
665  case PROP_PRINTNAME:
666  g_value_set_string(value, priv->printname);
667  break;
668  case PROP_CUSIP:
669  g_value_set_string(value, priv->cusip);
670  break;
671  case PROP_FRACTION:
672  g_value_set_int(value, priv->fraction);
673  break;
674  case PROP_UNIQUE_NAME:
675  g_value_set_string(value, priv->unique_name);
676  break;
677  case PROP_QUOTE_FLAG:
678  g_value_set_boolean(value, priv->quote_flag);
679  break;
680  case PROP_QUOTE_SOURCE:
681  g_value_set_pointer(value, priv->quote_source);
682  break;
683  case PROP_QUOTE_TZ:
684  g_value_set_string(value, priv->quote_tz);
685  break;
686  default:
687  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
688  break;
689  }
690 }
691 
692 static void
693 gnc_commodity_set_property (GObject *object,
694  guint prop_id,
695  const GValue *value,
696  GParamSpec *pspec)
697 {
698  gnc_commodity *commodity;
699 
700  g_return_if_fail(GNC_IS_COMMODITY(object));
701 
702  commodity = GNC_COMMODITY(object);
703  g_assert (qof_instance_get_editlevel(commodity));
704 
705  switch (prop_id)
706  {
707  case PROP_NAMESPACE:
708  gnc_commodity_set_namespace(commodity, g_value_get_object(value));
709  break;
710  case PROP_FULL_NAME:
711  gnc_commodity_set_fullname(commodity, g_value_get_string(value));
712  break;
713  case PROP_MNEMONIC:
714  gnc_commodity_set_mnemonic(commodity, g_value_get_string(value));
715  break;
716  case PROP_CUSIP:
717  gnc_commodity_set_cusip(commodity, g_value_get_string(value));
718  break;
719  case PROP_FRACTION:
720  gnc_commodity_set_fraction(commodity, g_value_get_int(value));
721  break;
722  case PROP_QUOTE_FLAG:
723  gnc_commodity_set_quote_flag(commodity, g_value_get_boolean(value));
724  break;
725  case PROP_QUOTE_SOURCE:
726  gnc_commodity_set_quote_source(commodity, g_value_get_pointer(value));
727  break;
728  case PROP_QUOTE_TZ:
729  gnc_commodity_set_quote_tz(commodity, g_value_get_string(value));
730  break;
731  default:
732  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
733  break;
734  }
735 }
736 static void
737 gnc_commodity_class_init(struct _GncCommodityClass* klass)
738 {
739  GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
740 
741  gobject_class->dispose = gnc_commodity_dispose;
742  gobject_class->finalize = gnc_commodity_finalize;
743  gobject_class->set_property = gnc_commodity_set_property;
744  gobject_class->get_property = gnc_commodity_get_property;
745 
746  g_type_class_add_private(klass, sizeof(CommodityPrivate));
747 
748  g_object_class_install_property(gobject_class,
749  PROP_NAMESPACE,
750  g_param_spec_object ("namespace",
751  "Namespace",
752  "The namespace field denotes the "
753  "namespace for this commodity, either "
754  "a currency or symbol from a quote source.",
755  GNC_TYPE_COMMODITY_NAMESPACE,
756  G_PARAM_READWRITE));
757  g_object_class_install_property(gobject_class,
758  PROP_FULL_NAME,
759  g_param_spec_string ("fullname",
760  "Full Commodity Name",
761  "The fullname is the official full name of"
762  "the currency.",
763  NULL,
764  G_PARAM_READWRITE));
765  g_object_class_install_property(gobject_class,
766  PROP_MNEMONIC,
767  g_param_spec_string ("mnemonic",
768  "Commodity Mnemonic",
769  "The mnemonic is the official abbreviated"
770  "designation for the currency.",
771  NULL,
772  G_PARAM_READWRITE));
773  g_object_class_install_property(gobject_class,
774  PROP_PRINTNAME,
775  g_param_spec_string ("printname",
776  "Commodity Print Name",
777  "Printable form of the commodity name.",
778  NULL,
779  G_PARAM_READABLE));
780  g_object_class_install_property(gobject_class,
781  PROP_CUSIP,
782  g_param_spec_string ("cusip",
783  "Commodity CUSIP Code",
784  "?????",
785  NULL,
786  G_PARAM_READWRITE));
787  g_object_class_install_property(gobject_class,
788  PROP_FRACTION,
789  g_param_spec_int ("fraction",
790  "Fraction",
791  "The fraction is the number of sub-units that "
792  "the basic commodity can be divided into.",
793  1,
794  1000000,
795  1,
796  G_PARAM_READWRITE));
797  g_object_class_install_property(gobject_class,
798  PROP_UNIQUE_NAME,
799  g_param_spec_string ("unique-name",
800  "Commodity Unique Name",
801  "Unique form of the commodity name which combines "
802  "the namespace name and the commodity name.",
803  NULL,
804  G_PARAM_READABLE));
805  g_object_class_install_property(gobject_class,
806  PROP_QUOTE_FLAG,
807  g_param_spec_boolean ("quote_flag",
808  "Quote Flag",
809  "TRUE if prices are to be downloaded for this "
810  "commodity from a quote source.",
811  FALSE,
812  G_PARAM_READWRITE));
813  g_object_class_install_property(gobject_class,
814  PROP_QUOTE_SOURCE,
815  g_param_spec_pointer("quote-source",
816  "Quote Source",
817  "The quote source from which prices are downloaded.",
818  G_PARAM_READWRITE));
819  g_object_class_install_property(gobject_class,
820  PROP_QUOTE_TZ,
821  g_param_spec_string ("quote-tz",
822  "Commodity Quote Timezone",
823  "?????",
824  NULL,
825  G_PARAM_READWRITE));
826 }
827 
829 gnc_commodity_new(QofBook *book, const char * fullname,
830  const char * name_space, const char * mnemonic,
831  const char * cusip, int fraction)
832 {
833  gnc_commodity * retval = g_object_new(GNC_TYPE_COMMODITY, NULL);
834 
835  qof_instance_init_data (&retval->inst, GNC_ID_COMMODITY, book);
836  gnc_commodity_begin_edit(retval);
837 
838  if ( name_space != NULL )
839  {
840  /* Prevent setting anything except template in namespace template. */
841  if (g_strcmp0 (name_space, "template") == 0 &&
842  g_strcmp0 (mnemonic, "template") != 0)
843  {
844  PWARN("Converting commodity %s from namespace template to "
845  "namespace User", mnemonic);
846  name_space = "User";
847  }
848  gnc_commodity_set_namespace(retval, name_space);
849  if (gnc_commodity_namespace_is_iso(name_space))
850  {
853  }
854  }
855  gnc_commodity_set_fullname(retval, fullname);
856  gnc_commodity_set_mnemonic(retval, mnemonic);
857  gnc_commodity_set_cusip(retval, cusip);
858  gnc_commodity_set_fraction(retval, fraction);
859  mark_commodity_dirty (retval);
860  gnc_commodity_commit_edit(retval);
861 
862  qof_event_gen (&retval->inst, QOF_EVENT_CREATE, NULL);
863 
864  return retval;
865 }
866 
867 
868 /********************************************************************
869  * gnc_commodity_destroy
870  ********************************************************************/
871 
872 static void
873 commodity_free(gnc_commodity * cm)
874 {
875  QofBook *book;
877  CommodityPrivate* priv;
878 
879  if (!cm) return;
880 
881  book = qof_instance_get_book(&cm->inst);
882  table = gnc_commodity_table_get_table(book);
883  gnc_commodity_table_remove(table, cm);
884  priv = GET_PRIVATE(cm);
885 
886  qof_event_gen (&cm->inst, QOF_EVENT_DESTROY, NULL);
887 
888  /* Set at creation */
889  CACHE_REMOVE (priv->fullname);
890  CACHE_REMOVE (priv->cusip);
891  CACHE_REMOVE (priv->mnemonic);
892  CACHE_REMOVE (priv->quote_tz);
893  priv->name_space = NULL;
894 
895  /* Set through accessor functions */
896  priv->quote_source = NULL;
897 
898  /* Automatically generated */
899  g_free(priv->printname);
900  priv->printname = NULL;
901 
902  g_free(priv->unique_name);
903  priv->unique_name = NULL;
904 
905 #ifdef ACCOUNTS_CLEANED_UP
906  /* Account objects are not actually cleaned up when a book is closed (in fact
907  * a memory leak), but commodities are, so in currently this warning gets hit
908  * quite frequently. Disable the check until cleaning up of accounts objects
909  * on close is implemented. */
910  if (priv->usage_count != 0)
911  {
912  PWARN("Destroying commodity (%p) with non-zero usage_count (%d).", cm,
913  priv->usage_count);
914  }
915 #endif
916 
917  /* qof_instance_release (&cm->inst); */
918  g_object_unref(cm);
919 }
920 
921 void
923 {
924  gnc_commodity_begin_edit(cm);
925  qof_instance_set_destroying(cm, TRUE);
926  gnc_commodity_commit_edit(cm);
927 }
928 
929 void
931 {
932  CommodityPrivate* src_priv = GET_PRIVATE(src);
933  CommodityPrivate* dest_priv = GET_PRIVATE(dest);
934 
935  gnc_commodity_set_fullname (dest, src_priv->fullname);
936  gnc_commodity_set_mnemonic (dest, src_priv->mnemonic);
937  dest_priv->name_space = src_priv->name_space;
938  gnc_commodity_set_fraction (dest, src_priv->fraction);
939  gnc_commodity_set_cusip (dest, src_priv->cusip);
940  gnc_commodity_set_quote_flag (dest, src_priv->quote_flag);
942  gnc_commodity_set_quote_tz (dest, src_priv->quote_tz);
943  kvp_frame_delete (dest->inst.kvp_data);
944  dest->inst.kvp_data = kvp_frame_copy (src->inst.kvp_data);
945 }
946 
949 {
950  CommodityPrivate* src_priv;
951  CommodityPrivate* dest_priv;
952 
953  gnc_commodity * dest = g_object_new(GNC_TYPE_COMMODITY, NULL);
954  qof_instance_init_data (&dest->inst, GNC_ID_COMMODITY, dest_book);
955  src_priv = GET_PRIVATE(src);
956  dest_priv = GET_PRIVATE(dest);
957 
958  dest_priv->fullname = CACHE_INSERT(src_priv->fullname);
959  dest_priv->mnemonic = CACHE_INSERT(src_priv->mnemonic);
960  dest_priv->cusip = CACHE_INSERT(src_priv->cusip);
961  dest_priv->quote_tz = CACHE_INSERT(src_priv->quote_tz);
962 
963  dest_priv->name_space = src_priv->name_space;
964 
965  dest_priv->fraction = src_priv->fraction;
966  dest_priv->quote_flag = src_priv->quote_flag;
967 
969 
970  kvp_frame_delete (dest->inst.kvp_data);
971  dest->inst.kvp_data = kvp_frame_copy (src->inst.kvp_data);
972 
973  reset_printname(dest_priv);
974  reset_unique_name(dest_priv);
975 
976  return dest;
977 }
978 
979 /********************************************************************
980  * gnc_commodity_get_mnemonic
981  ********************************************************************/
982 
983 const char *
985 {
986  if (!cm) return NULL;
987  return GET_PRIVATE(cm)->mnemonic;
988 }
989 
990 /********************************************************************
991  * gnc_commodity_get_printname
992  ********************************************************************/
993 
994 const char *
996 {
997  if (!cm) return NULL;
998  return GET_PRIVATE(cm)->printname;
999 }
1000 
1001 
1002 /********************************************************************
1003  * gnc_commodity_get_namespace
1004  ********************************************************************/
1005 
1006 const char *
1008 {
1009  if (!cm) return NULL;
1010  return gnc_commodity_namespace_get_name(GET_PRIVATE(cm)->name_space);
1011 }
1012 
1013 const char *
1015 {
1016  CommodityPrivate* priv;
1017 
1018  if (!cm) return NULL;
1019  priv = GET_PRIVATE(cm);
1020  if (!priv->name_space) return NULL;
1021  if (priv->name_space->iso4217)
1022  {
1023  /* Data files are still written with ISO4217. */
1024  return GNC_COMMODITY_NS_ISO;
1025  }
1026  return gnc_commodity_namespace_get_name(priv->name_space);
1027 }
1028 
1031 {
1032  if (!cm) return NULL;
1033  return GET_PRIVATE(cm)->name_space;
1034 }
1035 
1036 /********************************************************************
1037  * gnc_commodity_get_fullname
1038  ********************************************************************/
1039 
1040 const char *
1042 {
1043  if (!cm) return NULL;
1044  return GET_PRIVATE(cm)->fullname;
1045 }
1046 
1047 
1048 /********************************************************************
1049  * gnc_commodity_get_unique_name
1050  ********************************************************************/
1051 
1052 const char *
1054 {
1055  if (!cm) return NULL;
1056  return GET_PRIVATE(cm)->unique_name;
1057 }
1058 
1059 
1060 /********************************************************************
1061  * gnc_commodity_get_cusip
1062  ********************************************************************/
1063 
1064 const char *
1066 {
1067  if (!cm) return NULL;
1068  return GET_PRIVATE(cm)->cusip;
1069 }
1070 
1071 /********************************************************************
1072  * gnc_commodity_get_fraction
1073  ********************************************************************/
1074 
1075 int
1077 {
1078  if (!cm) return 0;
1079  return GET_PRIVATE(cm)->fraction;
1080 }
1081 
1082 /********************************************************************
1083  * gnc_commodity_get_auto_quote_control_flag
1084  ********************************************************************/
1085 
1086 static gboolean
1087 gnc_commodity_get_auto_quote_control_flag(const gnc_commodity *cm)
1088 {
1089  const char *str;
1090 
1091  if (!cm) return FALSE;
1092 
1093  str = kvp_frame_get_string(cm->inst.kvp_data, "auto_quote_control");
1094  return !str || (strcmp(str, "false") != 0);
1095 }
1096 
1097 /********************************************************************
1098  * gnc_commodity_get_quote_flag
1099  ********************************************************************/
1100 
1101 gboolean
1103 {
1104  if (!cm) return FALSE;
1105  return (GET_PRIVATE(cm)->quote_flag);
1106 }
1107 
1108 /********************************************************************
1109  * gnc_commodity_get_quote_source
1110  ********************************************************************/
1111 
1114 {
1115  CommodityPrivate* priv;
1116 
1117  if (!cm) return NULL;
1118  priv = GET_PRIVATE(cm);
1119  if (!priv->quote_source && gnc_commodity_is_iso(cm))
1120  return &currency_quote_source;
1121  return priv->quote_source;
1122 }
1123 
1125 gnc_commodity_get_default_quote_source(const gnc_commodity *cm)
1126 {
1127  if (cm && gnc_commodity_is_iso(cm))
1128  return &currency_quote_source;
1129  /* Should make this a user option at some point. */
1130  return gnc_quote_source_lookup_by_internal("yahoo");
1131 }
1132 
1133 /********************************************************************
1134  * gnc_commodity_get_quote_tz
1135  ********************************************************************/
1136 
1137 const char*
1139 {
1140  if (!cm) return NULL;
1141  return GET_PRIVATE(cm)->quote_tz;
1142 }
1143 
1144 /********************************************************************
1145  * gnc_commodity_get_user_symbol
1146  ********************************************************************/
1147 const char*
1149 {
1150  const char *str;
1151  if (!cm) return NULL;
1152  return kvp_frame_get_string(cm->inst.kvp_data, "user_symbol");
1153 }
1154 
1155 /********************************************************************
1156  * gnc_commodity_get_default_symbol
1157  *******************************************************************/
1158 const char*
1160 {
1161  const char *str;
1162  if (!cm) return NULL;
1163  return GET_PRIVATE(cm)->default_symbol;
1164 }
1165 
1166 /********************************************************************
1167  * gnc_commodity_get_nice_symbol
1168  *******************************************************************/
1169 const char*
1171 {
1172  const char *nice_symbol;
1173  struct lconv *lc;
1174  if (!cm) return NULL;
1175 
1176  nice_symbol = gnc_commodity_get_user_symbol(cm);
1177  if (nice_symbol && *nice_symbol)
1178  return nice_symbol;
1179 
1180  lc = gnc_localeconv();
1181  nice_symbol = lc->currency_symbol;
1182  if (!g_strcmp0(gnc_commodity_get_mnemonic(cm), lc->int_curr_symbol))
1183  return nice_symbol;
1184 
1185  nice_symbol = gnc_commodity_get_default_symbol(cm);
1186  if (nice_symbol && *nice_symbol)
1187  return nice_symbol;
1188 
1189  return gnc_commodity_get_mnemonic(cm);
1190 }
1191 
1192 /********************************************************************
1193  * gnc_commodity_set_mnemonic
1194  ********************************************************************/
1195 
1196 void
1197 gnc_commodity_set_mnemonic(gnc_commodity * cm, const char * mnemonic)
1198 {
1199  CommodityPrivate* priv;
1200 
1201  if (!cm) return;
1202  priv = GET_PRIVATE(cm);
1203  if (priv->mnemonic == mnemonic) return;
1204 
1205  gnc_commodity_begin_edit(cm);
1206  CACHE_REMOVE (priv->mnemonic);
1207  priv->mnemonic = CACHE_INSERT(mnemonic);
1208 
1209  mark_commodity_dirty (cm);
1210  reset_printname(priv);
1211  reset_unique_name(priv);
1212  gnc_commodity_commit_edit(cm);
1213 }
1214 
1215 /********************************************************************
1216  * gnc_commodity_set_namespace
1217  ********************************************************************/
1218 
1219 void
1220 gnc_commodity_set_namespace(gnc_commodity * cm, const char * name_space)
1221 {
1222  QofBook *book;
1223  gnc_commodity_table *table;
1225  CommodityPrivate* priv;
1226 
1227  if (!cm) return;
1228  priv = GET_PRIVATE(cm);
1229  book = qof_instance_get_book (&cm->inst);
1230  table = gnc_commodity_table_get_table(book);
1231  nsp = gnc_commodity_table_add_namespace(table, name_space, book);
1232  if (priv->name_space == nsp)
1233  return;
1234 
1235  gnc_commodity_begin_edit(cm);
1236  priv->name_space = nsp;
1237  if (nsp->iso4217)
1238  priv->quote_source = gnc_quote_source_lookup_by_internal("currency");
1239  mark_commodity_dirty(cm);
1240  reset_printname(priv);
1241  reset_unique_name(priv);
1242  gnc_commodity_commit_edit(cm);
1243 }
1244 
1245 /********************************************************************
1246  * gnc_commodity_set_fullname
1247  ********************************************************************/
1248 
1249 void
1250 gnc_commodity_set_fullname(gnc_commodity * cm, const char * fullname)
1251 {
1252  CommodityPrivate* priv;
1253 
1254  if (!cm) return;
1255  priv = GET_PRIVATE(cm);
1256  if (priv->fullname == fullname) return;
1257 
1258  CACHE_REMOVE (priv->fullname);
1259  priv->fullname = CACHE_INSERT (fullname);
1260 
1261  gnc_commodity_begin_edit(cm);
1262  mark_commodity_dirty(cm);
1263  reset_printname(priv);
1264  gnc_commodity_commit_edit(cm);
1265 }
1266 
1267 /********************************************************************
1268  * gnc_commodity_set_cusip
1269  ********************************************************************/
1270 
1271 void
1273  const char * cusip)
1274 {
1275  CommodityPrivate* priv;
1276 
1277  if (!cm) return;
1278 
1279  priv = GET_PRIVATE(cm);
1280  if (priv->cusip == cusip) return;
1281 
1282  gnc_commodity_begin_edit(cm);
1283  CACHE_REMOVE (priv->cusip);
1284  priv->cusip = CACHE_INSERT (cusip);
1285  mark_commodity_dirty(cm);
1286  gnc_commodity_commit_edit(cm);
1287 }
1288 
1289 /********************************************************************
1290  * gnc_commodity_set_fraction
1291  ********************************************************************/
1292 
1293 void
1295 {
1296  if (!cm) return;
1297  gnc_commodity_begin_edit(cm);
1298  GET_PRIVATE(cm)->fraction = fraction;
1299  mark_commodity_dirty(cm);
1300  gnc_commodity_commit_edit(cm);
1301 }
1302 
1303 /********************************************************************
1304  * gnc_commodity_set_auto_quote_control_flag
1305  ********************************************************************/
1306 
1307 static void
1308 gnc_commodity_set_auto_quote_control_flag(gnc_commodity *cm,
1309  const gboolean flag)
1310 {
1311  ENTER ("(cm=%p, flag=%d)", cm, flag);
1312 
1313  if (!cm)
1314  {
1315  LEAVE("");
1316  return;
1317  }
1318 
1319  gnc_commodity_begin_edit(cm);
1320  kvp_frame_set_string(cm->inst.kvp_data,
1321  "auto_quote_control", flag ? NULL : "false");
1322  mark_commodity_dirty(cm);
1323  gnc_commodity_commit_edit(cm);
1324  LEAVE("");
1325 }
1326 
1327 /********************************************************************
1328  * gnc_commodity_user_set_quote_flag
1329  ********************************************************************/
1330 
1331 void
1333 {
1334  CommodityPrivate* priv;
1335 
1336  ENTER ("(cm=%p, flag=%d)", cm, flag);
1337 
1338  if (!cm)
1339  {
1340  LEAVE("");
1341  return;
1342  }
1343 
1344  priv = GET_PRIVATE(cm);
1345  gnc_commodity_begin_edit(cm);
1346  gnc_commodity_set_quote_flag(cm, flag);
1347  if (gnc_commodity_is_iso(cm))
1348  {
1349  /* For currencies, disable auto quote control if the quote flag is being
1350  * changed from its default value and enable it if the quote flag is being
1351  * reset to its default value. The defaults for the quote flag are
1352  * disabled if no accounts are using the currency, and true otherwise.
1353  * Thus enable auto quote control if flag is FALSE and there are not any
1354  * accounts using this currency OR flag is TRUE and there are accounts
1355  * using this currency; otherwise disable auto quote control */
1356  gnc_commodity_set_auto_quote_control_flag(cm,
1357  (!flag && (priv->usage_count == 0)) || (flag && (priv->usage_count != 0)));
1358  }
1359  gnc_commodity_commit_edit(cm);
1360  LEAVE("");
1361 }
1362 
1363 /********************************************************************
1364  * gnc_commodity_set_quote_flag
1365  ********************************************************************/
1366 
1367 void
1369 {
1370  ENTER ("(cm=%p, flag=%d)", cm, flag);
1371 
1372  if (!cm) return;
1373  gnc_commodity_begin_edit(cm);
1374  GET_PRIVATE(cm)->quote_flag = flag;
1375  mark_commodity_dirty(cm);
1376  gnc_commodity_commit_edit(cm);
1377  LEAVE(" ");
1378 }
1379 
1380 /********************************************************************
1381  * gnc_commodity_set_quote_source
1382  ********************************************************************/
1383 
1384 void
1386 {
1387  ENTER ("(cm=%p, src=%p(%s))", cm, src, src ? src->internal_name : "unknown");
1388 
1389  if (!cm) return;
1390  gnc_commodity_begin_edit(cm);
1391  GET_PRIVATE(cm)->quote_source = src;
1392  mark_commodity_dirty(cm);
1393  gnc_commodity_commit_edit(cm);
1394  LEAVE(" ");
1395 }
1396 
1397 /********************************************************************
1398  * gnc_commodity_set_quote_tz
1399  ********************************************************************/
1400 
1401 void
1403 {
1404  CommodityPrivate* priv;
1405 
1406  if (!cm) return;
1407 
1408  ENTER ("(cm=%p, tz=%s)", cm, tz ? tz : "(null)");
1409 
1410  priv = GET_PRIVATE(cm);
1411 
1412  if (tz == priv->quote_tz)
1413  {
1414  LEAVE("Already correct TZ");
1415  return;
1416  }
1417 
1418  gnc_commodity_begin_edit(cm);
1419  CACHE_REMOVE (priv->quote_tz);
1420  priv->quote_tz = CACHE_INSERT (tz);
1421  mark_commodity_dirty(cm);
1422  gnc_commodity_commit_edit(cm);
1423  LEAVE(" ");
1424 }
1425 
1426 /********************************************************************
1427  * gnc_commodity_set_user_symbol
1428  ********************************************************************/
1429 
1430 void
1431 gnc_commodity_set_user_symbol(gnc_commodity * cm, const char * user_symbol)
1432 {
1433  struct lconv *lc;
1434 
1435  if (!cm) return;
1436 
1437  ENTER ("(cm=%p, symbol=%s)", cm, user_symbol ? user_symbol : "(null)");
1438 
1439  gnc_commodity_begin_edit(cm);
1440 
1441  lc = gnc_localeconv();
1442  if (!user_symbol || !*user_symbol)
1443  user_symbol = NULL;
1444  else if (!g_strcmp0(lc->int_curr_symbol, gnc_commodity_get_mnemonic(cm)) &&
1445  !g_strcmp0(lc->currency_symbol, user_symbol))
1446  /* if the user gives the ISO symbol for the locale currency or the
1447  * default symbol, actually remove the user symbol */
1448  user_symbol = NULL;
1449  else if (!g_strcmp0(user_symbol, gnc_commodity_get_default_symbol(cm)))
1450  user_symbol = NULL;
1451 
1452  kvp_frame_set_string(cm->inst.kvp_data, "user_symbol", user_symbol);
1453  mark_commodity_dirty(cm);
1454  gnc_commodity_commit_edit(cm);
1455 
1456  LEAVE(" ");
1457 }
1458 
1459 /********************************************************************
1460  * gnc_commodity_set_default_symbol
1461  * Not made visible in gnc-commodity.h, it is only called from
1462  * iso-4217-currencies.c at startup.
1463  ********************************************************************/
1464 void
1465 gnc_commodity_set_default_symbol(gnc_commodity * cm,
1466  const char * default_symbol)
1467 {
1468  GET_PRIVATE(cm)->default_symbol = default_symbol;
1469 }
1470 
1471 /********************************************************************
1472  * gnc_commodity_increment_usage_count
1473  ********************************************************************/
1474 
1475 void
1477 {
1478  CommodityPrivate* priv;
1479 
1480  ENTER("(cm=%p)", cm);
1481 
1482  if (!cm)
1483  {
1484  LEAVE("");
1485  return;
1486  }
1487 
1488  priv = GET_PRIVATE(cm);
1489 
1490  if ((priv->usage_count == 0) && !priv->quote_flag
1491  && gnc_commodity_get_auto_quote_control_flag(cm)
1492  && gnc_commodity_is_iso(cm))
1493  {
1494  /* compatability hack - Gnucash 1.8 gets currency quotes when a
1495  non-default currency is assigned to an account. */
1496  gnc_commodity_begin_edit(cm);
1497  gnc_commodity_set_quote_flag(cm, TRUE);
1499  gnc_commodity_get_default_quote_source(cm));
1500  gnc_commodity_commit_edit(cm);
1501  }
1502  priv->usage_count++;
1503  LEAVE("(usage_count=%d)", priv->usage_count);
1504 }
1505 
1506 /********************************************************************
1507  * gnc_commodity_decrement_usage_count
1508  ********************************************************************/
1509 
1510 void
1512 {
1513  CommodityPrivate* priv;
1514 
1515  ENTER("(cm=%p)", cm);
1516 
1517  if (!cm)
1518  {
1519  LEAVE("");
1520  return;
1521  }
1522 
1523  priv = GET_PRIVATE(cm);
1524 
1525  if (priv->usage_count == 0)
1526  {
1527  PWARN("usage_count already zero");
1528  LEAVE("");
1529  return;
1530  }
1531 
1532  priv->usage_count--;
1533  if ((priv->usage_count == 0) && priv->quote_flag
1534  && gnc_commodity_get_auto_quote_control_flag(cm)
1535  && gnc_commodity_is_iso(cm))
1536  {
1537  /* if this is a currency with auto quote control enabled and no more
1538  * accounts reference this currency, disable quote retrieval */
1539  gnc_commodity_set_quote_flag(cm, FALSE);
1540  }
1541  LEAVE("(usage_count=%d)", priv->usage_count);
1542 }
1543 
1544 /********************************************************************\
1545 \********************************************************************/
1546 
1547 
1548 /********************************************************************
1549  * gnc_commodity_equiv
1550  * are two commodities the same?
1551  ********************************************************************/
1552 
1553 gboolean
1555 {
1556  CommodityPrivate* priv_a;
1557  CommodityPrivate* priv_b;
1558 
1559  if (a == b) return TRUE;
1560  if (!a || !b) return FALSE;
1561 
1562  priv_a = GET_PRIVATE(a);
1563  priv_b = GET_PRIVATE(b);
1564  if (priv_a->name_space != priv_b->name_space) return FALSE;
1565  if (g_strcmp0(priv_a->mnemonic, priv_b->mnemonic) != 0) return FALSE;
1566  return TRUE;
1567 }
1568 
1569 gboolean
1571 {
1572  CommodityPrivate* priv_a;
1573  CommodityPrivate* priv_b;
1574  gboolean same_book;
1575 
1576  if (a == b) return TRUE;
1577 
1578  if (!a || !b)
1579  {
1580  DEBUG ("one is NULL");
1581  return FALSE;
1582  }
1583 
1584  priv_a = GET_PRIVATE(a);
1585  priv_b = GET_PRIVATE(b);
1586  same_book = qof_instance_get_book(QOF_INSTANCE(a)) == qof_instance_get_book(QOF_INSTANCE(b));
1587 
1588  if ((same_book && priv_a->name_space != priv_b->name_space)
1589  || (!same_book && g_strcmp0( gnc_commodity_namespace_get_name(priv_a->name_space),
1590  gnc_commodity_namespace_get_name(priv_b->name_space)) != 0))
1591  {
1592  DEBUG ("namespaces differ: %p(%s) vs %p(%s)",
1593  priv_a->name_space, gnc_commodity_namespace_get_name(priv_a->name_space),
1594  priv_b->name_space, gnc_commodity_namespace_get_name(priv_b->name_space));
1595  return FALSE;
1596  }
1597 
1598  if (g_strcmp0(priv_a->mnemonic, priv_b->mnemonic) != 0)
1599  {
1600  DEBUG ("mnemonics differ: %s vs %s", priv_a->mnemonic, priv_b->mnemonic);
1601  return FALSE;
1602  }
1603 
1604  if (g_strcmp0(priv_a->fullname, priv_b->fullname) != 0)
1605  {
1606  DEBUG ("fullnames differ: %s vs %s", priv_a->fullname, priv_b->fullname);
1607  return FALSE;
1608  }
1609 
1610  if (g_strcmp0(priv_a->cusip, priv_b->cusip) != 0)
1611  {
1612  DEBUG ("cusips differ: %s vs %s", priv_a->cusip, priv_b->cusip);
1613  return FALSE;
1614  }
1615 
1616  if (priv_a->fraction != priv_b->fraction)
1617  {
1618  DEBUG ("fractions differ: %d vs %d", priv_a->fraction, priv_b->fraction);
1619  return FALSE;
1620  }
1621 
1622  return TRUE;
1623 }
1624 
1626 {
1627  if (gnc_commodity_equal(a, b))
1628  {
1629  return 0;
1630  }
1631  else
1632  {
1633  return 1;
1634  }
1635 }
1636 
1637 int gnc_commodity_compare_void(const void * a, const void * b)
1638 {
1639  return gnc_commodity_compare(a, b);
1640 }
1641 
1642 /************************************************************
1643  * Namespace functions *
1644  ************************************************************/
1645 const char *
1647 {
1648  if (ns == NULL)
1649  return NULL;
1650  return ns->name;
1651 }
1652 
1653 GList *
1655 {
1656  if (!name_space)
1657  return NULL;
1658 
1659  return name_space->cm_list;
1660 }
1661 
1662 gboolean
1663 gnc_commodity_namespace_is_iso(const char *name_space)
1664 {
1665  return ((g_strcmp0(name_space, GNC_COMMODITY_NS_ISO) == 0) ||
1666  (g_strcmp0(name_space, GNC_COMMODITY_NS_CURRENCY) == 0));
1667 }
1668 
1669 static const gchar *
1670 gnc_commodity_table_map_namespace(const char * name_space)
1671 {
1672  if (g_strcmp0(name_space, GNC_COMMODITY_NS_ISO) == 0)
1673  return GNC_COMMODITY_NS_CURRENCY;
1674  return name_space;
1675 }
1676 
1677 /********************************************************************
1678  * gnc_commodity_table_new
1679  * make a new commodity table
1680  ********************************************************************/
1681 
1684 {
1685  gnc_commodity_table * retval = g_new0(gnc_commodity_table, 1);
1686  retval->ns_table = g_hash_table_new(&g_str_hash, &g_str_equal);
1687  retval->ns_list = NULL;
1688  return retval;
1689 }
1690 
1691 /********************************************************************
1692  * book anchor functons
1693  ********************************************************************/
1694 
1697 {
1698  if (!book) return NULL;
1699  return qof_book_get_data (book, GNC_COMMODITY_TABLE);
1700 }
1701 
1702 gnc_commodity *
1704 {
1705  gnc_commodity *twin;
1706  const char * ucom;
1707  gnc_commodity_table * comtbl;
1708 
1709  if (!from) return NULL;
1710  comtbl = gnc_commodity_table_get_table (book);
1711  if (!comtbl) return NULL;
1712 
1713  ucom = gnc_commodity_get_unique_name (from);
1714  twin = gnc_commodity_table_lookup_unique (comtbl, ucom);
1715  if (!twin)
1716  {
1717  twin = gnc_commodity_clone (from, book);
1718  twin = gnc_commodity_table_insert (comtbl, twin);
1719  }
1720  return twin;
1721 }
1722 
1723 /********************************************************************
1724  * gnc_commodity_table_get_size
1725  * get the size of the commodity table
1726  ********************************************************************/
1727 
1728 static void
1729 count_coms(gpointer key, gpointer value, gpointer user_data)
1730 {
1731  GHashTable *tbl = ((gnc_commodity_namespace*)value)->cm_table;
1732  guint *count = (guint*)user_data;
1733 
1734  if (g_strcmp0((char*)key, GNC_COMMODITY_NS_CURRENCY) == 0)
1735  {
1736  /* don't count default commodities */
1737  return;
1738  }
1739 
1740  if (!value) return;
1741 
1742  *count += g_hash_table_size(tbl);
1743 }
1744 
1745 guint
1747 {
1748  guint count = 0;
1749  g_return_val_if_fail(tbl, 0);
1750  g_return_val_if_fail(tbl->ns_table, 0);
1751 
1752  g_hash_table_foreach(tbl->ns_table, count_coms, (gpointer)&count);
1753 
1754  return count;
1755 }
1756 
1757 /********************************************************************
1758  * gnc_commodity_table_lookup
1759  * locate a commodity by namespace and mnemonic.
1760  ********************************************************************/
1761 
1762 gnc_commodity *
1763 gnc_commodity_table_lookup(const gnc_commodity_table * table,
1764  const char * name_space, const char * mnemonic)
1765 {
1766  gnc_commodity_namespace * nsp = NULL;
1767  unsigned int i;
1768 
1769  if (!table || !name_space || !mnemonic) return NULL;
1770 
1771  nsp = gnc_commodity_table_find_namespace(table, name_space);
1772 
1773  if (nsp)
1774  {
1775  /*
1776  * Backward compatability support for currencies that have
1777  * recently changed.
1778  */
1779  if (nsp->iso4217)
1780  {
1781  for (i = 0; i < GNC_NEW_ISO_CODES; i++)
1782  {
1783  if (strcmp(mnemonic, gnc_new_iso_codes[i].old_code) == 0)
1784  {
1785  mnemonic = gnc_new_iso_codes[i].new_code;
1786  break;
1787  }
1788  }
1789  }
1790  return g_hash_table_lookup(nsp->cm_table, (gpointer)mnemonic);
1791  }
1792  else
1793  {
1794  return NULL;
1795  }
1796 }
1797 
1798 /********************************************************************
1799  * gnc_commodity_table_lookup
1800  * locate a commodity by unique name.
1801  ********************************************************************/
1802 
1803 gnc_commodity *
1804 gnc_commodity_table_lookup_unique(const gnc_commodity_table *table,
1805  const char * unique_name)
1806 {
1807  char *name_space;
1808  char *mnemonic;
1809  gnc_commodity *commodity;
1810 
1811  if (!table || !unique_name) return NULL;
1812 
1813  name_space = g_strdup (unique_name);
1814  mnemonic = strstr (name_space, "::");
1815  if (!mnemonic)
1816  {
1817  g_free (name_space);
1818  return NULL;
1819  }
1820 
1821  *mnemonic = '\0';
1822  mnemonic += 2;
1823 
1824  commodity = gnc_commodity_table_lookup (table, name_space, mnemonic);
1825 
1826  g_free (name_space);
1827 
1828  return commodity;
1829 }
1830 
1831 /********************************************************************
1832  * gnc_commodity_table_find_full
1833  * locate a commodity by namespace and printable name
1834  ********************************************************************/
1835 
1836 gnc_commodity *
1837 gnc_commodity_table_find_full(const gnc_commodity_table * table,
1838  const char * name_space,
1839  const char * fullname)
1840 {
1841  gnc_commodity * retval = NULL;
1842  GList * all;
1843  GList * iterator;
1844 
1845  if (!fullname || (fullname[0] == '\0'))
1846  return NULL;
1847 
1848  all = gnc_commodity_table_get_commodities(table, name_space);
1849 
1850  for (iterator = all; iterator; iterator = iterator->next)
1851  {
1852  if (!strcmp(fullname,
1853  gnc_commodity_get_printname(iterator->data)))
1854  {
1855  retval = iterator->data;
1856  break;
1857  }
1858  }
1859 
1860  g_list_free (all);
1861 
1862  return retval;
1863 }
1864 
1865 
1866 /********************************************************************
1867  * gnc_commodity_table_insert
1868  * add a commodity to the table.
1869  ********************************************************************/
1870 
1871 gnc_commodity *
1873  gnc_commodity * comm)
1874 {
1875  gnc_commodity_namespace * nsp = NULL;
1876  gnc_commodity *c;
1877  const char *ns_name;
1878  CommodityPrivate* priv;
1879  QofBook *book;
1880 
1881  if (!table) return NULL;
1882  if (!comm) return NULL;
1883 
1884  priv = GET_PRIVATE(comm);
1885 
1886  ENTER ("(table=%p, comm=%p) %s %s", table, comm,
1887  (priv->mnemonic == NULL ? "(null)" : priv->mnemonic),
1888  (priv->fullname == NULL ? "(null)" : priv->fullname));
1889  ns_name = gnc_commodity_namespace_get_name(priv->name_space);
1890  c = gnc_commodity_table_lookup (table, ns_name, priv->mnemonic);
1891 
1892  if (c)
1893  {
1894  if (c == comm)
1895  {
1896  LEAVE("already in table");
1897  return c;
1898  }
1899 
1900  /* Backward compatability support for currencies that have
1901  * recently changed. */
1902  if (priv->name_space->iso4217)
1903  {
1904  guint i;
1905  for (i = 0; i < GNC_NEW_ISO_CODES; i++)
1906  {
1907  if (!priv->mnemonic
1908  || !strcmp(priv->mnemonic, gnc_new_iso_codes[i].old_code))
1909  {
1910  gnc_commodity_set_mnemonic(comm, gnc_new_iso_codes[i].new_code);
1911  break;
1912  }
1913  }
1914  }
1915  gnc_commodity_copy (c, comm);
1916  gnc_commodity_destroy (comm);
1917  LEAVE("found at %p", c);
1918  return c;
1919  }
1920 
1921  /* Prevent setting anything except template in namespace template. */
1922  if (g_strcmp0 (ns_name, "template") == 0 &&
1923  g_strcmp0 (priv->mnemonic, "template") != 0)
1924  {
1925  PWARN("Converting commodity %s from namespace template to "
1926  "namespace User", priv->mnemonic);
1927  gnc_commodity_set_namespace (comm, "User");
1928  ns_name = "User";
1929  mark_commodity_dirty (comm);
1930  }
1931 
1932  book = qof_instance_get_book (&comm->inst);
1933  nsp = gnc_commodity_table_add_namespace(table, ns_name, book);
1934 
1935  PINFO ("insert %p %s into nsp=%p %s", priv->mnemonic, priv->mnemonic,
1936  nsp->cm_table, nsp->name);
1937  g_hash_table_insert(nsp->cm_table,
1938  CACHE_INSERT(priv->mnemonic),
1939  (gpointer)comm);
1940  nsp->cm_list = g_list_append(nsp->cm_list, comm);
1941 
1942  qof_event_gen (&comm->inst, QOF_EVENT_ADD, NULL);
1943  LEAVE ("(table=%p, comm=%p)", table, comm);
1944  return comm;
1945 }
1946 
1947 /********************************************************************
1948  * gnc_commodity_table_remove
1949  * remove a commodity from the table.
1950  ********************************************************************/
1951 
1952 void
1954  gnc_commodity * comm)
1955 {
1957  gnc_commodity *c;
1958  CommodityPrivate* priv;
1959  const char *ns_name;
1960 
1961  if (!table) return;
1962  if (!comm) return;
1963 
1964  priv = GET_PRIVATE(comm);
1965  ns_name = gnc_commodity_namespace_get_name(priv->name_space);
1966  c = gnc_commodity_table_lookup (table, ns_name, priv->mnemonic);
1967  if (c != comm) return;
1968 
1969  qof_event_gen (&comm->inst, QOF_EVENT_REMOVE, NULL);
1970 
1971  nsp = gnc_commodity_table_find_namespace(table, ns_name);
1972  if (!nsp) return;
1973 
1974  nsp->cm_list = g_list_remove(nsp->cm_list, comm);
1975  g_hash_table_remove (nsp->cm_table, priv->mnemonic);
1976  /* XXX minor mem leak, should remove the key as well */
1977 }
1978 
1979 /********************************************************************
1980  * gnc_commodity_table_has_namespace
1981  * see if the commodities namespace exists. May have zero commodities.
1982  ********************************************************************/
1983 
1984 int
1986  const char * name_space)
1987 {
1988  gnc_commodity_namespace * nsp = NULL;
1989 
1990  if (!table || !name_space)
1991  {
1992  return 0;
1993  }
1994 
1995  nsp = gnc_commodity_table_find_namespace(table, name_space);
1996  if (nsp)
1997  {
1998  return 1;
1999  }
2000  else
2001  {
2002  return 0;
2003  }
2004 }
2005 
2006 static void
2007 hash_keys_helper(gpointer key, gpointer value, gpointer data)
2008 {
2009  GList ** l = data;
2010  *l = g_list_prepend(*l, key);
2011 }
2012 
2013 static GList *
2014 g_hash_table_keys(GHashTable * table)
2015 {
2016  GList * l = NULL;
2017  g_hash_table_foreach(table, &hash_keys_helper, (gpointer) &l);
2018  return l;
2019 }
2020 
2021 static void
2022 hash_values_helper(gpointer key, gpointer value, gpointer data)
2023 {
2024  GList ** l = data;
2025  *l = g_list_prepend(*l, value);
2026 }
2027 
2028 static GList *
2029 g_hash_table_values(GHashTable * table)
2030 {
2031  GList * l = NULL;
2032  g_hash_table_foreach(table, &hash_values_helper, (gpointer) &l);
2033  return l;
2034 }
2035 
2036 /********************************************************************
2037  * gnc_commodity_table_get_namespaces
2038  * see if any commodities in the namespace exist
2039  ********************************************************************/
2040 
2041 GList *
2043 {
2044  if (!table)
2045  return NULL;
2046 
2047  return g_hash_table_keys(table->ns_table);
2048 }
2049 
2050 GList *
2052 {
2053  if (!table)
2054  return NULL;
2055 
2056  return table->ns_list;
2057 }
2058 
2059 /* Because gnc_commodity_table_add_namespace maps GNC_COMMODITY_NS_ISO to
2060  GNC_COMMODITY_NS_CURRENCY and then sets iso4217 if the namespace is
2061  either of these, the net result is that the iso4217 bit is set only
2062  for GNC_COMMODITY_NS_CURRENCY. This means that gnc_commodity_is_iso is
2063  a subset of gnc_commodity_is_currency. Most callers seem to use
2064  gnc_commodity_is_iso. */
2065 gboolean
2067 {
2068  CommodityPrivate* priv;
2069 
2070  if (!cm) return FALSE;
2071 
2072  priv = GET_PRIVATE(cm);
2073  if ( !priv->name_space) return FALSE;
2074  return priv->name_space->iso4217;
2075 }
2076 
2077 gboolean
2079 {
2080  const char *ns_name;
2081  if (!cm) return FALSE;
2082 
2083  ns_name = gnc_commodity_namespace_get_name(GET_PRIVATE(cm)->name_space);
2084  return (!g_strcmp0(ns_name, GNC_COMMODITY_NS_LEGACY) ||
2085  !g_strcmp0(ns_name, GNC_COMMODITY_NS_CURRENCY));
2086 }
2087 
2088 /********************************************************************
2089  * gnc_commodity_table_get_commodities
2090  * list commodities in a give namespace
2091  ********************************************************************/
2092 
2093 CommodityList *
2095  const char * name_space)
2096 {
2097  gnc_commodity_namespace * ns = NULL;
2098 
2099  if (!table)
2100  return NULL;
2101 
2102  ns = gnc_commodity_table_find_namespace(table, name_space);
2103  if (!ns)
2104  return NULL;
2105 
2106  return g_hash_table_values(ns->cm_table);
2107 }
2108 
2109 /********************************************************************
2110  * gnc_commodity_table_get_quotable_commodities
2111  * list commodities in a given namespace that get price quotes
2112  ********************************************************************/
2113 
2114 static void
2115 get_quotables_helper1(gpointer key, gpointer value, gpointer data)
2116 {
2117  gnc_commodity *comm = value;
2118  CommodityPrivate* priv = GET_PRIVATE(comm);
2119  GList ** l = data;
2120 
2121  if (!priv->quote_flag ||
2122  !priv->quote_source || !priv->quote_source->supported)
2123  return;
2124  *l = g_list_prepend(*l, value);
2125 }
2126 
2127 static gboolean
2128 get_quotables_helper2 (gnc_commodity *comm, gpointer data)
2129 {
2130  GList ** l = data;
2131  CommodityPrivate* priv = GET_PRIVATE(comm);
2132 
2133  if (!priv->quote_flag ||
2134  !priv->quote_source || !priv->quote_source->supported)
2135  return TRUE;
2136  *l = g_list_prepend(*l, comm);
2137  return TRUE;
2138 }
2139 
2140 CommodityList *
2142 {
2143  gnc_commodity_namespace * ns = NULL;
2144  const char *name_space;
2145  GList * nslist, * tmp;
2146  GList * l = NULL;
2147  regex_t pattern;
2148  const char *expression = gnc_prefs_get_namespace_regexp();
2149 
2150  ENTER("table=%p, expression=%s", table, expression);
2151  if (!table)
2152  return NULL;
2153 
2154  if (expression && *expression)
2155  {
2156  if (regcomp(&pattern, expression, REG_EXTENDED | REG_ICASE) != 0)
2157  {
2158  LEAVE("Cannot compile regex");
2159  return NULL;
2160  }
2161 
2162  nslist = gnc_commodity_table_get_namespaces(table);
2163  for (tmp = nslist; tmp; tmp = tmp->next)
2164  {
2165  name_space = tmp->data;
2166  if (regexec(&pattern, name_space, 0, NULL, 0) == 0)
2167  {
2168  DEBUG("Running list of %s commodities", name_space);
2169  ns = gnc_commodity_table_find_namespace(table, name_space);
2170  if (ns)
2171  {
2172  g_hash_table_foreach(ns->cm_table, &get_quotables_helper1, (gpointer) &l);
2173  }
2174  }
2175  }
2176  g_list_free(nslist);
2177  regfree(&pattern);
2178  }
2179  else
2180  {
2181  gnc_commodity_table_foreach_commodity(table, get_quotables_helper2,
2182  (gpointer) &l);
2183  }
2184  LEAVE("list head %p", l);
2185  return l;
2186 }
2187 
2188 /********************************************************************
2189  * gnc_commodity_table_add_namespace
2190  * add an empty namespace if it does not exist
2191  ********************************************************************/
2192 
2193 /* GObject Initialization */
2194 QOF_GOBJECT_IMPL(gnc_commodity_namespace, gnc_commodity_namespace, QOF_TYPE_INSTANCE);
2195 
2196 static void
2197 gnc_commodity_namespace_init(gnc_commodity_namespace* ns)
2198 {
2199 }
2200 
2201 static void
2202 gnc_commodity_namespace_dispose_real (GObject *nsp)
2203 {
2204 }
2205 
2206 static void
2207 gnc_commodity_namespace_finalize_real(GObject* nsp)
2208 {
2209 }
2210 
2213  const char * name_space,
2214  QofBook *book)
2215 {
2216  gnc_commodity_namespace * ns = NULL;
2217 
2218  if (!table) return NULL;
2219 
2220  name_space = gnc_commodity_table_map_namespace(name_space);
2221  ns = gnc_commodity_table_find_namespace(table, name_space);
2222  if (!ns)
2223  {
2224  ns = g_object_new(GNC_TYPE_COMMODITY_NAMESPACE, NULL);
2225  ns->cm_table = g_hash_table_new(g_str_hash, g_str_equal);
2226  ns->name = CACHE_INSERT((gpointer)name_space);
2227  ns->iso4217 = gnc_commodity_namespace_is_iso(name_space);
2228  qof_instance_init_data (&ns->inst, GNC_ID_COMMODITY_NAMESPACE, book);
2229  qof_event_gen (&ns->inst, QOF_EVENT_CREATE, NULL);
2230 
2231  g_hash_table_insert(table->ns_table,
2232  (gpointer) ns->name,
2233  (gpointer) ns);
2234  table->ns_list = g_list_append(table->ns_list, ns);
2235  qof_event_gen (&ns->inst, QOF_EVENT_ADD, NULL);
2236  }
2237  return ns;
2238 }
2239 
2240 
2243  const char * name_space)
2244 {
2245  if (!table || !name_space)
2246  return NULL;
2247 
2248  name_space = gnc_commodity_table_map_namespace(name_space);
2249  return g_hash_table_lookup(table->ns_table, (gpointer)name_space);
2250 }
2251 
2252 
2253 gnc_commodity *
2254 gnc_commodity_find_commodity_by_guid(const GncGUID *guid, QofBook *book)
2255 {
2256  QofCollection *col;
2257  if (!guid || !book) return NULL;
2258  col = qof_book_get_collection (book, GNC_ID_COMMODITY);
2259  return (gnc_commodity *) qof_collection_lookup_entity (col, guid);
2260 }
2261 
2262 /********************************************************************
2263  * gnc_commodity_table_delete_namespace
2264  * delete a namespace
2265  ********************************************************************/
2266 
2267 static int
2268 ns_helper(gpointer key, gpointer value, gpointer user_data)
2269 {
2270  gnc_commodity * c = value;
2272  CACHE_REMOVE(key); /* key is commodity mnemonic */
2273  return TRUE;
2274 }
2275 
2276 void
2278  const char * name_space)
2279 {
2281 
2282  if (!table) return;
2283 
2284  ns = gnc_commodity_table_find_namespace(table, name_space);
2285  if (!ns)
2286  return;
2287 
2288  qof_event_gen (&ns->inst, QOF_EVENT_REMOVE, NULL);
2289  g_hash_table_remove(table->ns_table, name_space);
2290  table->ns_list = g_list_remove(table->ns_list, ns);
2291 
2292  g_list_free(ns->cm_list);
2293  ns->cm_list = NULL;
2294 
2295  g_hash_table_foreach_remove(ns->cm_table, ns_helper, NULL);
2296  g_hash_table_destroy(ns->cm_table);
2297  CACHE_REMOVE(ns->name);
2298 
2299  qof_event_gen (&ns->inst, QOF_EVENT_DESTROY, NULL);
2300  /* qof_instance_release(&ns->inst); */
2301  g_object_unref(ns);
2302 }
2303 
2304 /********************************************************************
2305  * gnc_commodity_table_foreach_commodity
2306  * call user-defined function once for every commodity in every
2307  * namespace
2308  ********************************************************************/
2309 
2310 typedef struct
2311 {
2312  gboolean ok;
2313  gboolean (*func)(gnc_commodity *, gpointer);
2314  gpointer user_data;
2315 } IterData;
2316 
2317 static void
2318 iter_commodity (gpointer key, gpointer value, gpointer user_data)
2319 {
2320  IterData *iter_data = (IterData *) user_data;
2321  gnc_commodity *cm = (gnc_commodity *) value;
2322 
2323  if (iter_data->ok)
2324  {
2325  iter_data->ok = (iter_data->func)(cm, iter_data->user_data);
2326  }
2327 }
2328 
2329 static void
2330 iter_namespace (gpointer key, gpointer value, gpointer user_data)
2331 {
2332  GHashTable *namespace_hash = ((gnc_commodity_namespace *) value)->cm_table;
2333  g_hash_table_foreach (namespace_hash, iter_commodity, user_data);
2334 }
2335 
2336 gboolean
2338  gboolean (*f)(gnc_commodity *, gpointer),
2339  gpointer user_data)
2340 {
2341  IterData iter_data;
2342 
2343  if (!tbl || !f) return FALSE;
2344 
2345  iter_data.ok = TRUE;
2346  iter_data.func = f;
2347  iter_data.user_data = user_data;
2348 
2349  g_hash_table_foreach(tbl->ns_table, iter_namespace, (gpointer)&iter_data);
2350 
2351  return iter_data.ok;
2352 }
2353 
2354 /********************************************************************
2355  * gnc_commodity_table_destroy
2356  * cleanup and free.
2357  ********************************************************************/
2358 
2359 void
2360 gnc_commodity_table_destroy(gnc_commodity_table * t)
2361 {
2363  GList *item, *next;
2364 
2365  if (!t) return;
2366  ENTER ("table=%p", t);
2367 
2368  for (item = t->ns_list; item; item = next)
2369  {
2370  next = g_list_next(item);
2371  ns = item->data;
2373  }
2374 
2375  g_list_free(t->ns_list);
2376  t->ns_list = NULL;
2377  g_hash_table_destroy(t->ns_table);
2378  t->ns_table = NULL;
2379  g_free(t);
2380  LEAVE ("table=%p", t);
2381 }
2382 
2383 /* =========================================================== */
2384 
2385 /********************************************************************
2386  * gnc_commodity_table_add_default_data
2387  ********************************************************************/
2388 
2389 #define CUR_I18N(String) dgettext ("iso_4217", String)
2390 
2391 gboolean
2393 {
2394  QofCollection *col;
2395  gnc_commodity* c;
2396 
2397  ENTER ("table=%p", table);
2398  gnc_commodity_table_add_namespace(table, GNC_COMMODITY_NS_AMEX, book);
2399  gnc_commodity_table_add_namespace(table, GNC_COMMODITY_NS_NYSE, book);
2400  gnc_commodity_table_add_namespace(table, GNC_COMMODITY_NS_NASDAQ, book);
2401  gnc_commodity_table_add_namespace(table, GNC_COMMODITY_NS_EUREX, book);
2402  gnc_commodity_table_add_namespace(table, GNC_COMMODITY_NS_MUTUAL, book);
2403  gnc_commodity_table_add_namespace(table, "template", book);
2404  c = gnc_commodity_new(book, "template", "template", "template", "template", 1);
2405  gnc_commodity_table_insert(table, c);
2406 
2407 #include "iso-4217-currencies.c"
2408 
2409  /* We've just created the default namespaces and currencies. Mark
2410  * these collections as clean because there is no USER entered data
2411  * in these collections as of yet. */
2412  col = qof_book_get_collection(book, GNC_ID_COMMODITY);
2414  col = qof_book_get_collection(book, GNC_ID_COMMODITY_NAMESPACE);
2416 
2417  LEAVE ("table=%p", table);
2418  return TRUE;
2419 }
2420 
2421 /********************************************************************
2422  ********************************************************************/
2423 /* QofObject function implementation and registration */
2424 
2425 #ifdef _MSC_VER
2426 /* MSVC compiler doesn't have C99 "designated initializers"
2427  * so we wrap them in a macro that is empty on MSVC. */
2428 # define DI(x) /* */
2429 #else
2430 # define DI(x) x
2431 #endif
2432 static QofObject commodity_object_def =
2433 {
2434  DI(.interface_version = ) QOF_OBJECT_VERSION,
2435  DI(.e_type = ) GNC_ID_COMMODITY,
2436  DI(.type_label = ) "Commodity",
2437  DI(.create = ) NULL,
2438  DI(.book_begin = ) NULL,
2439  DI(.book_end = ) NULL,
2440  DI(.is_dirty = ) qof_collection_is_dirty,
2441  DI(.mark_clean = ) qof_collection_mark_clean,
2442  DI(.foreach = ) qof_collection_foreach,
2443  DI(.printable = ) (const char * (*)(gpointer)) gnc_commodity_get_fullname,
2444 };
2445 
2446 static QofObject namespace_object_def =
2447 {
2448  DI(.interface_version = ) QOF_OBJECT_VERSION,
2449  DI(.e_type = ) GNC_ID_COMMODITY_NAMESPACE,
2450  DI(.type_label = ) "Namespace",
2451  DI(.create = ) NULL,
2452  DI(.book_begin = ) NULL,
2453  DI(.book_end = ) NULL,
2454  DI(.is_dirty = ) NULL,
2455  DI(.mark_clean = ) NULL,
2456  DI(.foreach = ) NULL,
2457  DI(.printable = ) NULL,
2458 };
2459 
2460 static void
2461 commodity_table_book_begin (QofBook *book)
2462 {
2463  gnc_commodity_table *ct;
2464  ENTER ("book=%p", book);
2465 
2467  return;
2468 
2469  ct = gnc_commodity_table_new ();
2470  qof_book_set_data (book, GNC_COMMODITY_TABLE, ct);
2471 
2472  if (!gnc_commodity_table_add_default_data(ct, book))
2473  {
2474  PWARN("unable to initialize book's commodity_table");
2475  }
2476 
2477  LEAVE ("book=%p", book);
2478 }
2479 
2480 static void
2481 commodity_table_book_end (QofBook *book)
2482 {
2483  gnc_commodity_table *ct;
2484 
2485  ct = gnc_commodity_table_get_table (book);
2486  qof_book_set_data (book, GNC_COMMODITY_TABLE, NULL);
2487  gnc_commodity_table_destroy (ct);
2488 }
2489 
2490 static QofObject commodity_table_object_def =
2491 {
2492  DI(.interface_version = ) QOF_OBJECT_VERSION,
2493  DI(.e_type = ) GNC_ID_COMMODITY_TABLE,
2494  DI(.type_label = ) "CommodityTable",
2495  DI(.create = ) NULL,
2496  DI(.book_begin = ) commodity_table_book_begin,
2497  DI(.book_end = ) commodity_table_book_end,
2498  DI(.is_dirty = ) qof_collection_is_dirty,
2499  DI(.mark_clean = ) qof_collection_mark_clean,
2500  DI(.foreach = ) NULL,
2501  DI(.printable = ) NULL,
2502  DI(.version_cmp = ) NULL,
2503 };
2504 
2505 gboolean
2507 {
2508  gnc_quote_source_init_tables();
2509 
2510  if (!qof_object_register (&commodity_object_def))
2511  return FALSE;
2512  if (!qof_object_register (&namespace_object_def))
2513  return FALSE;
2514  return qof_object_register (&commodity_table_object_def);
2515 }
2516 
2517 /* *******************************************************************
2518 * gnc_monetary methods
2519 ********************************************************************/
2520 
2522 MonetaryList *
2523 gnc_monetary_list_add_monetary(MonetaryList *list, gnc_monetary add_mon)
2524 {
2525  MonetaryList *l = list, *tmp;
2526  for (tmp = list; tmp; tmp = tmp->next)
2527  {
2528  gnc_monetary *list_mon = tmp->data;
2529  if (gnc_commodity_equiv(list_mon->commodity, add_mon.commodity))
2530  {
2531  list_mon->value = gnc_numeric_add(list_mon->value, add_mon.value,
2533  break;
2534  }
2535  }
2536 
2537  /* See if we found an entry, and add one if not */
2538  if (tmp == NULL)
2539  {
2540  gnc_monetary *new_mon = g_new0(gnc_monetary, 1);
2541  *new_mon = add_mon;
2542  l = g_list_prepend(l, new_mon);
2543  }
2544 
2545  return l;
2546 }
2547 
2550 MonetaryList *
2552 {
2553  MonetaryList *node, *next;
2554  for (node = list; node; node = next)
2555  {
2556  gnc_monetary *mon = node->data;
2557  next = node->next;
2558  if (gnc_numeric_zero_p(mon->value))
2559  {
2560  g_free(mon);
2561  list = g_list_delete_link(list, node);
2562  }
2563  }
2564  return list;
2565 }
2566 
2568 void
2569 gnc_monetary_list_free(MonetaryList *list)
2570 {
2571  MonetaryList *tmp;
2572  for (tmp = list; tmp; tmp = tmp->next)
2573  {
2574  g_free(tmp->data);
2575  }
2576 
2577  g_list_free(list);
2578 }
2579 
2580 /* ========================= END OF FILE ============================== */
gnc_commodity * gnc_commodity_table_insert(gnc_commodity_table *table, gnc_commodity *comm)
const char * gnc_commodity_get_cusip(const gnc_commodity *cm)
gboolean gnc_commodity_table_foreach_commodity(const gnc_commodity_table *table, gboolean(*f)(gnc_commodity *cm, gpointer user_data), gpointer user_data)
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
gboolean gnc_commodity_is_currency(const gnc_commodity *cm)
int gnc_commodity_get_fraction(const gnc_commodity *cm)
gboolean gnc_commodity_table_add_default_data(gnc_commodity_table *table, QofBook *book)
const char * gnc_quote_source_get_user_name(const gnc_quote_source *source)
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
QofBook * qof_instance_get_book(gconstpointer)
gboolean qof_collection_is_dirty(const QofCollection *col)
gnc_quote_source * gnc_quote_source_add_new(const char *source_name, gboolean supported)
QofInstance * qof_collection_lookup_entity(const QofCollection *, const GncGUID *)
#define PINFO(format, args...)
Definition: qoflog.h:249
gboolean gnc_commodity_get_quote_flag(const gnc_commodity *cm)
QofBackendError
The errors that can be reported to the GUI & other front-end users.
Definition: qofbackend.h:59
const char * gnc_commodity_get_namespace_compat(const gnc_commodity *cm)
const char * gnc_commodity_get_user_symbol(const gnc_commodity *cm)
void gnc_commodity_set_quote_tz(gnc_commodity *cm, const char *tz)
void gnc_commodity_decrement_usage_count(gnc_commodity *cm)
void gnc_quote_source_set_fq_installed(const GList *sources_list)
const char * gnc_commodity_get_quote_tz(const gnc_commodity *cm)
#define DEBUG(format, args...)
Definition: qoflog.h:255
void gnc_commodity_set_fraction(gnc_commodity *cm, int fraction)
KvpFrame * kvp_frame_copy(const KvpFrame *frame)
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
gboolean gnc_quote_source_get_supported(const gnc_quote_source *source)
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
QuoteSourceType gnc_quote_source_get_type(const gnc_quote_source *source)
int gnc_commodity_compare_void(const void *a, const void *b)
gboolean gnc_numeric_zero_p(gnc_numeric a)
gnc_commodity * gnc_commodity_clone(const gnc_commodity *src, QofBook *dest_book)
const char * gnc_commodity_get_namespace(const gnc_commodity *cm)
void gnc_commodity_set_quote_flag(gnc_commodity *cm, const gboolean flag)
#define QOF_OBJECT_VERSION
Definition: qofobject.h:64
QuoteSourceType
gnc_quote_source * gnc_quote_source_lookup_by_ti(QuoteSourceType type, gint index)
gboolean qof_commit_edit(QofInstance *inst)
#define PERR(format, args...)
Definition: qoflog.h:237
#define ENTER(format, args...)
Definition: qoflog.h:261
void gnc_commodity_user_set_quote_flag(gnc_commodity *cm, const gboolean flag)
gnc_commodity_namespace * gnc_commodity_table_add_namespace(gnc_commodity_table *table, const char *name_space, QofBook *book)
void qof_collection_foreach(const QofCollection *, QofInstanceForeachCB, gpointer user_data)
GList * gnc_commodity_namespace_get_commodity_list(const gnc_commodity_namespace *name_space)
void kvp_frame_delete(KvpFrame *frame)
void gnc_commodity_set_user_symbol(gnc_commodity *cm, const char *user_symbol)
Definition: guid.h:65
const char * gnc_commodity_namespace_get_name(const gnc_commodity_namespace *ns)
#define PWARN(format, args...)
Definition: qoflog.h:243
void qof_instance_init_data(QofInstance *, QofIdType, QofBook *)
MonetaryList * gnc_monetary_list_delete_zeros(MonetaryList *list)
gboolean qof_begin_edit(QofInstance *inst)
void gnc_commodity_set_quote_source(gnc_commodity *cm, gnc_quote_source *src)
gint gnc_quote_source_num_entries(QuoteSourceType type)
GList * gnc_commodity_table_get_namespaces(const gnc_commodity_table *table)
gboolean gnc_commodity_table_register(void)
void gnc_commodity_increment_usage_count(gnc_commodity *cm)
void gnc_commodity_set_cusip(gnc_commodity *cm, const char *cusip)
void gnc_monetary_list_free(MonetaryList *list)
gnc_commodity * gnc_commodity_new(QofBook *book, const char *fullname, const char *name_space, const char *mnemonic, const char *cusip, int fraction)
int gnc_commodity_table_has_namespace(const gnc_commodity_table *table, const char *name_space)
void gnc_commodity_table_delete_namespace(gnc_commodity_table *table, const char *name_space)
gboolean gnc_commodity_namespace_is_iso(const char *name_space)
const char * gnc_commodity_get_fullname(const gnc_commodity *cm)
#define GNC_COMMODITY_NS_LEGACY
Definition: gnc-commodity.h:97
void qof_book_set_data(QofBook *book, const gchar *key, gpointer data)
gboolean qof_commit_edit_part2(QofInstance *inst, void(*on_error)(QofInstance *, QofBackendError), void(*on_done)(QofInstance *), void(*on_free)(QofInstance *))
const char * gnc_commodity_get_nice_symbol(const gnc_commodity *cm)
void qof_collection_mark_clean(QofCollection *)
Generic api to store and retrieve preferences.
CommodityList * gnc_commodity_table_get_commodities(const gnc_commodity_table *table, const char *name_space)
gnc_quote_source * gnc_quote_source_lookup_by_internal(const char *name)
const char * gnc_commodity_get_printname(const gnc_commodity *cm)
int gnc_commodity_compare(const gnc_commodity *a, const gnc_commodity *b)
void gnc_commodity_set_fullname(gnc_commodity *cm, const char *fullname)
gnc_quote_source * gnc_commodity_get_quote_source(const gnc_commodity *cm)
gnc_commodity_namespace * gnc_commodity_table_find_namespace(const gnc_commodity_table *table, const char *name_space)
void gnc_commodity_set_mnemonic(gnc_commodity *cm, const char *mnemonic)
const char * gnc_commodity_get_default_symbol(const gnc_commodity *cm)
CommodityList * gnc_commodity_table_get_quotable_commodities(const gnc_commodity_table *table)
gnc_commodity_table * gnc_commodity_table_new(void)
gint gnc_quote_source_get_index(const gnc_quote_source *source)
gnc_commodity_namespace * gnc_commodity_get_namespace_ds(const gnc_commodity *cm)
#define LEAVE(format, args...)
Definition: qoflog.h:271
const char * gnc_commodity_get_unique_name(const gnc_commodity *cm)
MonetaryList * gnc_monetary_list_add_monetary(MonetaryList *list, gnc_monetary add_mon)
void gnc_commodity_table_remove(gnc_commodity_table *table, gnc_commodity *comm)
void gnc_commodity_set_namespace(gnc_commodity *cm, const char *name_space)
QofCollection * qof_book_get_collection(const QofBook *, QofIdType)
guint gnc_commodity_table_get_size(const gnc_commodity_table *tbl)
const char * gnc_quote_source_get_internal_name(const gnc_quote_source *source)
gboolean qof_object_register(const QofObject *object)
void qof_event_gen(QofInstance *entity, QofEventId event_type, gpointer event_data)
Invoke all registered event handlers using the given arguments.
#define GNC_DENOM_AUTO
Definition: gnc-numeric.h:246
void gnc_commodity_copy(gnc_commodity *dest, const gnc_commodity *src)
gpointer qof_book_get_data(const QofBook *book, const gchar *key)
GList * gnc_commodity_table_get_namespaces_list(const gnc_commodity_table *table)
void kvp_frame_set_string(KvpFrame *frame, const gchar *path, const gchar *str)
Store a copy of the string at the indicated path.
gnc_commodity * gnc_commodity_obtain_twin(const gnc_commodity *from, QofBook *book)
Commodity handling public routines.
void gnc_commodity_destroy(gnc_commodity *cm)
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
gboolean gnc_commodity_is_iso(const gnc_commodity *cm)
gboolean gnc_quote_source_fq_installed(void)
const gchar * QofLogModule
Definition: qofid.h:89