PageRenderTime 32ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/src/engine/gnc-commodity.c

http://github.com/mchochlov/Gnucash
C | 2551 lines | 1854 code | 405 blank | 292 comment | 247 complexity | 684590e3236492c6f1c7de19e9b01a6c MD5 | raw file
Possible License(s): GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /********************************************************************
  2. * gnc-commodity.c -- api for tradable commodities (incl. currency) *
  3. * Copyright (C) 2000 Bill Gribble *
  4. * Copyright (C) 2001,2003 Linas Vepstas <linas@linas.org> *
  5. * Copyright (c) 2006 David Hampton <hampton@employees.org> *
  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 gnu@gnu.org *
  23. * *
  24. *******************************************************************/
  25. #include "config.h"
  26. #include <glib.h>
  27. #include <glib/gi18n.h>
  28. #include <ctype.h>
  29. #include <limits.h>
  30. #include <string.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <regex.h>
  34. #include "gnc-commodity.h"
  35. #include "gnc-main.h"
  36. static QofLogModule log_module = GNC_MOD_COMMODITY;
  37. /* Parts per unit is nominal, i.e. number of 'partname' units in
  38. * a 'unitname' unit. fraction is transactional, i.e. how many
  39. * of the smallest-transactional-units of the currency are there
  40. * in a 'unitname' unit. */
  41. enum
  42. {
  43. PROP_0,
  44. PROP_NAMESPACE,
  45. PROP_FULL_NAME,
  46. PROP_MNEMONIC,
  47. PROP_PRINTNAME,
  48. PROP_CUSIP,
  49. PROP_FRACTION,
  50. PROP_UNIQUE_NAME,
  51. PROP_QUOTE_FLAG,
  52. PROP_QUOTE_SOURCE,
  53. PROP_QUOTE_TZ,
  54. };
  55. struct gnc_commodity_s
  56. {
  57. QofInstance inst;
  58. };
  59. typedef struct CommodityPrivate
  60. {
  61. gnc_commodity_namespace *namespace;
  62. char * fullname;
  63. char * mnemonic;
  64. char * printname;
  65. char * cusip; /* CUSIP or other identifying code */
  66. int fraction;
  67. char * unique_name;
  68. gboolean quote_flag; /* user wants price quotes */
  69. gnc_quote_source * quote_source; /* current/old source of quotes */
  70. char * quote_tz;
  71. /* the number of accounts using this commodity - this field is not
  72. * persisted */
  73. int usage_count;
  74. } CommodityPrivate;
  75. #define GET_PRIVATE(o) \
  76. (G_TYPE_INSTANCE_GET_PRIVATE((o), GNC_TYPE_COMMODITY, CommodityPrivate))
  77. struct _GncCommodityClass
  78. {
  79. QofInstanceClass parent_class;
  80. };
  81. static void commodity_free(gnc_commodity * cm);
  82. struct gnc_commodity_namespace_s
  83. {
  84. QofInstance inst;
  85. gchar * name;
  86. gboolean iso4217;
  87. GHashTable * cm_table;
  88. GList * cm_list;
  89. };
  90. struct _GncCommodityNamespaceClass
  91. {
  92. QofInstanceClass parent_class;
  93. };
  94. struct gnc_commodity_table_s
  95. {
  96. GHashTable * ns_table;
  97. GList * ns_list;
  98. };
  99. struct gnc_new_iso_code
  100. {
  101. const char *old_code;
  102. const char *new_code;
  103. } gnc_new_iso_codes[] =
  104. {
  105. {"RUR", "RUB"}, /* Russian Ruble: RUR through 1997-12, RUB from 1998-01 onwards; see bug #393185 */
  106. {"PLZ", "PLN"}, /* Polish Zloty */
  107. {"UAG", "UAH"}, /* Ukraine Hryvnia */
  108. {"NIS", "ILS"}, /* New Israeli Shekel: The informal abbreviation may be "NIS", but
  109. its iso-4217 is clearly ILS and only this! Incorrectly changed
  110. due to bug#152755 (Nov 2004) and changed back again by bug#492417
  111. (Oct 2008). */
  112. {"MXP", "MXN"}, /* Mexican (Nuevo) Peso */
  113. {"TRL", "TRY"}, /* New Turkish Lira: changed 2005 */
  114. /* Only add currencies to this table when the old currency no longer
  115. * exists in the file iso-4217-currencies.scm */
  116. };
  117. #define GNC_NEW_ISO_CODES \
  118. (sizeof(gnc_new_iso_codes) / sizeof(struct gnc_new_iso_code))
  119. static gboolean fq_is_installed = FALSE;
  120. struct gnc_quote_source_s
  121. {
  122. gboolean supported;
  123. QuoteSourceType type;
  124. gint index;
  125. char *user_name; /* User friendly name */
  126. char *old_internal_name; /* Name used internally (deprecated) */
  127. char *internal_name; /* Name used internally and by finance::quote. */
  128. };
  129. static gnc_quote_source currency_quote_source =
  130. { TRUE, 0, 0, "Currency", "CURRENCY", "currency" };
  131. static gnc_quote_source single_quote_sources[] =
  132. {
  133. { FALSE, 0, 0, "Amsterdam Euronext eXchange, NL", "AEX", "aex" },
  134. { FALSE, 0, 0, "AEX Futures (now in AEX)", "AEX_FUTURES", "aex_futures" },
  135. { FALSE, 0, 0, "AEX Options (now in AEX)", "AEX_OPTIONS", "aex_options" },
  136. { FALSE, 0, 0, "American International Assurance, HK", "AIAHK", "aiahk" },
  137. { FALSE, 0, 0, "Association of Mutual Funds in India", "AMFIINDIA", "amfiindia" },
  138. { FALSE, 0, 0, "Athens Stock Exchange, GR", "ASEGR", "asegr" },
  139. { FALSE, 0, 0, "Australian Stock Exchange, AU", "ASX", "asx" },
  140. { FALSE, 0, 0, "BMO NesbittBurns, CA", "BMONESBITTBURNS", "bmonesbittburns" },
  141. { FALSE, 0, 0, "BUX/Magyar Tökepiac, HU", "BUX", "bux" },
  142. { FALSE, 0, 0, "Cominvest, ex-Adig, DE", "COMINVEST", "cominvest" },
  143. { FALSE, 0, 0, "Deka Investments, DE", "DEKA", "deka" },
  144. { FALSE, 0, 0, "DWS, DE", "DWS", "dwsfunds" },
  145. { FALSE, 0, 0, "Fidelity Direct", "FIDELITY_DIRECT", "fidelity_direct" },
  146. { FALSE, 0, 0, "Finance Canada", "FINANCECANADA", "financecanada" },
  147. { FALSE, 0, 0, "Finanzpartner, DE", "FINANZPARTNER", "finanzpartner" },
  148. { FALSE, 0, 0, "First Trust Portfolios, US", "FTPORTFOLIOS_DIRECT", "ftportfolios_direct" },
  149. { FALSE, 0, 0, "Fund Library, CA", "FUNDLIBRARY", "fundlibrary" },
  150. { FALSE, 0, 0, "GoldMoney spot rates, JE", "GOLDMONEY", "goldmoney" },
  151. { FALSE, 0, 0, "HElsinki stock eXchange, FI", "HEX", "hex" },
  152. { FALSE, 0, 0, "Man Investments, AU", "maninv", "maninv" },
  153. { FALSE, 0, 0, "Morningstar, SE", "MORNINGSTAR", "morningstar" },
  154. { FALSE, 0, 0, "Motley Fool, US", "FOOL", "fool" },
  155. { FALSE, 0, 0, "New Zealand stock eXchange, NZ", "NZX", "nzx" },
  156. { FALSE, 0, 0, "Paris Stock Exchange/Boursorama, FR", "BOURSO", "bourso" },
  157. { FALSE, 0, 0, "Paris Stock Exchange/LeRevenu, FR", "LEREVENU", "lerevenu" },
  158. { FALSE, 0, 0, "Platinum Asset Management, AU", "PLATINUM", "platinum" },
  159. { FALSE, 0, 0, "Skandinaviska Enskilda Banken, SE", "SEB_FUNDS", "seb_funds" },
  160. { FALSE, 0, 0, "Sharenet, ZA", "ZA", "za" },
  161. { FALSE, 0, 0, "StockHouse Canada", "STOCKHOUSE_FUND", "stockhousecanada_fund" },
  162. { FALSE, 0, 0, "TD Waterhouse Canada", "TDWATERHOUSE", "tdwaterhouse" },
  163. { FALSE, 0, 0, "TD Efunds, CA", "TDEFUNDS", "tdefunds" },
  164. { FALSE, 0, 0, "TIAA-CREF, US", "TIAACREF", "tiaacref" },
  165. { FALSE, 0, 0, "Toronto Stock eXchange, CA", "TSX", "tsx" },
  166. { FALSE, 0, 0, "T. Rowe Price, US", "TRPRICE_DIRECT", "troweprice_direct" },
  167. { FALSE, 0, 0, "Trustnet, GB", "TRUSTNET", "trustnet" },
  168. { FALSE, 0, 0, "Union Investment, DE", "UNIONFUNDS", "unionfunds" },
  169. { FALSE, 0, 0, "US Treasury Bonds", "usfedbonds", "usfedbonds" },
  170. { FALSE, 0, 0, "US Govt. Thrift Savings Plan", "TSP", "tsp" },
  171. { FALSE, 0, 0, "Vanguard", "VANGUARD", "vanguard" }, /* No module seen in F::Q 1.17. */
  172. { FALSE, 0, 0, "VWD, DE (unmaintained)", "VWD", "vwd" },
  173. { FALSE, 0, 0, "Yahoo USA", "YAHOO", "yahoo" },
  174. { FALSE, 0, 0, "Yahoo Asia", "YAHOO_ASIA", "yahoo_asia" },
  175. { FALSE, 0, 0, "Yahoo Australia", "YAHOO_AUSTRALIA", "yahoo_australia" },
  176. { FALSE, 0, 0, "Yahoo Brasil", "YAHOO_BRASIL", "yahoo_brasil" },
  177. { FALSE, 0, 0, "Yahoo Europe", "YAHOO_EUROPE", "yahoo_europe" },
  178. { FALSE, 0, 0, "Yahoo New Zealand", "YAHOO_NZ", "yahoo_nz" },
  179. { FALSE, 0, 0, "Zuerich Investments (outdated)", "ZIFUNDS", "zifunds" }, /* Removed from F::Q 1.11. */
  180. };
  181. static gnc_quote_source multiple_quote_sources[] =
  182. {
  183. { FALSE, 0, 0, "Asia (Yahoo, ...)", "ASIA", "asia" },
  184. { FALSE, 0, 0, "Australia (ASX, Yahoo, ...)", "AUSTRALIA", "australia" },
  185. { FALSE, 0, 0, "Brasil (Yahoo, ...)", "BRASIL", "brasil" },
  186. { FALSE, 0, 0, "Canada (Yahoo, ...)", "CANADA", "canada" },
  187. { FALSE, 0, 0, "Canada Mutual (Fund Library, ...)", "CANADAMUTUAL", "canadamutual" },
  188. { FALSE, 0, 0, "Dutch (AEX, ...)", "DUTCH", "dutch" },
  189. { FALSE, 0, 0, "Europe (Yahoo, ...)", "EUROPE", "europe" },
  190. { FALSE, 0, 0, "Greece (ASE, ...)", "GREECE", "greece" },
  191. { FALSE, 0, 0, "India Mutual (AMFI, ...)", "INDIAMUTUAL", "indiamutual" },
  192. { FALSE, 0, 0, "Fidelity (Fidelity, ...)", "FIDELITY", "fidelity" },
  193. { FALSE, 0, 0, "Finland (HEX, ...)", "FINLAND", "finland" },
  194. { FALSE, 0, 0, "First Trust (First Trust, ...)", "FTPORTFOLIOS", "ftportfolios" },
  195. { FALSE, 0, 0, "France (Boursorama, ...)", "FRANCE", "france" },
  196. { FALSE, 0, 0, "Nasdaq (Yahoo, ...)", "NASDAQ", "nasdaq" },
  197. { FALSE, 0, 0, "New Zealand (Yahoo, ...)", "NZ", "nz" },
  198. { FALSE, 0, 0, "NYSE (Yahoo, ...)", "NYSE", "nyse" },
  199. /* { FALSE, 0, 0, "South Africa (Sharenet, ...)", "ZA", "za" }, */
  200. { FALSE, 0, 0, "T. Rowe Price", "TRPRICE", "troweprice" },
  201. { FALSE, 0, 0, "U.K. Unit Trusts", "UKUNITTRUSTS", "uk_unit_trusts" },
  202. { FALSE, 0, 0, "USA (Yahoo, Fool ...)", "USA", "usa" },
  203. };
  204. static const int num_single_quote_sources =
  205. sizeof(single_quote_sources) / sizeof(gnc_quote_source);
  206. static const int num_multiple_quote_sources =
  207. sizeof(multiple_quote_sources) / sizeof(gnc_quote_source);
  208. static GList *new_quote_sources = NULL;
  209. /********************************************************************
  210. * gnc_quote_source_fq_installed
  211. *
  212. * This function indicates whether or not the Finance::Quote module
  213. * is installed on a users computer.
  214. ********************************************************************/
  215. gboolean
  216. gnc_quote_source_fq_installed (void)
  217. {
  218. return fq_is_installed;
  219. }
  220. /********************************************************************
  221. * gnc_quote_source_num_entries
  222. *
  223. * Return the number of entries for a given type of price source.
  224. ********************************************************************/
  225. gint gnc_quote_source_num_entries(QuoteSourceType type)
  226. {
  227. if (type == SOURCE_CURRENCY)
  228. return 1;
  229. if (type == SOURCE_SINGLE)
  230. return num_single_quote_sources;
  231. if (type == SOURCE_MULTI)
  232. return num_multiple_quote_sources;
  233. return g_list_length(new_quote_sources);
  234. }
  235. /********************************************************************
  236. * gnc_quote_source_init_tables
  237. *
  238. * Update the type/index values for prices sources.
  239. ********************************************************************/
  240. static void
  241. gnc_quote_source_init_tables (void)
  242. {
  243. gint i;
  244. for (i = 0; i < num_single_quote_sources; i++)
  245. {
  246. single_quote_sources[i].type = SOURCE_SINGLE;
  247. single_quote_sources[i].index = i;
  248. }
  249. for (i = 0; i < num_multiple_quote_sources; i++)
  250. {
  251. multiple_quote_sources[i].type = SOURCE_MULTI;
  252. multiple_quote_sources[i].index = i;
  253. }
  254. currency_quote_source.type = SOURCE_CURRENCY;
  255. currency_quote_source.index = 0;
  256. }
  257. /********************************************************************
  258. * gnc_quote_source_add_new
  259. *
  260. * Add a new price source. Called when unknown source names are found
  261. * either in the F::Q installation (a newly available source) or in
  262. * the user's data file (a source that has vanished but needs to be
  263. * tracked.)
  264. ********************************************************************/
  265. gnc_quote_source *
  266. gnc_quote_source_add_new (const char *source_name, gboolean supported)
  267. {
  268. gnc_quote_source *new_source;
  269. DEBUG("Creating new source %s", (source_name == NULL ? "(null)" : source_name));
  270. new_source = malloc(sizeof(gnc_quote_source));
  271. new_source->supported = supported;
  272. new_source->type = SOURCE_UNKNOWN;
  273. new_source->index = g_list_length(new_quote_sources);
  274. /* This name can be changed if/when support for this price source is
  275. * integrated into gnucash. */
  276. new_source->user_name = g_strdup(source_name);
  277. /* This name is permanent and must be kept the same if/when support
  278. * for this price source is integrated into gnucash (i.e. for a
  279. * nice user name). */
  280. new_source->old_internal_name = g_strdup(source_name);
  281. new_source->internal_name = g_strdup(source_name);
  282. new_quote_sources = g_list_append(new_quote_sources, new_source);
  283. return new_source;
  284. }
  285. /********************************************************************
  286. * gnc_quote_source_lookup_by_xxx
  287. *
  288. * Lookup a price source data structure based upon various criteria.
  289. ********************************************************************/
  290. gnc_quote_source *
  291. gnc_quote_source_lookup_by_ti (QuoteSourceType type, gint index)
  292. {
  293. gnc_quote_source *source;
  294. GList *node;
  295. ENTER("type/index is %d/%d", type, index);
  296. switch (type)
  297. {
  298. case SOURCE_CURRENCY:
  299. LEAVE("found %s", currency_quote_source.user_name);
  300. return &currency_quote_source;
  301. break;
  302. case SOURCE_SINGLE:
  303. if (index < num_single_quote_sources)
  304. {
  305. LEAVE("found %s", single_quote_sources[index].user_name);
  306. return &single_quote_sources[index];
  307. }
  308. break;
  309. case SOURCE_MULTI:
  310. if (index < num_multiple_quote_sources)
  311. {
  312. LEAVE("found %s", multiple_quote_sources[index].user_name);
  313. return &multiple_quote_sources[index];
  314. }
  315. break;
  316. case SOURCE_UNKNOWN:
  317. default:
  318. node = g_list_nth(new_quote_sources, index);
  319. if (node)
  320. {
  321. source = node->data;
  322. LEAVE("found %s", source->user_name);
  323. return source;
  324. }
  325. }
  326. LEAVE("not found");
  327. return NULL;
  328. }
  329. gnc_quote_source *
  330. gnc_quote_source_lookup_by_internal(const char * name)
  331. {
  332. gnc_quote_source *source;
  333. GList *node;
  334. gint i;
  335. if ((name == NULL) || (safe_strcmp(name, "") == 0))
  336. {
  337. return NULL;
  338. }
  339. if (safe_strcmp(name, currency_quote_source.internal_name) == 0)
  340. return &currency_quote_source;
  341. if (safe_strcmp(name, currency_quote_source.old_internal_name) == 0)
  342. return &currency_quote_source;
  343. for (i = 0; i < num_single_quote_sources; i++)
  344. {
  345. if (safe_strcmp(name, single_quote_sources[i].internal_name) == 0)
  346. return &single_quote_sources[i];
  347. if (safe_strcmp(name, single_quote_sources[i].old_internal_name) == 0)
  348. return &single_quote_sources[i];
  349. }
  350. for (i = 0; i < num_multiple_quote_sources; i++)
  351. {
  352. if (safe_strcmp(name, multiple_quote_sources[i].internal_name) == 0)
  353. return &multiple_quote_sources[i];
  354. if (safe_strcmp(name, multiple_quote_sources[i].old_internal_name) == 0)
  355. return &multiple_quote_sources[i];
  356. }
  357. for (i = 0, node = new_quote_sources; node; node = node->next, i++)
  358. {
  359. source = node->data;
  360. if (safe_strcmp(name, source->internal_name) == 0)
  361. return source;
  362. if (safe_strcmp(name, source->old_internal_name) == 0)
  363. return source;
  364. }
  365. DEBUG("gnc_quote_source_lookup_by_internal: Unknown source %s", name);
  366. return NULL;
  367. }
  368. /********************************************************************
  369. * gnc_quote_source_get_xxx
  370. *
  371. * Accessor functions - get functions only. There are no set functions.
  372. ********************************************************************/
  373. QuoteSourceType
  374. gnc_quote_source_get_type (const gnc_quote_source *source)
  375. {
  376. ENTER("%p", source);
  377. if (!source)
  378. {
  379. LEAVE("bad source");
  380. return SOURCE_SINGLE;
  381. }
  382. LEAVE("type is %d", source->type);
  383. return source->type;
  384. }
  385. gint
  386. gnc_quote_source_get_index (const gnc_quote_source *source)
  387. {
  388. ENTER("%p", source);
  389. if (!source)
  390. {
  391. LEAVE("bad source");
  392. return 0;
  393. }
  394. LEAVE("index is %d", source->index);
  395. return source->index;
  396. }
  397. gboolean
  398. gnc_quote_source_get_supported (const gnc_quote_source *source)
  399. {
  400. ENTER("%p", source);
  401. if (!source)
  402. {
  403. LEAVE("bad source");
  404. return FALSE;
  405. }
  406. LEAVE("%ssupported", source && source->supported ? "" : "not ");
  407. return source->supported;
  408. }
  409. const char *
  410. gnc_quote_source_get_user_name (const gnc_quote_source *source)
  411. {
  412. ENTER("%p", source);
  413. if (!source)
  414. {
  415. LEAVE("bad source");
  416. return NULL;
  417. }
  418. LEAVE("user name %s", source->user_name);
  419. return source->user_name;
  420. }
  421. const char *
  422. gnc_quote_source_get_old_internal_name (const gnc_quote_source *source)
  423. {
  424. ENTER("%p", source);
  425. if (!source)
  426. {
  427. LEAVE("bad source");
  428. return NULL;
  429. }
  430. LEAVE("old internal name %s", source->old_internal_name);
  431. return source->old_internal_name;
  432. }
  433. const char *
  434. gnc_quote_source_get_internal_name (const gnc_quote_source *source)
  435. {
  436. ENTER("%p", source);
  437. if (!source)
  438. {
  439. LEAVE("bad source");
  440. return NULL;
  441. }
  442. LEAVE("internal name %s", source->internal_name);
  443. return source->internal_name;
  444. }
  445. /********************************************************************
  446. * gnc_quote_source_set_fq_installed
  447. *
  448. * Update gnucash internal tables on what Finance::Quote sources are
  449. * installed.
  450. ********************************************************************/
  451. void
  452. gnc_quote_source_set_fq_installed (const GList *sources_list)
  453. {
  454. gnc_quote_source *source;
  455. char *source_name;
  456. const GList *node;
  457. ENTER(" ");
  458. fq_is_installed = TRUE;
  459. if (!sources_list)
  460. return;
  461. for (node = sources_list; node; node = node->next)
  462. {
  463. source_name = node->data;
  464. source = gnc_quote_source_lookup_by_internal(source_name);
  465. if (source != NULL)
  466. {
  467. DEBUG("Found source %s: %s", source_name, source->user_name);
  468. source->supported = TRUE;
  469. continue;
  470. }
  471. gnc_quote_source_add_new(source_name, TRUE);
  472. }
  473. LEAVE(" ");
  474. }
  475. /********************************************************************
  476. * QoF Helpers
  477. ********************************************************************/
  478. void
  479. gnc_commodity_begin_edit (gnc_commodity *cm)
  480. {
  481. qof_begin_edit(&cm->inst);
  482. }
  483. static void commit_err (QofInstance *inst, QofBackendError errcode)
  484. {
  485. PERR ("Failed to commit: %d", errcode);
  486. gnc_engine_signal_commit_error( errcode );
  487. }
  488. static void noop (QofInstance *inst) {}
  489. static void
  490. comm_free(QofInstance* inst)
  491. {
  492. commodity_free( GNC_COMMODITY(inst) );
  493. }
  494. void
  495. gnc_commodity_commit_edit (gnc_commodity *cm)
  496. {
  497. if (!qof_commit_edit (QOF_INSTANCE(cm))) return;
  498. qof_commit_edit_part2 (&cm->inst, commit_err, noop, comm_free);
  499. }
  500. /********************************************************************
  501. * gnc_commodity_new
  502. ********************************************************************/
  503. static void
  504. mark_commodity_dirty (gnc_commodity *cm)
  505. {
  506. qof_instance_set_dirty(&cm->inst);
  507. qof_event_gen (&cm->inst, QOF_EVENT_MODIFY, NULL);
  508. }
  509. static void
  510. reset_printname(CommodityPrivate *priv)
  511. {
  512. g_free(priv->printname);
  513. priv->printname = g_strdup_printf("%s (%s)",
  514. priv->mnemonic ? priv->mnemonic : "",
  515. priv->fullname ? priv->fullname : "");
  516. }
  517. static void
  518. reset_unique_name(CommodityPrivate *priv)
  519. {
  520. gnc_commodity_namespace *ns;
  521. g_free(priv->unique_name);
  522. ns = priv->namespace;
  523. priv->unique_name = g_strdup_printf("%s::%s",
  524. ns ? ns->name : "",
  525. priv->mnemonic ? priv->mnemonic : "");
  526. }
  527. /* GObject Initialization */
  528. G_DEFINE_TYPE(gnc_commodity, gnc_commodity, QOF_TYPE_INSTANCE);
  529. static void
  530. gnc_commodity_init(gnc_commodity* com)
  531. {
  532. CommodityPrivate* priv;
  533. priv = GET_PRIVATE(com);
  534. priv->namespace = NULL;
  535. priv->fullname = CACHE_INSERT("");
  536. priv->mnemonic = CACHE_INSERT("");
  537. priv->cusip = CACHE_INSERT("");
  538. priv->fraction = 10000;
  539. priv->quote_flag = 0;
  540. priv->quote_source = NULL;
  541. priv->quote_tz = CACHE_INSERT("");
  542. reset_printname(priv);
  543. reset_unique_name(priv);
  544. }
  545. static void
  546. gnc_commodity_dispose(GObject *comp)
  547. {
  548. G_OBJECT_CLASS(gnc_commodity_parent_class)->dispose(comp);
  549. }
  550. static void
  551. gnc_commodity_finalize(GObject* comp)
  552. {
  553. G_OBJECT_CLASS(gnc_commodity_parent_class)->finalize(comp);
  554. }
  555. static void
  556. gnc_commodity_get_property (GObject *object,
  557. guint prop_id,
  558. GValue *value,
  559. GParamSpec *pspec)
  560. {
  561. gnc_commodity *commodity;
  562. CommodityPrivate* priv;
  563. g_return_if_fail(GNC_IS_COMMODITY(object));
  564. commodity = GNC_COMMODITY(object);
  565. priv = GET_PRIVATE(commodity);
  566. switch (prop_id)
  567. {
  568. case PROP_NAMESPACE:
  569. g_value_set_object(value, priv->namespace);
  570. break;
  571. case PROP_FULL_NAME:
  572. g_value_set_string(value, priv->fullname);
  573. break;
  574. case PROP_MNEMONIC:
  575. g_value_set_string(value, priv->mnemonic);
  576. break;
  577. case PROP_PRINTNAME:
  578. g_value_set_string(value, priv->printname);
  579. break;
  580. case PROP_CUSIP:
  581. g_value_set_string(value, priv->cusip);
  582. break;
  583. case PROP_FRACTION:
  584. g_value_set_int(value, priv->fraction);
  585. break;
  586. case PROP_UNIQUE_NAME:
  587. g_value_set_string(value, priv->unique_name);
  588. break;
  589. case PROP_QUOTE_FLAG:
  590. g_value_set_boolean(value, priv->quote_flag);
  591. break;
  592. case PROP_QUOTE_SOURCE:
  593. g_value_set_pointer(value, priv->quote_source);
  594. break;
  595. case PROP_QUOTE_TZ:
  596. g_value_set_string(value, priv->quote_tz);
  597. break;
  598. default:
  599. G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
  600. break;
  601. }
  602. }
  603. static void
  604. gnc_commodity_set_property (GObject *object,
  605. guint prop_id,
  606. const GValue *value,
  607. GParamSpec *pspec)
  608. {
  609. gnc_commodity *commodity;
  610. g_return_if_fail(GNC_IS_COMMODITY(object));
  611. commodity = GNC_COMMODITY(object);
  612. switch (prop_id)
  613. {
  614. case PROP_NAMESPACE:
  615. gnc_commodity_set_namespace(commodity, g_value_get_object(value));
  616. break;
  617. case PROP_FULL_NAME:
  618. gnc_commodity_set_fullname(commodity, g_value_get_string(value));
  619. break;
  620. case PROP_MNEMONIC:
  621. gnc_commodity_set_mnemonic(commodity, g_value_get_string(value));
  622. break;
  623. case PROP_CUSIP:
  624. gnc_commodity_set_cusip(commodity, g_value_get_string(value));
  625. break;
  626. case PROP_FRACTION:
  627. gnc_commodity_set_fraction(commodity, g_value_get_int(value));
  628. break;
  629. case PROP_QUOTE_FLAG:
  630. gnc_commodity_set_quote_flag(commodity, g_value_get_boolean(value));
  631. break;
  632. case PROP_QUOTE_SOURCE:
  633. gnc_commodity_set_quote_source(commodity, g_value_get_pointer(value));
  634. break;
  635. case PROP_QUOTE_TZ:
  636. gnc_commodity_set_quote_tz(commodity, g_value_get_string(value));
  637. break;
  638. default:
  639. G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
  640. break;
  641. }
  642. }
  643. static void
  644. gnc_commodity_class_init(struct _GncCommodityClass* klass)
  645. {
  646. GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
  647. gobject_class->dispose = gnc_commodity_dispose;
  648. gobject_class->finalize = gnc_commodity_finalize;
  649. gobject_class->set_property = gnc_commodity_set_property;
  650. gobject_class->get_property = gnc_commodity_get_property;
  651. g_type_class_add_private(klass, sizeof(CommodityPrivate));
  652. g_object_class_install_property(gobject_class,
  653. PROP_NAMESPACE,
  654. g_param_spec_object ("namespace",
  655. "Namespace",
  656. "The namespace field denotes the "
  657. "namespace for this commodity, either "
  658. "a currency or symbol from a quote source.",
  659. GNC_TYPE_COMMODITY_NAMESPACE,
  660. G_PARAM_READWRITE));
  661. g_object_class_install_property(gobject_class,
  662. PROP_FULL_NAME,
  663. g_param_spec_string ("fullname",
  664. "Full Commodity Name",
  665. "The fullname is the official full name of"
  666. "the currency.",
  667. NULL,
  668. G_PARAM_READWRITE));
  669. g_object_class_install_property(gobject_class,
  670. PROP_MNEMONIC,
  671. g_param_spec_string ("mnemonic",
  672. "Commodity Mnemonic",
  673. "The mnemonic is the official abbreviated"
  674. "designation for the currency.",
  675. NULL,
  676. G_PARAM_READWRITE));
  677. g_object_class_install_property(gobject_class,
  678. PROP_PRINTNAME,
  679. g_param_spec_string ("printname",
  680. "Commodity Print Name",
  681. "Printable form of the commodity name.",
  682. NULL,
  683. G_PARAM_READABLE));
  684. g_object_class_install_property(gobject_class,
  685. PROP_CUSIP,
  686. g_param_spec_string ("cusip",
  687. "Commodity CUSIP Code",
  688. "?????",
  689. NULL,
  690. G_PARAM_READWRITE));
  691. g_object_class_install_property(gobject_class,
  692. PROP_FRACTION,
  693. g_param_spec_int ("fraction",
  694. "Fraction",
  695. "The fraction is the number of sub-units that "
  696. "the basic commodity can be divided into.",
  697. 1,
  698. 1000000,
  699. 1,
  700. G_PARAM_READWRITE));
  701. g_object_class_install_property(gobject_class,
  702. PROP_UNIQUE_NAME,
  703. g_param_spec_string ("unique-name",
  704. "Commodity Unique Name",
  705. "Unique form of the commodity name which combines "
  706. "the namespace name and the commodity name.",
  707. NULL,
  708. G_PARAM_READABLE));
  709. g_object_class_install_property(gobject_class,
  710. PROP_QUOTE_FLAG,
  711. g_param_spec_boolean ("quote_flag",
  712. "Quote Flag",
  713. "TRUE if prices are to be downloaded for this "
  714. "commodity from a quote source.",
  715. FALSE,
  716. G_PARAM_READWRITE));
  717. g_object_class_install_property(gobject_class,
  718. PROP_QUOTE_SOURCE,
  719. g_param_spec_pointer("quote-source",
  720. "Quote Source",
  721. "The quote source from which prices are downloaded.",
  722. G_PARAM_READWRITE));
  723. g_object_class_install_property(gobject_class,
  724. PROP_QUOTE_TZ,
  725. g_param_spec_string ("quote-tz",
  726. "Commodity Quote Timezone",
  727. "?????",
  728. NULL,
  729. G_PARAM_READWRITE));
  730. }
  731. gnc_commodity *
  732. gnc_commodity_new(QofBook *book, const char * fullname,
  733. const char * namespace, const char * mnemonic,
  734. const char * cusip, int fraction)
  735. {
  736. gnc_commodity * retval = g_object_new(GNC_TYPE_COMMODITY, NULL);
  737. qof_instance_init_data (&retval->inst, GNC_ID_COMMODITY, book);
  738. gnc_commodity_begin_edit(retval);
  739. if ( namespace != NULL )
  740. {
  741. gnc_commodity_set_namespace(retval, namespace);
  742. if (gnc_commodity_namespace_is_iso(namespace))
  743. {
  744. gnc_commodity_set_quote_source(retval,
  745. gnc_quote_source_lookup_by_internal("currency") );
  746. }
  747. }
  748. gnc_commodity_set_fullname(retval, fullname);
  749. gnc_commodity_set_mnemonic(retval, mnemonic);
  750. gnc_commodity_set_cusip(retval, cusip);
  751. gnc_commodity_set_fraction(retval, fraction);
  752. gnc_commodity_commit_edit(retval);
  753. qof_event_gen (&retval->inst, QOF_EVENT_CREATE, NULL);
  754. return retval;
  755. }
  756. /********************************************************************
  757. * gnc_commodity_destroy
  758. ********************************************************************/
  759. static void
  760. commodity_free(gnc_commodity * cm)
  761. {
  762. QofBook *book;
  763. gnc_commodity_table *table;
  764. CommodityPrivate* priv;
  765. if (!cm) return;
  766. book = qof_instance_get_book(&cm->inst);
  767. table = gnc_commodity_table_get_table(book);
  768. gnc_commodity_table_remove(table, cm);
  769. priv = GET_PRIVATE(cm);
  770. qof_event_gen (&cm->inst, QOF_EVENT_DESTROY, NULL);
  771. /* Set at creation */
  772. CACHE_REMOVE (priv->fullname);
  773. CACHE_REMOVE (priv->cusip);
  774. CACHE_REMOVE (priv->mnemonic);
  775. CACHE_REMOVE (priv->quote_tz);
  776. priv->namespace = NULL;
  777. /* Set through accessor functions */
  778. priv->quote_source = NULL;
  779. /* Automatically generated */
  780. g_free(priv->printname);
  781. priv->printname = NULL;
  782. g_free(priv->unique_name);
  783. priv->unique_name = NULL;
  784. #ifdef ACCOUNTS_CLEANED_UP
  785. /* Account objects are not actually cleaned up when a book is closed (in fact
  786. * a memory leak), but commodities are, so in currently this warning gets hit
  787. * quite frequently. Disable the check until cleaning up of accounts objects
  788. * on close is implemented. */
  789. if (priv->usage_count != 0)
  790. {
  791. PWARN("Destroying commodity (%p) with non-zero usage_count (%d).", cm,
  792. priv->usage_count);
  793. }
  794. #endif
  795. /* qof_instance_release (&cm->inst); */
  796. g_object_unref(cm);
  797. }
  798. void
  799. gnc_commodity_destroy(gnc_commodity * cm)
  800. {
  801. gnc_commodity_begin_edit(cm);
  802. qof_instance_set_destroying(cm, TRUE);
  803. gnc_commodity_commit_edit(cm);
  804. }
  805. void
  806. gnc_commodity_copy(gnc_commodity * dest, const gnc_commodity *src)
  807. {
  808. CommodityPrivate* src_priv = GET_PRIVATE(src);
  809. CommodityPrivate* dest_priv = GET_PRIVATE(dest);
  810. gnc_commodity_set_fullname (dest, src_priv->fullname);
  811. gnc_commodity_set_mnemonic (dest, src_priv->mnemonic);
  812. dest_priv->namespace = src_priv->namespace;
  813. gnc_commodity_set_fraction (dest, src_priv->fraction);
  814. gnc_commodity_set_cusip (dest, src_priv->cusip);
  815. gnc_commodity_set_quote_flag (dest, src_priv->quote_flag);
  816. gnc_commodity_set_quote_source (dest, gnc_commodity_get_quote_source (src));
  817. gnc_commodity_set_quote_tz (dest, src_priv->quote_tz);
  818. kvp_frame_delete (dest->inst.kvp_data);
  819. dest->inst.kvp_data = kvp_frame_copy (src->inst.kvp_data);
  820. kvp_frame_delete (dest->inst.kvp_data);
  821. dest->inst.kvp_data = kvp_frame_copy (src->inst.kvp_data);
  822. }
  823. gnc_commodity *
  824. gnc_commodity_clone(const gnc_commodity *src, QofBook *dest_book)
  825. {
  826. CommodityPrivate* src_priv;
  827. CommodityPrivate* dest_priv;
  828. gnc_commodity * dest = g_object_new(GNC_TYPE_COMMODITY, NULL);
  829. qof_instance_init_data (&dest->inst, GNC_ID_COMMODITY, dest_book);
  830. src_priv = GET_PRIVATE(src);
  831. dest_priv = GET_PRIVATE(dest);
  832. dest_priv->fullname = CACHE_INSERT(src_priv->fullname);
  833. dest_priv->mnemonic = CACHE_INSERT(src_priv->mnemonic);
  834. dest_priv->cusip = CACHE_INSERT(src_priv->cusip);
  835. dest_priv->quote_tz = CACHE_INSERT(src_priv->quote_tz);
  836. dest_priv->namespace = src_priv->namespace;
  837. dest_priv->fraction = src_priv->fraction;
  838. dest_priv->quote_flag = src_priv->quote_flag;
  839. gnc_commodity_set_quote_source (dest, gnc_commodity_get_quote_source (src));
  840. kvp_frame_delete (dest->inst.kvp_data);
  841. dest->inst.kvp_data = kvp_frame_copy (src->inst.kvp_data);
  842. reset_printname(dest_priv);
  843. reset_unique_name(dest_priv);
  844. return dest;
  845. }
  846. /********************************************************************
  847. * gnc_commodity_get_mnemonic
  848. ********************************************************************/
  849. const char *
  850. gnc_commodity_get_mnemonic(const gnc_commodity * cm)
  851. {
  852. if (!cm) return NULL;
  853. return GET_PRIVATE(cm)->mnemonic;
  854. }
  855. /********************************************************************
  856. * gnc_commodity_get_printname
  857. ********************************************************************/
  858. const char *
  859. gnc_commodity_get_printname(const gnc_commodity * cm)
  860. {
  861. if (!cm) return NULL;
  862. return GET_PRIVATE(cm)->printname;
  863. }
  864. /********************************************************************
  865. * gnc_commodity_get_namespace
  866. ********************************************************************/
  867. const char *
  868. gnc_commodity_get_namespace(const gnc_commodity * cm)
  869. {
  870. if (!cm) return NULL;
  871. return gnc_commodity_namespace_get_name(GET_PRIVATE(cm)->namespace);
  872. }
  873. const char *
  874. gnc_commodity_get_namespace_compat(const gnc_commodity * cm)
  875. {
  876. CommodityPrivate* priv;
  877. if (!cm) return NULL;
  878. priv = GET_PRIVATE(cm);
  879. if (!priv->namespace) return NULL;
  880. if (priv->namespace->iso4217)
  881. {
  882. /* Data files are still written with ISO4217. */
  883. return GNC_COMMODITY_NS_ISO;
  884. }
  885. return gnc_commodity_namespace_get_name(priv->namespace);
  886. }
  887. gnc_commodity_namespace *
  888. gnc_commodity_get_namespace_ds(const gnc_commodity * cm)
  889. {
  890. if (!cm) return NULL;
  891. return GET_PRIVATE(cm)->namespace;
  892. }
  893. /********************************************************************
  894. * gnc_commodity_get_fullname
  895. ********************************************************************/
  896. const char *
  897. gnc_commodity_get_fullname(const gnc_commodity * cm)
  898. {
  899. if (!cm) return NULL;
  900. return GET_PRIVATE(cm)->fullname;
  901. }
  902. /********************************************************************
  903. * gnc_commodity_get_unique_name
  904. ********************************************************************/
  905. const char *
  906. gnc_commodity_get_unique_name(const gnc_commodity * cm)
  907. {
  908. if (!cm) return NULL;
  909. return GET_PRIVATE(cm)->unique_name;
  910. }
  911. /********************************************************************
  912. * gnc_commodity_get_cusip
  913. ********************************************************************/
  914. const char *
  915. gnc_commodity_get_cusip(const gnc_commodity * cm)
  916. {
  917. if (!cm) return NULL;
  918. return GET_PRIVATE(cm)->cusip;
  919. }
  920. /********************************************************************
  921. * gnc_commodity_get_fraction
  922. ********************************************************************/
  923. int
  924. gnc_commodity_get_fraction(const gnc_commodity * cm)
  925. {
  926. if (!cm) return 0;
  927. return GET_PRIVATE(cm)->fraction;
  928. }
  929. /********************************************************************
  930. * gnc_commodity_get_auto_quote_control_flag
  931. ********************************************************************/
  932. static gboolean
  933. gnc_commodity_get_auto_quote_control_flag(const gnc_commodity *cm)
  934. {
  935. const char *str;
  936. if (!cm) return FALSE;
  937. str = kvp_frame_get_string(cm->inst.kvp_data, "auto_quote_control");
  938. return !str || (strcmp(str, "false") != 0);
  939. }
  940. /********************************************************************
  941. * gnc_commodity_get_quote_flag
  942. ********************************************************************/
  943. gboolean
  944. gnc_commodity_get_quote_flag(const gnc_commodity *cm)
  945. {
  946. if (!cm) return FALSE;
  947. return (GET_PRIVATE(cm)->quote_flag);
  948. }
  949. /********************************************************************
  950. * gnc_commodity_get_quote_source
  951. ********************************************************************/
  952. gnc_quote_source*
  953. gnc_commodity_get_quote_source(const gnc_commodity *cm)
  954. {
  955. CommodityPrivate* priv;
  956. if (!cm) return NULL;
  957. priv = GET_PRIVATE(cm);
  958. if (!priv->quote_source && gnc_commodity_is_iso(cm))
  959. return &currency_quote_source;
  960. return priv->quote_source;
  961. }
  962. gnc_quote_source*
  963. gnc_commodity_get_default_quote_source(const gnc_commodity *cm)
  964. {
  965. if (cm && gnc_commodity_is_iso(cm))
  966. return &currency_quote_source;
  967. /* Should make this a user option at some point. */
  968. return gnc_quote_source_lookup_by_internal("yahoo");
  969. }
  970. /********************************************************************
  971. * gnc_commodity_get_quote_tz
  972. ********************************************************************/
  973. const char*
  974. gnc_commodity_get_quote_tz(const gnc_commodity *cm)
  975. {
  976. if (!cm) return NULL;
  977. return GET_PRIVATE(cm)->quote_tz;
  978. }
  979. /********************************************************************
  980. * gnc_commodity_set_mnemonic
  981. ********************************************************************/
  982. void
  983. gnc_commodity_set_mnemonic(gnc_commodity * cm, const char * mnemonic)
  984. {
  985. CommodityPrivate* priv;
  986. if (!cm) return;
  987. priv = GET_PRIVATE(cm);
  988. if (priv->mnemonic == mnemonic) return;
  989. gnc_commodity_begin_edit(cm);
  990. CACHE_REMOVE (priv->mnemonic);
  991. priv->mnemonic = CACHE_INSERT(mnemonic);
  992. mark_commodity_dirty (cm);
  993. reset_printname(priv);
  994. reset_unique_name(priv);
  995. gnc_commodity_commit_edit(cm);
  996. }
  997. /********************************************************************
  998. * gnc_commodity_set_namespace
  999. ********************************************************************/
  1000. void
  1001. gnc_commodity_set_namespace(gnc_commodity * cm, const char * namespace)
  1002. {
  1003. QofBook *book;
  1004. gnc_commodity_table *table;
  1005. gnc_commodity_namespace *nsp;
  1006. CommodityPrivate* priv;
  1007. if (!cm) return;
  1008. priv = GET_PRIVATE(cm);
  1009. book = qof_instance_get_book (&cm->inst);
  1010. table = gnc_commodity_table_get_table(book);
  1011. nsp = gnc_commodity_table_add_namespace(table, namespace, book);
  1012. if (priv->namespace == nsp)
  1013. return;
  1014. gnc_commodity_begin_edit(cm);
  1015. priv->namespace = nsp;
  1016. if (nsp->iso4217)
  1017. priv->quote_source = gnc_quote_source_lookup_by_internal("currency");
  1018. mark_commodity_dirty(cm);
  1019. reset_printname(priv);
  1020. reset_unique_name(priv);
  1021. gnc_commodity_commit_edit(cm);
  1022. }
  1023. /********************************************************************
  1024. * gnc_commodity_set_fullname
  1025. ********************************************************************/
  1026. void
  1027. gnc_commodity_set_fullname(gnc_commodity * cm, const char * fullname)
  1028. {
  1029. CommodityPrivate* priv;
  1030. if (!cm) return;
  1031. priv = GET_PRIVATE(cm);
  1032. if (priv->fullname == fullname) return;
  1033. CACHE_REMOVE (priv->fullname);
  1034. priv->fullname = CACHE_INSERT (fullname);
  1035. gnc_commodity_begin_edit(cm);
  1036. mark_commodity_dirty(cm);
  1037. reset_printname(priv);
  1038. gnc_commodity_commit_edit(cm);
  1039. }
  1040. /********************************************************************
  1041. * gnc_commodity_set_cusip
  1042. ********************************************************************/
  1043. void
  1044. gnc_commodity_set_cusip(gnc_commodity * cm,
  1045. const char * cusip)
  1046. {
  1047. CommodityPrivate* priv;
  1048. if (!cm) return;
  1049. priv = GET_PRIVATE(cm);
  1050. if (priv->cusip == cusip) return;
  1051. gnc_commodity_begin_edit(cm);
  1052. CACHE_REMOVE (priv->cusip);
  1053. priv->cusip = CACHE_INSERT (cusip);
  1054. mark_commodity_dirty(cm);
  1055. gnc_commodity_commit_edit(cm);
  1056. }
  1057. /********************************************************************
  1058. * gnc_commodity_set_fraction
  1059. ********************************************************************/
  1060. void
  1061. gnc_commodity_set_fraction(gnc_commodity * cm, int fraction)
  1062. {
  1063. if (!cm) return;
  1064. gnc_commodity_begin_edit(cm);
  1065. GET_PRIVATE(cm)->fraction = fraction;
  1066. mark_commodity_dirty(cm);
  1067. gnc_commodity_commit_edit(cm);
  1068. }
  1069. /********************************************************************
  1070. * gnc_commodity_set_auto_quote_control_flag
  1071. ********************************************************************/
  1072. static void
  1073. gnc_commodity_set_auto_quote_control_flag(gnc_commodity *cm,
  1074. const gboolean flag)
  1075. {
  1076. ENTER ("(cm=%p, flag=%d)", cm, flag);
  1077. if (!cm)
  1078. {
  1079. LEAVE("");
  1080. return;
  1081. }
  1082. gnc_commodity_begin_edit(cm);
  1083. kvp_frame_set_string(cm->inst.kvp_data,
  1084. "auto_quote_control", flag ? NULL : "false");
  1085. mark_commodity_dirty(cm);
  1086. gnc_commodity_commit_edit(cm);
  1087. LEAVE("");
  1088. }
  1089. /********************************************************************
  1090. * gnc_commodity_user_set_quote_flag
  1091. ********************************************************************/
  1092. void
  1093. gnc_commodity_user_set_quote_flag(gnc_commodity *cm, const gboolean flag)
  1094. {
  1095. CommodityPrivate* priv;
  1096. ENTER ("(cm=%p, flag=%d)", cm, flag);
  1097. if (!cm)
  1098. {
  1099. LEAVE("");
  1100. return;
  1101. }
  1102. priv = GET_PRIVATE(cm);
  1103. gnc_commodity_begin_edit(cm);
  1104. gnc_commodity_set_quote_flag(cm, flag);
  1105. if (gnc_commodity_is_iso(cm))
  1106. {
  1107. /* For currencies, disable auto quote control if the quote flag is being
  1108. * changed from its default value and enable it if the quote flag is being
  1109. * reset to its default value. The defaults for the quote flag are
  1110. * disabled if no accounts are using the currency, and true otherwise.
  1111. * Thus enable auto quote control if flag is FALSE and there are not any
  1112. * accounts using this currency OR flag is TRUE and there are accounts
  1113. * using this currency; otherwise disable auto quote control */
  1114. gnc_commodity_set_auto_quote_control_flag(cm,
  1115. (!flag && (priv->usage_count == 0)) || (flag && (priv->usage_count != 0)));
  1116. }
  1117. gnc_commodity_commit_edit(cm);
  1118. LEAVE("");
  1119. }
  1120. /********************************************************************
  1121. * gnc_commodity_set_quote_flag
  1122. ********************************************************************/
  1123. void
  1124. gnc_commodity_set_quote_flag(gnc_commodity *cm, const gboolean flag)
  1125. {
  1126. ENTER ("(cm=%p, flag=%d)", cm, flag);
  1127. if (!cm) return;
  1128. gnc_commodity_begin_edit(cm);
  1129. GET_PRIVATE(cm)->quote_flag = flag;
  1130. mark_commodity_dirty(cm);
  1131. gnc_commodity_commit_edit(cm);
  1132. LEAVE(" ");
  1133. }
  1134. /********************************************************************
  1135. * gnc_commodity_set_quote_source
  1136. ********************************************************************/
  1137. void
  1138. gnc_commodity_set_quote_source(gnc_commodity *cm, gnc_quote_source *src)
  1139. {
  1140. ENTER ("(cm=%p, src=%p(%s))", cm, src, src ? src->internal_name : "unknown");
  1141. if (!cm) return;
  1142. gnc_commodity_begin_edit(cm);
  1143. GET_PRIVATE(cm)->quote_source = src;
  1144. mark_commodity_dirty(cm);
  1145. gnc_commodity_commit_edit(cm);
  1146. LEAVE(" ");
  1147. }
  1148. /********************************************************************
  1149. * gnc_commodity_set_quote_tz
  1150. ********************************************************************/
  1151. void
  1152. gnc_commodity_set_quote_tz(gnc_commodity *cm, const char *tz)
  1153. {
  1154. CommodityPrivate* priv;
  1155. if (!cm) return;
  1156. ENTER ("(cm=%p, tz=%s)", cm, tz ? tz : "(null)");
  1157. priv = GET_PRIVATE(cm);
  1158. if (tz == priv->quote_tz)
  1159. {
  1160. LEAVE("Already correct TZ");
  1161. return;
  1162. }
  1163. gnc_commodity_begin_edit(cm);
  1164. CACHE_REMOVE (priv->quote_tz);
  1165. priv->quote_tz = CACHE_INSERT (tz);
  1166. mark_commodity_dirty(cm);
  1167. gnc_commodity_commit_edit(cm);
  1168. LEAVE(" ");
  1169. }
  1170. /********************************************************************
  1171. * gnc_commodity_increment_usage_count
  1172. ********************************************************************/
  1173. void
  1174. gnc_commodity_increment_usage_count(gnc_commodity *cm)
  1175. {
  1176. CommodityPrivate* priv;
  1177. ENTER("(cm=%p)", cm);
  1178. if (!cm)
  1179. {
  1180. LEAVE("");
  1181. return;
  1182. }
  1183. priv = GET_PRIVATE(cm);
  1184. if ((priv->usage_count == 0) && !priv->quote_flag
  1185. && gnc_commodity_get_auto_quote_control_flag(cm)
  1186. && gnc_commodity_is_iso(cm))
  1187. {
  1188. /* compatability hack - Gnucash 1.8 gets currency quotes when a
  1189. non-default currency is assigned to an account. */
  1190. gnc_commodity_begin_edit(cm);
  1191. gnc_commodity_set_quote_flag(cm, TRUE);
  1192. gnc_commodity_set_quote_source(cm,
  1193. gnc_commodity_get_default_quote_source(cm));
  1194. gnc_commodity_commit_edit(cm);
  1195. }
  1196. priv->usage_count++;
  1197. LEAVE("(usage_count=%d)", priv->usage_count);
  1198. }
  1199. /********************************************************************
  1200. * gnc_commodity_decrement_usage_count
  1201. ********************************************************************/
  1202. void
  1203. gnc_commodity_decrement_usage_count(gnc_commodity *cm)
  1204. {
  1205. CommodityPrivate* priv;
  1206. ENTER("(cm=%p)", cm);
  1207. if (!cm)
  1208. {
  1209. LEAVE("");
  1210. return;
  1211. }
  1212. priv = GET_PRIVATE(cm);
  1213. if (priv->usage_count == 0)
  1214. {
  1215. PWARN("usage_count already zero");
  1216. LEAVE("");
  1217. return;
  1218. }
  1219. priv->usage_count--;
  1220. if ((priv->usage_count == 0) && priv->quote_flag
  1221. && gnc_commodity_get_auto_quote_control_flag(cm)
  1222. && gnc_commodity_is_iso(cm))
  1223. {
  1224. /* if this is a currency with auto quote control enabled and no more
  1225. * accounts reference this currency, disable quote retrieval */
  1226. gnc_commodity_set_quote_flag(cm, FALSE);
  1227. }
  1228. LEAVE("(usage_count=%d)", priv->usage_count);
  1229. }
  1230. /********************************************************************\
  1231. \********************************************************************/
  1232. /********************************************************************
  1233. * gnc_commodity_equiv
  1234. * are two commodities the same?
  1235. ********************************************************************/
  1236. gboolean
  1237. gnc_commodity_equiv(const gnc_commodity * a, const gnc_commodity * b)
  1238. {
  1239. CommodityPrivate* priv_a;
  1240. CommodityPrivate* priv_b;
  1241. if (a == b) return TRUE;
  1242. if (!a || !b) return FALSE;
  1243. priv_a = GET_PRIVATE(a);
  1244. priv_b = GET_PRIVATE(b);
  1245. if (priv_a->namespace != priv_b->namespace) return FALSE;
  1246. if (safe_strcmp(priv_a->mnemonic, priv_b->mnemonic) != 0) return FALSE;
  1247. return TRUE;
  1248. }
  1249. gboolean
  1250. gnc_commodity_equal(const gnc_commodity * a, const gnc_commodity * b)
  1251. {
  1252. CommodityPrivate* priv_a;
  1253. CommodityPrivate* priv_b;
  1254. gboolean same_book;
  1255. if (a == b) return TRUE;
  1256. if (!a || !b)
  1257. {
  1258. DEBUG ("one is NULL");
  1259. return FALSE;
  1260. }
  1261. priv_a = GET_PRIVATE(a);
  1262. priv_b = GET_PRIVATE(b);
  1263. same_book = qof_instance_get_book(QOF_INSTANCE(a)) == qof_instance_get_book(QOF_INSTANCE(b));
  1264. if ((same_book && priv_a->namespace != priv_b->namespace)
  1265. || (!same_book && safe_strcmp( gnc_commodity_namespace_get_name(priv_a->namespace),
  1266. gnc_commodity_namespace_get_name(priv_b->namespace)) != 0))
  1267. {
  1268. DEBUG ("namespaces differ: %p(%s) vs %p(%s)",
  1269. priv_a->namespace, gnc_commodity_namespace_get_name(priv_a->namespace),
  1270. priv_b->namespace, gnc_commodity_namespace_get_name(priv_b->namespace));
  1271. return FALSE;
  1272. }
  1273. if (safe_strcmp(priv_a->mnemonic, priv_b->mnemonic) != 0)
  1274. {
  1275. DEBUG ("mnemonics differ: %s vs %s", priv_a->mnemonic, priv_b->mnemonic);
  1276. return FALSE;
  1277. }
  1278. if (safe_strcmp(priv_a->fullname, priv_b->fullname) != 0)
  1279. {
  1280. DEBUG ("fullnames differ: %s vs %s", priv_a->fullname, priv_b->fullname);
  1281. return FALSE;
  1282. }
  1283. if (safe_strcmp(priv_a->cusip, priv_b->cusip) != 0)
  1284. {
  1285. DEBUG ("cusips differ: %s vs %s", priv_a->cusip, priv_b->cusip);
  1286. return FALSE;
  1287. }
  1288. if (priv_a->fraction != priv_b->fraction)
  1289. {
  1290. DEBUG ("fractions differ: %d vs %d", priv_a->fraction, priv_b->fraction);
  1291. return FALSE;
  1292. }
  1293. return TRUE;
  1294. }
  1295. int gnc_commodity_compare(const gnc_commodity * a, const gnc_commodity * b)
  1296. {
  1297. if (gnc_commodity_equal(a, b))
  1298. {
  1299. return 0;
  1300. }
  1301. else
  1302. {
  1303. return 1;
  1304. }
  1305. }
  1306. int gnc_commodity_compare_void(const void * a, const void * b)
  1307. {
  1308. return gnc_commodity_compare(a, b);
  1309. }
  1310. /************************************************************
  1311. * Namespace functions *
  1312. ************************************************************/
  1313. const char *
  1314. gnc_commodity_namespace_get_name (const gnc_commodity_namespace *ns)
  1315. {
  1316. if (ns == NULL)
  1317. return NULL;
  1318. return ns->name;
  1319. }
  1320. GList *
  1321. gnc_c

Large files files are truncated, but you can click here to view the full file