From 5b7353d67cfe2ad89b4ac58fc2ccb5ac55557e7e Mon Sep 17 00:00:00 2001 From: David Hampton Date: Sun, 11 May 2003 00:45:03 +0000 Subject: [PATCH] Move price quote information from the Account data structure to the Commodity data structure. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@8292 57a11ea4-9604-0410-9ed3-97b8803252fd --- ChangeLog | 41 + src/app-utils/gnc-helpers.c | 41 + src/app-utils/gnc-helpers.h | 11 + src/app-utils/gw-app-utils-spec.scm | 15 + src/backend/file/gnc-account-xml-v2.c | 32 + src/backend/file/gnc-commodity-xml-v2.c | 23 + src/backend/file/io-gncbin-r.c | 2 +- src/backend/file/io-gncxml-v2.c | 4 + src/engine/Account.c | 16 +- src/engine/Account.h | 50 +- src/engine/Scrub.c | 61 ++ src/engine/Scrub.h | 15 + src/engine/gnc-commodity.c | 211 ++++- src/engine/gnc-commodity.h | 528 ++++++++++- src/engine/gw-engine-spec.scm | 27 +- src/gnome-utils/commodity.glade | 481 ++++++++-- src/gnome-utils/dialog-account.c | 154 ---- src/gnome-utils/dialog-commodity.c | 904 ++++++++++--------- src/gnome-utils/dialog-commodity.h | 192 +++- src/gnome-utils/dialog-utils.c | 4 +- src/gnome-utils/dialog-utils.h | 4 +- src/gnome/glade/account.glade | 156 ---- src/import-export/import-commodity-matcher.c | 5 +- src/scm/price-quotes.scm | 115 +-- 24 files changed, 2072 insertions(+), 1020 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7f8721ec47..2c3272f4fa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,46 @@ 2003-05-10 David Hampton + * src/backend/file/gnc-commodity-xml-v2.c: + * src/engine/gnc-commodity.c: + * src/engine/gnc-commodity.h: + * src/gnome/glade/account.glade: + * src/gnome-utils/commodity.glade: + * src/gnome-utils/dialog-account.c: + * src/gnome-utils/dialog-commodity.c: + * src/gnome-utils/dialog-commodity.h: + * src/gnome-utils/dialog-utils.c: + * src/gnome-utils/dialog-utils.h: Migrate fields and functions + related to price quotes from the account to the commodity. + + * src/backend/file/io-gncxml-v2.c: + * src/engine/Scrub.c: + * src/engine/Scrub.h: Migrate price quote information when reading + in the data file. + + * src/app-utils/gnc-helpers.c: + * src/app-utils/gnc-helpers.h: + * src/app-utils/gw-app-utils-spec.scm: + * src/engine/gw-engine-spec.scm: + * src/scm/price-quotes.scm: The code to get quotes from F::Q now + needs to get the information from the commodity data structures, + not the Account data structures. + + * src/backend/file/gnc-account-xml-v2.c: Continue to write out + price quote information with the Account data. This allows users + to fall pack to production code without loss of information. This + code will drop out in the next release of gnucash (1.10 or 2.0). + + * src/engine/Account.c: + * src/engine/Account.h: Deprecated a couple of functions. + Continue existing hack of automatically marking cross currency + accounts for automatic quote retrieval. + + * src/backend/file/io-gncbin-r.c: Update for the new names of + deprecated functions. + + * src/import-export/import-commodity-matcher.c: Update for changed + calling conventions. + * configure.in: Restore some lost changes. 2003-05-09 Christian Stimming diff --git a/src/app-utils/gnc-helpers.c b/src/app-utils/gnc-helpers.c index a25ee5ef05..92db9f98b1 100644 --- a/src/app-utils/gnc-helpers.c +++ b/src/app-utils/gnc-helpers.c @@ -26,11 +26,13 @@ #include #include "guile-mappings.h" #include +#include #include "gnc-engine-util.h" #include "engine-helpers.h" #include "gnc-helpers.h" #include "gnc-ui-util.h" +#include "global-options.h" static short module = MOD_SX; @@ -118,6 +120,45 @@ gnc_printinfo_p(SCM info_scm) return retval; } +/* This is a scaled down version of the routine that would be needed + * to fully convert a gnc-commodity to a scheme data structure. In an + * attempt to optimize the speed of price quote retrieval, this + * routine only converts the fields that price-quotes.scm uses. Since + * it converts these fields all at once, it should prevent multiple + * transitions back and forth from Scheme to C (via g-wrap) to extract + * the data from a pointers to a gnc-commodity (the older method). + * This is *not* a reversible conversion as it drops data. + * + * When this routine was written, gnucash retrieved all quotes into + * the user's default currency. (Did earlier version do any + * different?) This routine inserts that default currency into the + * returned structure as another optimization. + */ +SCM +gnc_quoteinfo2scm(gnc_commodity *comm) +{ + const char *source, *tz; + SCM info_scm = SCM_EOL, comm_scm, def_comm_scm; + + if (!comm) + return SCM_EOL; + + source = gnc_price_source_internal2fq (gnc_commodity_get_quote_source (comm)); + tz = gnc_commodity_get_quote_tz (comm); + comm_scm = gw_wcp_assimilate_ptr (comm, scm_c_eval_string("")); + def_comm_scm = gw_wcp_assimilate_ptr (gnc_default_currency (), + scm_c_eval_string("")); + + if (tz) + info_scm = scm_cons (scm_makfrom0str (tz), info_scm); + else + info_scm = scm_cons (SCM_BOOL_F, info_scm); + info_scm = scm_cons (def_comm_scm, info_scm); + info_scm = scm_cons (comm_scm, info_scm); + info_scm = scm_cons (scm_makfrom0str (source), info_scm); + return info_scm; +} + const char * gnc_get_account_separator_string (void) { diff --git a/src/app-utils/gnc-helpers.h b/src/app-utils/gnc-helpers.h index 41b90a6f28..40c0f7dbd7 100644 --- a/src/app-utils/gnc-helpers.h +++ b/src/app-utils/gnc-helpers.h @@ -32,6 +32,17 @@ SCM gnc_printinfo2scm(GNCPrintAmountInfo info); GNCPrintAmountInfo gnc_scm2printinfo(SCM info_scm); int gnc_printinfo_p(SCM info_scm); +/** Given a pointer to a gnc-commodity data structure, build a Scheme + * list containing the data needed by the code in price-quotes.scm. + * This prevents flipping back and forth from Scheme to C while + * extracting values from a pointer. + * + * @param com A pointer to the commodity to convert. + * + * @return A pointer to a Scheme list, or SCM_EOL on error. + */ +SCM gnc_quoteinfo2scm(gnc_commodity *com); + const char * gnc_get_account_separator_string (void); SCM gnc_parse_amount_helper (const char * string, gboolean monetary); diff --git a/src/app-utils/gw-app-utils-spec.scm b/src/app-utils/gw-app-utils-spec.scm index 3933e65719..6788839598 100644 --- a/src/app-utils/gw-app-utils-spec.scm +++ b/src/app-utils/gw-app-utils-spec.scm @@ -42,6 +42,11 @@ '(c-var " = gnc_scm2printinfo(" scm-var ");\n") '(scm-var " = gnc_printinfo2scm(" c-var ");\n")) + (gw:wrap-simple-type ws ' "gnc_commodity *" + '("FALSE") + '(c-var " = NULL;\n") + '(scm-var " = gnc_quoteinfo2scm(" c-var ");\n")) + (gw:wrap-as-wct ws ' "GNCOptionChangeCallback" "const GNCOptionChangeCallback") @@ -462,6 +467,16 @@ determines formatting details.") '(((gw:glist-of ( callee-owned) callee-owned) choices)) "Takes a list of installed Finance::Quote souces and records it internally.") + (gw:wrap-function + ws + 'gnc:commodity-table-get-quotable-commodities-info + '(gw:glist-of caller-owned) + "gnc_commodity_table_get_quotable_commodities" + '(( table) + (( caller-owned const) namespace)) + "Return a list of all the quotable commodities in a given namespace in the table.") + + (gw:wrap-function ws 'gnc:account-separator-char diff --git a/src/backend/file/gnc-account-xml-v2.c b/src/backend/file/gnc-account-xml-v2.c index 90beec4786..81f8cec832 100644 --- a/src/backend/file/gnc-account-xml-v2.c +++ b/src/backend/file/gnc-account-xml-v2.c @@ -119,6 +119,38 @@ gnc_account_dom_tree_create(Account *act, gboolean exporting) if(kf) { xmlNodePtr kvpnode = kvp_frame_to_dom_tree(act_slots_string, kf); +#if ((GNUCASH_MAJOR_VERSION == 1) && (GNUCASH_MINOR_VERSION < 10)) + { + /* Temporary backwards compatability hack. Create kvp slot + * information for the stock quote data in case the user has + * to fall back to the production code. */ + xmlNodePtr slot_node, val_node; + gnc_commodity *com; + const gchar *tz; + + com = xaccAccountGetCommodity(act); + if (com && + !gnc_commodity_is_iso(com) && + gnc_commodity_get_quote_flag(com)) { + if (!kvpnode) + kvpnode= xmlNewNode(NULL, act_slots_string); + + slot_node = xmlNewChild(kvpnode, NULL, "slot", NULL); + xmlNewTextChild(slot_node, NULL, "slot:key", "old-price-source"); + val_node = xmlNewTextChild(slot_node, NULL, "slot:value", + gnc_commodity_get_quote_source(com)); + xmlSetProp(val_node, "type", "string"); + + tz = gnc_commodity_get_quote_tz(com); + if (tz) { + slot_node = xmlNewChild(kvpnode, NULL, "slot", NULL); + xmlNewTextChild(slot_node, NULL, "slot:key", "old-quote-tz"); + val_node = xmlNewTextChild(slot_node, NULL, "slot:value", tz); + xmlSetProp(val_node, "type", "string"); + } + } + } +#endif if(kvpnode) { xmlAddChild(ret, kvpnode); diff --git a/src/backend/file/gnc-commodity-xml-v2.c b/src/backend/file/gnc-commodity-xml-v2.c index 251f561f56..cdb5ed630f 100644 --- a/src/backend/file/gnc-commodity-xml-v2.c +++ b/src/backend/file/gnc-commodity-xml-v2.c @@ -56,10 +56,14 @@ const gchar *commodity_version_string = "2.0.0"; #define cmdty_name "cmdty:name" #define cmdty_xcode "cmdty:xcode" #define cmdty_fraction "cmdty:fraction" +#define cmdty_get_quotes "cmdty:get_quotes" +#define cmdty_quote_source "cmdty:quote_source" +#define cmdty_quote_tz "cmdty:quote_tz" xmlNodePtr gnc_commodity_dom_tree_create(const gnc_commodity *com) { + const char *string; xmlNodePtr ret; ret = xmlNewNode(NULL, gnc_commodity_string); @@ -88,6 +92,15 @@ gnc_commodity_dom_tree_create(const gnc_commodity *com) xmlAddChild(ret, int_to_dom_tree(cmdty_fraction, gnc_commodity_get_fraction(com))); + if (gnc_commodity_get_quote_flag(com)) + xmlNewChild(ret, NULL, cmdty_get_quotes, NULL); + string = gnc_commodity_get_quote_source(com); + if (string) + xmlAddChild(ret, text_to_dom_tree(cmdty_quote_source, string)); + string = gnc_commodity_get_quote_tz(com); + if (string) + xmlAddChild(ret, text_to_dom_tree(cmdty_quote_tz, string)); + return ret; } @@ -104,6 +117,8 @@ struct com_char_handler com_handlers[] = { { cmdty_id, gnc_commodity_set_mnemonic }, { cmdty_name, gnc_commodity_set_fullname }, { cmdty_xcode, gnc_commodity_set_exchange_code }, + { cmdty_quote_source, gnc_commodity_set_quote_source }, + { cmdty_quote_tz, gnc_commodity_set_quote_tz }, { 0, 0 } }; @@ -122,6 +137,14 @@ set_commodity_value(xmlNodePtr node, gnc_commodity* com) } xmlFree (string); } + else if(safe_strcmp(node->name, cmdty_get_quotes) == 0) + { + char *string; + + string = xmlNodeGetContent (node->xmlChildrenNode); + gnc_commodity_set_quote_flag(com, TRUE); + xmlFree (string); + } else { struct com_char_handler *mark; diff --git a/src/backend/file/io-gncbin-r.c b/src/backend/file/io-gncbin-r.c index 829cc7617a..d152beb0b7 100644 --- a/src/backend/file/io-gncbin-r.c +++ b/src/backend/file/io-gncbin-r.c @@ -871,7 +871,7 @@ readAccInfo(int fd, Account *acc, int token) { if ((acc_type == STOCK) || (acc_type == MUTUAL)) { const char *tmp = readString( fd, token ); if(NULL == tmp) return(FALSE); - if(strlen(tmp) > 0) xaccAccountSetPriceSrc(acc, tmp); + if(strlen(tmp) > 0) dxaccAccountSetPriceSrc(acc, tmp); free((char *) tmp); } return(TRUE); diff --git a/src/backend/file/io-gncxml-v2.c b/src/backend/file/io-gncxml-v2.c index 8dfd7c29ec..d0bf6a3ae1 100644 --- a/src/backend/file/io-gncxml-v2.c +++ b/src/backend/file/io-gncxml-v2.c @@ -713,6 +713,10 @@ gnc_session_load_from_xml_file_v2(GNCSession *session) /* Mark the book as saved */ gnc_book_mark_saved (book); + /* fix price quote sources */ + xaccGroupScrubQuoteSources (gnc_book_get_group(book), + gnc_book_get_commodity_table(book)); + /* Fix account and transaction commodities */ xaccGroupScrubCommodities (gnc_book_get_group(book)); diff --git a/src/engine/Account.c b/src/engine/Account.c index 5125d5be71..34b614539e 100644 --- a/src/engine/Account.c +++ b/src/engine/Account.c @@ -1489,6 +1489,11 @@ xaccAccountSetCommodity (Account * acc, gnc_commodity * com) } acc->core_dirty = TRUE; xaccAccountCommitEdit(acc); + if (gnc_commodity_is_iso(com)) { + /* compatability hack - Gnucash 1.8 gets currency quotes when a + non-default currency is assigned to an account. */ + gnc_commodity_set_quote_flag(com, TRUE); + } } void @@ -2894,7 +2899,7 @@ xaccAccountSetLastNum (Account *account, const char *num) \********************************************************************/ void -xaccAccountSetPriceSrc(Account *acc, const char *src) +dxaccAccountSetPriceSrc(Account *acc, const char *src) { if(!acc) return; @@ -2917,7 +2922,7 @@ xaccAccountSetPriceSrc(Account *acc, const char *src) \********************************************************************/ const char* -xaccAccountGetPriceSrc(Account *acc) +dxaccAccountGetPriceSrc(Account *acc) { GNCAccountType t; if(!acc) return NULL; @@ -2935,10 +2940,9 @@ xaccAccountGetPriceSrc(Account *acc) \********************************************************************/ void -xaccAccountSetQuoteTZ(Account *acc, const char *tz) +dxaccAccountSetQuoteTZ(Account *acc, const char *tz) { if(!acc) return; - if(!tz) return; xaccAccountBeginEdit(acc); { @@ -2947,7 +2951,7 @@ xaccAccountSetQuoteTZ(Account *acc, const char *tz) if((t == STOCK) || (t == MUTUAL) || (t == CURRENCY)) { kvp_frame_set_slot_nc(acc->kvp_data, "old-quote-tz", - kvp_value_new_string(tz)); + tz ? kvp_value_new_string(tz) : NULL); mark_account (acc); } } @@ -2959,7 +2963,7 @@ xaccAccountSetQuoteTZ(Account *acc, const char *tz) \********************************************************************/ const char* -xaccAccountGetQuoteTZ(Account *acc) +dxaccAccountGetQuoteTZ(Account *acc) { GNCAccountType t; if(!acc) return NULL; diff --git a/src/engine/Account.h b/src/engine/Account.h index a50bc00a55..772ecab1d5 100644 --- a/src/engine/Account.h +++ b/src/engine/Account.h @@ -232,16 +232,20 @@ const char * xaccAccountGetLastNum (Account *account); */ char * xaccAccountGetFullName (Account *account, const char separator); -/** The xaccAccountSetPriceSrc() and xaccAccountGetPriceSrc() routines - are used to get and set a string that identifies the Finance::Quote - backend that should be used to retrieve online prices. See - price-quotes.scm for more information.*/ -void xaccAccountSetPriceSrc (Account *account, const char *src); -/** The xaccAccountSetPriceSrc() and xaccAccountGetPriceSrc() routines - are used to get and set a string that identifies the Finance::Quote - backend that should be used to retrieve online prices. See - price-quotes.scm for more information.*/ -const char * xaccAccountGetPriceSrc (Account *account); +/** Set a string that identifies the Finance::Quote backend that + * should be used to retrieve online prices. See price-quotes.scm + * for more information + * + * @deprecated Price quote information is now stored on the + * commodity, not the account. */ +void dxaccAccountSetPriceSrc (Account *account, const char *src); +/** Get a string that identifies the Finance::Quote backend that + * should be used to retrieve online prices. See price-quotes.scm + * for more information. + * + * @deprecated Price quote information is now stored on the + * commodity, not the account. */ +const char * dxaccAccountGetPriceSrc (Account *account); /** Returns a per-account flag: Prior to reconciling an account which charges or pays interest, this flag tells whether to prompt the @@ -717,18 +721,20 @@ void DxaccAccountSetCurrencySCU (Account *account, int frac); * it. */ int DxaccAccountGetCurrencySCU (Account *account); -/** xaccAccountGetQuoteTZ() and xaccAccountSetQuoteTZ() set the - timezone to be used when interpreting the results from a given - Finance::Quote backend. Unfortunately, the upstream sources don't - label their output, so the user has to specify this bit. - - @deprecated Since prices are not going to be stored in the accounts in the - future, and since the whole commodities infrastructure is changing - radically as we speak, this interface is not long for this - world. */ -void xaccAccountSetQuoteTZ (Account *account, const char *tz); -/** @deprecated */ -const char * xaccAccountGetQuoteTZ (Account *account); +/** Set the timezone to be used when interpreting the results from a + * given Finance::Quote backend. Unfortunately, the upstream sources + * don't label their output, so the user has to specify this bit. + * + * @deprecated Price quote information is now stored on the + * commodity, not the account. */ +void dxaccAccountSetQuoteTZ (Account *account, const char *tz); +/** Get the timezone to be used when interpreting the results from a + * given Finance::Quote backend. Unfortunately, the upstream sources + * don't label their output, so the user has to specify this bit. + * + * @deprecated Price quote information is now stored on the + * commodity, not the account. */ +const char * dxaccAccountGetQuoteTZ (Account *account); /**@}*/ diff --git a/src/engine/Scrub.c b/src/engine/Scrub.c index bd324ec39f..c06fffda1c 100644 --- a/src/engine/Scrub.c +++ b/src/engine/Scrub.c @@ -571,6 +571,67 @@ xaccGroupScrubCommodities (AccountGroup *group) /* ================================================================ */ +static gboolean +check_quote_source (gnc_commodity *com, gpointer data) +{ + gboolean *commodity_has_quote_src = (gboolean *)data; + if (com && !gnc_commodity_is_iso(com)) + *commodity_has_quote_src |= gnc_commodity_get_quote_flag(com); + return TRUE; +} + +static gpointer +move_quote_source (Account *account, gpointer data) +{ + gnc_commodity *com; + gboolean new_style = GPOINTER_TO_INT(data); + const char *source, *tz; + + com = xaccAccountGetCommodity(account); + if (!com) + return NULL; + + if (!new_style) { + source = dxaccAccountGetPriceSrc(account); + if (!source || !*source) + return NULL; + tz = dxaccAccountGetQuoteTZ(account); + + PINFO("to %8s from %s", gnc_commodity_get_mnemonic(com), + xaccAccountGetName(account)); + gnc_commodity_set_quote_flag(com, TRUE); + gnc_commodity_set_quote_source(com, source); + gnc_commodity_set_quote_tz(com, tz); + } + + dxaccAccountSetPriceSrc(account, NULL); + dxaccAccountSetQuoteTZ(account, NULL); + return NULL; +} + + +void +xaccGroupScrubQuoteSources (AccountGroup *group, gnc_commodity_table *table) +{ + ENTER(" "); + gboolean new_style = FALSE; + + if (!group || !table) { + LEAVE("Oops") + return; + } + + gnc_commodity_table_foreach_commodity (table, check_quote_source, &new_style); + + xaccAccountGroupBeginEdit (group); + xaccGroupForEachAccount (group, move_quote_source, + GINT_TO_POINTER(new_style), TRUE); + xaccAccountGroupCommitEdit (group); + LEAVE("Migration done"); +} + +/* ================================================================ */ + Account * xaccScrubUtilityGetOrMakeAccount (AccountGroup *root, gnc_commodity * currency, const char *name_root) diff --git a/src/engine/Scrub.h b/src/engine/Scrub.h index e54dfc9798..13393eb18e 100644 --- a/src/engine/Scrub.h +++ b/src/engine/Scrub.h @@ -105,4 +105,19 @@ void xaccAccountScrubCommodity (Account *account); * of all accounts & transactions in the group. */ void xaccGroupScrubCommodities (AccountGroup *group); +/** This routine will migrate the information about price quote + * sources from the account data structures to the commodity data + * structures. It first checks to see if this is necessary since, + * for the time being, the quote information will still be written + * out as part of the account. Just in case anyone needs to fall + * back from CVS to a production version of code. + * + * @param group A pointer to the account group containing all + * accounts in the current book. + * + * @param table A pointer to the commodity table for the current + * book. + */ +void xaccGroupScrubQuoteSources (AccountGroup *group, gnc_commodity_table *table); + #endif /* XACC_SCRUB_H */ diff --git a/src/engine/gnc-commodity.c b/src/engine/gnc-commodity.c index 3ae988944b..b135f663c6 100644 --- a/src/engine/gnc-commodity.c +++ b/src/engine/gnc-commodity.c @@ -51,6 +51,10 @@ struct gnc_commodity_s { int fraction; char * unique_name; gint16 mark; /* user-defined mark, handy for traversals */ + + gboolean quote_flag; /* user wants price quotes */ + char * quote_source; /* current/old source of quotes */ + char * quote_tz; }; struct gnc_commodity_namespace_s { @@ -116,12 +120,10 @@ gnc_commodity_destroy(gnc_commodity * cm) { if(!cm) return; + /* Set at creation */ g_free(cm->fullname); cm->fullname = NULL; - g_free(cm->printname); - cm->printname = NULL; - g_free(cm->namespace); cm->namespace = NULL; @@ -131,6 +133,17 @@ gnc_commodity_destroy(gnc_commodity * cm) g_free(cm->mnemonic); cm->mnemonic = NULL; + /* Set through accessor functions */ + g_free(cm->quote_source); + cm->quote_source = NULL; + + g_free(cm->quote_tz); + cm->quote_tz = NULL; + + /* Automatically generated */ + g_free(cm->printname); + cm->printname = NULL; + g_free(cm->unique_name); cm->unique_name = NULL; @@ -232,6 +245,41 @@ gnc_commodity_get_mark(const gnc_commodity * cm) return cm->mark; } +/******************************************************************** + * gnc_commodity_get_quote_flag + ********************************************************************/ + +gboolean +gnc_commodity_get_quote_flag(const gnc_commodity *cm) +{ + if(!cm) return FALSE; + return (cm->quote_flag); +} + +/******************************************************************** + * gnc_commodity_get_quote_source + ********************************************************************/ + +const char* +gnc_commodity_get_quote_source(const gnc_commodity *cm) +{ + if(!cm) return NULL; + if (!cm->quote_source && gnc_commodity_is_iso(cm)) + return "CURRENCY"; + return cm->quote_source; +} + +/******************************************************************** + * gnc_commodity_get_quote_tz + ********************************************************************/ + +const char* +gnc_commodity_get_quote_tz(const gnc_commodity *cm) +{ + if(!cm) return NULL; + return cm->quote_tz; +} + /******************************************************************** * gnc_commodity_set_mnemonic ********************************************************************/ @@ -309,7 +357,7 @@ gnc_commodity_set_fraction(gnc_commodity * cm, int fraction) } /******************************************************************** - * gnc_commodity_get_mark + * gnc_commodity_set_mark ********************************************************************/ void @@ -319,6 +367,65 @@ gnc_commodity_set_mark(gnc_commodity * cm, gint16 mark) cm->mark = mark; } +/******************************************************************** + * gnc_commodity_set_quote_flag + ********************************************************************/ + +void +gnc_commodity_set_quote_flag(gnc_commodity *cm, const gboolean flag) +{ + ENTER ("(cm=%p, flag=%d)", cm, flag); + + if(!cm) return; + cm->quote_flag = flag; + LEAVE(" "); +} + +/******************************************************************** + * gnc_commodity_set_quote_source + ********************************************************************/ + +void +gnc_commodity_set_quote_source(gnc_commodity *cm, const char *src) +{ + ENTER ("(cm=%p, src=%s)", cm, src); + + if(!cm) return; + if (cm->quote_source) { + g_free(cm->quote_source); + cm->quote_source = NULL; + } + + if (src && *src) + cm->quote_source = g_strdup(src); + LEAVE(" "); +} + +/******************************************************************** + * gnc_commodity_set_quote_tz + ********************************************************************/ + +void +gnc_commodity_set_quote_tz(gnc_commodity *cm, const char *tz) +{ + ENTER ("(cm=%p, tz=%s)", cm, tz); + + if(!cm) return; + + if (cm->quote_tz) { + g_free(cm->quote_tz); + cm->quote_tz = NULL; + } + + if (tz && *tz) + cm->quote_tz = g_strdup(tz); + LEAVE(" "); +} + +/********************************************************************\ +\********************************************************************/ + + /******************************************************************** * gnc_commodity_equiv * are two commodities the same? @@ -553,7 +660,9 @@ gnc_commodity_table_insert(gnc_commodity_table * table, gnc_commodity_set_fraction (c, gnc_commodity_get_fraction (comm)); gnc_commodity_set_exchange_code (c, gnc_commodity_get_exchange_code (comm)); - + gnc_commodity_set_quote_flag (c, gnc_commodity_get_quote_flag (comm)); + gnc_commodity_set_quote_source (c, gnc_commodity_get_quote_source (comm)); + gnc_commodity_set_quote_tz (c, gnc_commodity_get_quote_tz (comm)); gnc_commodity_destroy (comm); return c; @@ -602,7 +711,7 @@ gnc_commodity_table_remove(gnc_commodity_table * table, /******************************************************************** * gnc_commodity_table_has_namespace - * see if any commodities in the namespace exist + * see if the commodities namespace exists. May have zero commodities. ********************************************************************/ int @@ -690,16 +799,65 @@ gnc_commodity_table_get_commodities(const gnc_commodity_table * table, { gnc_commodity_namespace * ns = NULL; - if(table) { - ns = g_hash_table_lookup(table->table, (gpointer)namespace); - } - - if(ns) { - return g_hash_table_values(ns->table); - } - else { + if (!table) return NULL; + + ns = g_hash_table_lookup(table->table, (gpointer)namespace); + if (!ns) + return NULL; + + return g_hash_table_values(ns->table); +} + +/******************************************************************** + * gnc_commodity_table_get_quotable_commodities + * list commodities in a given namespace that get price quotes + ********************************************************************/ + +static void +get_quotables_helper1(gpointer key, gpointer value, gpointer data) +{ + gnc_commodity *comm = value; + GList ** l = data; + + if (!comm->quote_flag) + return; + *l = g_list_prepend(*l, value); +} + +static gboolean +get_quotables_helper2 (gnc_commodity *comm, gpointer data) +{ + GList ** l = data; + + if (!comm->quote_flag) + return TRUE; + *l = g_list_prepend(*l, comm); + return TRUE; +} + +GList * +gnc_commodity_table_get_quotable_commodities(const gnc_commodity_table * table, + const char * namespace) +{ + gnc_commodity_namespace * ns = NULL; + GList * l = NULL; + + ENTER("table=%p, namespace=%s", table, namespace); + if (!table) + return NULL; + + if (namespace && *namespace) { + ns = g_hash_table_lookup(table->table, (gpointer)namespace); + DEBUG("ns=%p", ns); + if (ns) + g_hash_table_foreach(ns->table, &get_quotables_helper1, (gpointer) &l); + } else { + gnc_commodity_table_foreach_commodity(table, get_quotables_helper2, + (gpointer) &l); } + LEAVE("list head %p", l); + return l; } /******************************************************************** @@ -764,29 +922,6 @@ gnc_commodity_table_delete_namespace(gnc_commodity_table * table, } } -void -gnc_commodity_table_remove_non_iso (gnc_commodity_table *t) -{ - GList *namespaces; - GList *node; - - if (!t) return; - - namespaces = gnc_commodity_table_get_namespaces (t); - - for (node = namespaces; node; node = node->next) - { - char *ns = node->data; - - if (safe_strcmp (ns, GNC_COMMODITY_NS_ISO) == 0) - continue; - - gnc_commodity_table_delete_namespace (t, ns); - } - - g_list_free (namespaces); -} - /******************************************************************** * gnc_commodity_table_foreach_commodity * call user-defined function once for every commodity in every @@ -819,7 +954,7 @@ iter_namespace (gpointer key, gpointer value, gpointer user_data) } gboolean -gnc_commodity_table_foreach_commodity (gnc_commodity_table * tbl, +gnc_commodity_table_foreach_commodity (const gnc_commodity_table * tbl, gboolean (*f)(gnc_commodity *, gpointer), gpointer user_data) { diff --git a/src/engine/gnc-commodity.h b/src/engine/gnc-commodity.h index 3d767890ca..41779e39f3 100644 --- a/src/engine/gnc-commodity.h +++ b/src/engine/gnc-commodity.h @@ -1,5 +1,5 @@ /******************************************************************** - * gnc-commodity.h -- api for tradable commodities (incl. currency) * + * gnc-commodity.h -- API for tradable commodities (incl. currency) * * Copyright (C) 2000 Bill Gribble * * * * This program is free software; you can redistribute it and/or * @@ -21,12 +21,39 @@ * * *******************************************************************/ +/** @addtogroup Engine + @{ */ +/** @file gnc-commodity.h + * + * This file contains the functions to manipulate two different + * objects. These are an object of type gnc_commodity, and an object + * of type gnc_commodity_table. The gnc_commodity object corresponds + * one-to-one with some type of tradable commodity; a currency, a + * stock, a mutual fund, etc. The gnc_commodity_table object is a + * database containing objects of type gnc_commodity. + * + * @brief Commodity handling public routines + * @author Copyright (C) 2000 Bill Gribble + * @author Copyright (C) 2001 Linas Vepstas + */ + #ifndef GNC_COMMODITY_H #define GNC_COMMODITY_H #include #include "gnc-engine.h" +/** The commodity namespace definitions are used to tag a commodity by + * its type, or a stocks by the exchange where it is traded. + * + * The LEGACY name is only used by the file i/o routines, and is + * converted to another commodity namespace before it is seen by the + * rest of the system. The ISO namespace represents currencies. + * With the exception of the NASDAQ namespace (which is used once in + * the binary importer) the rest of the namespace declarations are + * only used to populate an option menu in the commodity selection + * window. + */ #define GNC_COMMODITY_NS_LEGACY "GNC_LEGACY_CURRENCIES" #define GNC_COMMODITY_NS_ISO "ISO4217" #define GNC_COMMODITY_NS_NASDAQ "NASDAQ" @@ -36,59 +63,373 @@ #define GNC_COMMODITY_NS_AMEX "AMEX" #define GNC_COMMODITY_NS_ASX "ASX" -/* gnc_commodity functions */ + + +/** @name Commodity Creation */ +/** @{ */ + +/** Create a new commodity. This function allocates a new commodity + * data structure, populates it with the data provided, and then + * generates the dynamic names that exist as part of a commodity. + * + * @note This function does not check to see if the commodity exists + * before adding a new commodity. + * + * @param fullname The complete name of this commodity. E.G. "Acme + * Systems, Inc." + * + * @param namespace An aggregation of commodities. E.G. ISO4217, + * Nasdaq, Downbelow, etc. + * + * @param mnemonic An abbreviation for this stock. For publicly + * traced stocks, this field should contain the stock ticker + * symbol. This field is used to get online price quotes, so it must + * match the stock ticker symbol used by the exchange where you want + * to get automatic stock quote updates. E.G. ACME, ACME.US, etc. + * + * @param exchange_code A string containing the CUSIP code or similar + * UNIQUE code for this commodity. The stock ticker is NOT + * appropriate. + * + * @param fraction The smallest division of this commodity + * allowed. I.E. If this is 1, then the commodity must be traded in + * whole units; if 100 then the commodity may be traded in 0.01 + * units, etc. + * + * @return A pointer to the new commodity. + */ gnc_commodity * gnc_commodity_new(const char * fullname, const char * namespace, const char * mnemonic, const char * exchange_code, int fraction); +/** Destroy a commodity. Release all memory attached to this data structure. + * @note This function does not (can not) check to see if the + * commodity is referenced anywhere. + * @param cm The commodity to destroy. + */ void gnc_commodity_destroy(gnc_commodity * cm); +/** @} */ + + +/** @name Commodity Accessor Routines - Get */ +/** @{ */ + +/** Retrieve the mnemonic for the specified commodity. This will be a + * pointer to a null terminated string of the form "ACME", "QWER", + * etc. + * + * @param cm A pointer to a commodity data structure. + * + * @return A pointer to the mnemonic for this commodity. This string + * is owned by the engine and should not be freed by the caller. + */ const char * gnc_commodity_get_mnemonic(const gnc_commodity * cm); + +/** Retrieve the namespace for the specified commodity. This will be + * a pointer to a null terminated string of the form "AMEX", + * "NASDAQ", etc. + * + * @param cm A pointer to a commodity data structure. + * + * @return A pointer to the namespace for this commodity. This string + * is owned by the engine and should not be freed by the caller. + */ const char * gnc_commodity_get_namespace(const gnc_commodity * cm); + +/** Retrieve the full name for the specified commodity. This will be + * a pointer to a null terminated string of the form "Acme Systems, + * Inc.", etc. + * + * @param cm A pointer to a commodity data structure. + * + * @return A pointer to the full name for this commodity. This string + * is owned by the engine and should not be freed by the caller. + */ const char * gnc_commodity_get_fullname(const gnc_commodity * cm); + +/** Retrieve the 'print' name for the specified commodity. This will + * be a pointer to a null terminated string of the form "Acme + * Systems, Inc. (ACME)", etc. + * + * @param cm A pointer to a commodity data structure. + * + * @return A pointer to the print name for this commodity. This + * string is owned by the engine and should not be freed by the + * caller. + */ const char * gnc_commodity_get_printname(const gnc_commodity * cm); + +/** Retrieve the 'exchange code' for the specified commodity. This + * will be a pointer to a null terminated string of the form + * "AXQ14728", etc. This field is often used when presenting + * information to the user. + * + * @note This is a unique code that specifies a particular item or + * set of shares of a commodity, not a code that specifies a stock + * exchange. That is the namespace field. + * + * @param cm A pointer to a commodity data structure. + * + * @return A pointer to the exchange code for this commodity. This + * string is owned by the engine and should not be freed by the + * caller. + */ const char * gnc_commodity_get_exchange_code(const gnc_commodity * cm); + +/** Retrieve the 'unique' name for the specified commodity. This will + * be a pointer to a null terminated string of the form "AMEX::ACME", + * etc. This field is often used when performing comparisons or + * other functions invisible to the user. + * + * @param cm A pointer to a commodity data structure. + * + * @return A pointer to the 'unique' name for this commodity. This + * string is owned by the engine and should not be freed by the + * caller. + */ const char * gnc_commodity_get_unique_name(const gnc_commodity * cm); + +/** Retrieve the fraction for the specified commodity. This will be + * an integer value specifying the number of fractional units that + * one of these commodities can be divided into. Should always be a + * power of 10. + * + * @param cm A pointer to a commodity data structure. + * + * @return The number of fractional units that one of these + * commodities can be divided into. + */ int gnc_commodity_get_fraction(const gnc_commodity * cm); + +/** Retrieve the 'mark' field for the specified commodity. + * + * @note This is a private field used by the Postgres back end. + * + * @param cm A pointer to a commodity data structure. + * + * @return The value of the mark field. + */ gint16 gnc_commodity_get_mark(const gnc_commodity * cm); +/** Retrieve the automatic price quote flag for the specified + * commodity. This flag indicates whether stock quotes should be + * retrieved for the specified stock. + * + * @param cm A pointer to a commodity data structure. + * + * @return TRUE if quotes should be pulled for this commodity, FALSE + * otherwise. + */ +gboolean gnc_commodity_get_quote_flag(const gnc_commodity *cm); + +/** Retrieve the automatic price quote source for the specified + * commodity. This will be a pointer to a null terminated string of + * the form "Yahoo (Asia)", etc. + * + * @param cm A pointer to a commodity data structure. + * + * @return A pointer to the price quote source for this commodity. + * This string is owned by the engine and should not be freed by the + * caller. + */ +const char* gnc_commodity_get_quote_source(const gnc_commodity *cm); + +/** Retrieve the automatic price quote timezone for the specified + * commodity. This will be a pointer to a null terminated string of + * the form "America/New_York", etc. + * + * @param cm A pointer to a commodity data structure. + * + * @return A pointer to the price quote timezone for this commodity. + * This string is owned by the engine and should not be freed by the + * caller. + */ +const char* gnc_commodity_get_quote_tz(const gnc_commodity *cm); +/** @} */ + + + +/** @name Commodity Accessor Routines - Set */ +/** @{ */ + +/** Set the mnemonic for the specified commodity. This should be a + * pointer to a null terminated string of the form "ACME", "QWER", + * etc. + * + * @param cm A pointer to a commodity data structure. + * + * @param mnemonic A pointer to the mnemonic for this commodity. + * This string belongs to the caller and will be duplicated by the + * engine. + */ void gnc_commodity_set_mnemonic(gnc_commodity * cm, const char * mnemonic); + +/** Set the namespace for the specified commodity. This should be a + * pointer to a null terminated string of the form "AMEX", "NASDAQ", + * etc. + * + * @param cm A pointer to a commodity data structure. + * + * @param namespace A pointer to the namespace for this commodity. + * This string belongs to the caller and will be duplicated by the + * engine. + */ void gnc_commodity_set_namespace(gnc_commodity * cm, const char * namespace); + +/** Set the full name for the specified commodity. This should be + * a pointer to a null terminated string of the form "Acme Systems, + * Inc.", etc. + * + * @param cm A pointer to a commodity data structure. + * + * @param fullname A pointer to the full name for this commodity. + * This string belongs to the caller and will be duplicated by the + * engine. + */ void gnc_commodity_set_fullname(gnc_commodity * cm, const char * fullname); + +/** Set the 'exchange code' for the specified commodity. This should + * be a pointer to a null terminated string of the form "AXQ14728", + * etc. + * + * @note This is a unique code that specifies a particular item or + * set of shares of a commodity, not a code that specifies a stock + * exchange. That is the namespace field. + * + * @param cm A pointer to a commodity data structure. + * + * @param exchange_code A pointer to the full name for this commodity. This + * string belongs to the caller and will be duplicated by the engine. + */ void gnc_commodity_set_exchange_code(gnc_commodity * cm, const char * exchange_code); + +/** Set the fraction for the specified commodity. This should be + * an integer value specifying the number of fractional units that + * one of these commodities can be divided into. Should always be a + * power of 10. + * + * @param cm A pointer to a commodity data structure. + * + * @param smallest_fraction The number of fractional units that one of + * these commodities can be divided into. + */ void gnc_commodity_set_fraction(gnc_commodity * cm, int smallest_fraction); + +/** Set the 'mark' field for the specified commodity. + * + * @note This is a private field used by the Postgres back end. + * + * @param cm A pointer to a commodity data structure. + * + * @param mark The new value of the mark field. + */ void gnc_commodity_set_mark(gnc_commodity * cm, gint16 mark); -/** The gnc_commodity_equiv() routine returns TRUE if the two commodities are - * equivalent. Commodities are equivalent if they have the same namespace - * and mnemonic. Equivalent commodities my belong to different exchanges, - * may have different fullnames, and may have different fractionals. +/** Set the automatic price quote flag for the specified commodity. + * This flag indicates whether stock quotes should be retrieved for + * the specified stock. + * + * @param cm A pointer to a commodity data structure. + * + * @param flag TRUE if quotes should be pulled for this commodity, FALSE + * otherwise. + */ +void gnc_commodity_set_quote_flag(gnc_commodity *cm, const gboolean flag); + +/** Set the automatic price quote source for the specified commodity. + * This should be a pointer to a null terminated string of the form + * "Yahoo (Asia)", etc. Legal values can be found in the + * quote_sources array in the file gnc-ui-util.c. + * + * @param cm A pointer to a commodity data structure. + * + * @return A pointer to the price quote source for this commodity. + * This string belongs to the caller and will be duplicated by the + * engine. + */ +void gnc_commodity_set_quote_source(gnc_commodity *cm, const char *src); + +/** Set the automatic price quote timezone for the specified + * commodity. This should be a pointer to a null terminated string + * of the form "America/New_York", etc. Legal values can be found in + * the known_timezones array in the file dialog-util.c. + * + * @param cm A pointer to a commodity data structure. + * + * @return A pointer to the price quote timezone for this commodity. + * This string belongs to the caller and will be duplicated by the + * engine. + */ +void gnc_commodity_set_quote_tz(gnc_commodity *cm, const char *tz); +/** @} */ + + + +/** @name Commodity Comparison */ +/** @{ */ + +/** This routine returns TRUE if the two commodities are equivalent. + * Commodities are equivalent if they have the same namespace and + * mnemonic. Equivalent commodities may belong to different + * exchanges, may have different fullnames, and may have different + * fractions. */ gboolean gnc_commodity_equiv(const gnc_commodity * a, const gnc_commodity * b); -/** The gnc_commodity_equal() routine returns TRUE if the two commodities are - * equal. Commodities are equal if they have the same namespace, mnemonic, - * fullname, exchange and fraction. +/** This routine returns TRUE if the two commodities are equal. + * Commodities are equal if they have the same namespace, mnemonic, + * fullname, exchange private code and fraction. */ gboolean gnc_commodity_equal(const gnc_commodity * a, const gnc_commodity * b); +/** @} */ +/** @name Currency Checks */ +/** @{ */ + +/** Checks to see if the specified commodity namespace is the + * namespace for ISO 4217 currencies. + * + * @param cm The string to check. + * + * @return TRUE if the string indicates an ISO currency, FALSE otherwise. */ gboolean gnc_commodity_namespace_is_iso(const char *namespace); -gboolean gnc_commodity_is_iso(const gnc_commodity * comm); +/** Checks to see if the specified commodity is an ISO 4217 recognized currency. + * + * @param cm The commodity to check. + * + * @return TRUE if the commodity represents a currency, FALSE otherwise. */ +gboolean gnc_commodity_is_iso(const gnc_commodity * cm); +/** @} */ + + +/** @name Commodity Table Creation */ +/** @{ */ /* gnc_commodity_table functions : operate on a database of commodity * info */ gnc_commodity_table * gnc_commodity_table_new(void); void gnc_commodity_table_destroy(gnc_commodity_table * table); +/** @} */ + + +/** @name Commodity Table Comparison */ +/** @{ */ gboolean gnc_commodity_table_equal(gnc_commodity_table *t_1, gnc_commodity_table *t_2); +/** @} */ + + +/** @name Commodity Table Lookup functions */ +/** @{ */ gnc_commodity * gnc_commodity_table_lookup(const gnc_commodity_table * table, const char * namespace, const char * mnemonic); @@ -98,38 +439,169 @@ gnc_commodity_table_lookup_unique(const gnc_commodity_table *table, gnc_commodity * gnc_commodity_table_find_full(const gnc_commodity_table * t, const char * namespace, const char * fullname); +/** @} */ + + + +/** @name Commodity Table Maintenance functions */ +/** @{ */ + +/** Add a new commodity to the commodity table. This routine handles + * the cases where the commodity already exists in the database (does + * nothing), or another entries has the same namespace and mnemonic + * (updates the existing entry). + * + * @param table A pointer to the commodity table for the book. + * + * @param comm A pointer to the commodity to add. + * + * @return The added commodity. Null on error. + * + * @note The commodity pointer passed to this function should not be + * used after its return, as it may have been destroyed. Use the + * return value which is guaranteed to be valid. */ gnc_commodity * gnc_commodity_table_insert(gnc_commodity_table * table, gnc_commodity * comm); -void gnc_commodity_table_remove(gnc_commodity_table * table, - gnc_commodity * comm); -int gnc_commodity_table_has_namespace(const gnc_commodity_table * t, - const char * namespace); +/** Remove a commodity from the commodity table. If the commodity to + * remove doesn't exist, nothing happens. + * + * @param table A pointer to the commodity table for the book. + * + * @param comm A pointer to the commodity to remove. */ +void gnc_commodity_table_remove(gnc_commodity_table * table, + gnc_commodity * comm); -guint gnc_commodity_table_get_size(gnc_commodity_table* tbl); +/** Add all the standard namespaces and currencies to the commodity + * table. This routine creates the namespaces for the NYSE, NASDAQ, + * etc. It also adds all of the ISO 4217 currencies to the commodity + * table. + * + * @param table A pointer to the commodity table for the book. */ +gboolean gnc_commodity_table_add_default_data(gnc_commodity_table *table); +/** @} */ + + + +/** @name Commodity Table Namespace functions */ +/** @{ */ + +/** Return a count of the number of namespaces in the commodity table. + * This count includes both system and user defined namespaces. + * + * @return The number of namespaces. Zero if an invalid argument was + * supplied or there was an error. */ guint gnc_commodity_table_get_number_of_namespaces(gnc_commodity_table* tbl); -/* The next two functions return newly allocated lists which should - * be freed with g_list_free. */ -GList * gnc_commodity_table_get_namespaces(const gnc_commodity_table * t); -GList * gnc_commodity_table_get_commodities(const gnc_commodity_table * t, - const char * namespace); +/** Test to see if the indicated namespace exits in the commodity table. + * + * @param table A pointer to the commodity table for the current + * book. + * + * @param namespace The new namespace to check. + * + * @return 1 if the namespace exists. 0 if it doesn't exist, or the + * routine was passed a bad argument. */ +int gnc_commodity_table_has_namespace(const gnc_commodity_table * t, + const char * namespace); +/** Return a list of all namespaces in the commodity table. This + * returns both system and user defined namespaces. + * + * @return A pointer to the list of names. NULL if an invalid + * argument was supplied. + * + * @note It is the callers responsibility to free the list. */ +GList * gnc_commodity_table_get_namespaces(const gnc_commodity_table * t); + +/** This function adds a new string to the list of commodity namespaces. + * If the new namespace already exists, nothing happens. + * + * @param table A pointer to the commodity table for the current + * book. + * + * @param namespace The new namespace to be added.*/ void gnc_commodity_table_add_namespace(gnc_commodity_table * table, const char * namespace); + +/** This function deletes a string from the list of commodity namespaces. + * If the namespace does not exist, nothing happens. + * + * @param table A pointer to the commodity table for the current + * book. + * + * @param namespace The namespace to be deleted. + * + * @note This routine will destroy any commodities that exist as part + * of this namespace. Use it carefully. */ void gnc_commodity_table_delete_namespace(gnc_commodity_table * t, const char * namespace); +/** @} */ -void gnc_commodity_table_remove_non_iso (gnc_commodity_table *t); -/* gnc_commodity_table_foreach_commodity - call f once for each commodity in - * table, until and unless f returns FALSE. - */ -gboolean gnc_commodity_table_foreach_commodity(gnc_commodity_table * table, +/** @name Commodity Table Accessor functions */ +/** @{ */ + +/** Returns the number of commodities in the commodity table. + * + * @param table A pointer to the commodity table for the current + * book. + * + * @return The number of commodities in the table. 0 if there are no + * commodities, or the routine was passed a bad argument. */ +guint gnc_commodity_table_get_size(gnc_commodity_table* tbl); + +/** Return a list of all commodities in the commodity table that are + * in the given namespace. + * + * @param namespace A string indicating which commodities should be + * returned. It is a required argument. + * + * @return A pointer to the list of commodities. NULL if an invalid + * argument was supplied, or the namespace could not be found. + * + * @note It is the callers responsibility to free the list. */ +GList * gnc_commodity_table_get_commodities(const gnc_commodity_table * t, + const char * namespace); + +/** This function returns a list of commodities for which price quotes + * should be retrieved. It will scan the entire commodity table (or + * a subset) and check each commodity to see if the price_quote_flag + * field has been set. All matching commodities are queued onto a + * list, and the head of that list is returned. + * + * @param table A pointer to the commodity table for the current + * book. + * + * @param namespace Use the given namespace as a filter on the + * commodities to be returned. If non-null, only commodities in the + * specified namespace are checked. If null, all commodities are + * checked. + * + * @return A pointer to a list of commodities. NULL if invalid + * arguments were supplied or if there no commodities are flagged for + * quote retrieval. + * + * @note It is the callers responsibility to free the list. */ +GList * gnc_commodity_table_get_quotable_commodities(const gnc_commodity_table * table, + const char * namespace); + +/** Call a function once for each commodity in the commodity table. + * This table walk returns whenever the end of the table is reached, + * or the function returns FALSE. + * + * @param table A pointer to the commodity table for the current + * book. + * + * @param f The function to call for each commodity. + * + * @param user_data A pointer that is passed into the function + * unchanged by the table walk routine. */ +gboolean gnc_commodity_table_foreach_commodity(const gnc_commodity_table * table, gboolean (*f)(gnc_commodity *cm, gpointer user_data), gpointer user_data); +/** @} */ -gboolean gnc_commodity_table_add_default_data(gnc_commodity_table *table); - -#endif +#endif /* GNC_COMMODITY_H */ +/** @} */ diff --git a/src/engine/gw-engine-spec.scm b/src/engine/gw-engine-spec.scm index 0b1df3d197..21ec2b69b2 100644 --- a/src/engine/gw-engine-spec.scm +++ b/src/engine/gw-engine-spec.scm @@ -919,22 +919,6 @@ Expenses) are given numeric codes in corresponding ``number ranges.''") '(( a)) "Get the tax payer name source set on the account.") -(gw:wrap-function - ws - 'gnc:account-get-price-src - '( callee-owned const) - "xaccAccountGetPriceSrc" - '(( a)) - "Get the account's price source, if any.") - -(gw:wrap-function - ws - 'gnc:account-get-quote-tz - '( callee-owned const) - "xaccAccountGetQuoteTZ" - '(( a)) - "Get the quote source's timezone, if any.") - (gw:wrap-function ws 'gnc:account-get-children @@ -2189,7 +2173,16 @@ of having a parent transaction with which one is working...") "gnc_commodity_table_get_commodities" '(( table) (( caller-owned const) namespace)) - "Return a list of all the namespaces in the table.") + "Return a list of all the commodities in a given namespace in the table.") + +(gw:wrap-function + ws + 'gnc:commodity-table-get-quotable-commodities + '(gw:glist-of caller-owned) + "gnc_commodity_table_get_quotable_commodities" + '(( table) + (( caller-owned const) namespace)) + "Return a list of all the quotable commodities in a given namespace in the table.") (gw:wrap-function ws diff --git a/src/gnome-utils/commodity.glade b/src/gnome-utils/commodity.glade index efd642eac3..c1953fc776 100644 --- a/src/gnome-utils/commodity.glade +++ b/src/gnome-utils/commodity.glade @@ -19,15 +19,16 @@ GnomeDialog Commodity Selector Dialog + False Select currency/security GTK_WINDOW_TOPLEVEL GTK_WIN_POS_NONE - False - True - True + True + False + False False False - False + True GtkVBox @@ -60,15 +61,10 @@ GtkButton - button63 + ok_button + False True True - - clicked - gnc_ui_select_commodity_ok_cb - Commodity_Selector_Dialog - Tue, 08 Aug 2000 16:55:03 GMT - GNOME_STOCK_BUTTON_OK @@ -90,13 +86,8 @@ GtkButton button65 True + True True - - clicked - gnc_ui_select_commodity_cancel_cb - Commodity_Selector_Dialog - Tue, 08 Aug 2000 16:56:01 GMT - GNOME_STOCK_BUTTON_CANCEL @@ -240,6 +231,11 @@ GtkCombo:entry commodity_entry True + + changed + gnc_ui_select_commodity_changed_cb + Sun, 13 Apr 2003 23:10:41 GMT + False True 0 @@ -254,22 +250,23 @@ GnomeDialog Commodity Dialog - New Security + False + New Commodity GTK_WINDOW_TOPLEVEL GTK_WIN_POS_NONE - False - True + True + False True - False + True False - False + True GtkVBox GnomeDialog:vbox dialog-vbox13 False - 8 + 3 4 True @@ -295,7 +292,8 @@ GtkButton - button66 + ok_button + False True True True @@ -310,15 +308,10 @@ GtkButton - button67 + cancel_button True + True True - - clicked - gnc_ui_commodity_cancel_cb - Commodity_Dialog - Wed, 11 Apr 2001 09:03:18 GMT - GNOME_STOCK_BUTTON_CANCEL @@ -338,10 +331,12 @@ - GtkHBox - hbox63 - False - 0 + GtkFrame + commodity_info_frame + 3 + + 0 + GTK_SHADOW_ETCHED_IN 0 True @@ -349,15 +344,14 @@ - GtkVBox - vbox77 - True - 0 - - 2 - True - True - + GtkTable + table1 + 5 + 5 + 2 + False + 3 + 3 GtkLabel @@ -370,9 +364,18 @@ 0 0 - 0 - False - False + 0 + 1 + 0 + 1 + 0 + 0 + False + False + False + False + True + False @@ -387,15 +390,24 @@ 0 0 - 0 - False - False + 0 + 1 + 1 + 2 + 0 + 0 + False + False + False + False + True + False GtkLabel - label812 + namespace_label GTK_JUSTIFY_CENTER False @@ -404,9 +416,18 @@ 0 0 - 0 - False - False + 0 + 1 + 2 + 3 + 0 + 0 + False + False + False + False + True + False @@ -421,9 +442,18 @@ 0 0 - 0 - False - False + 0 + 1 + 3 + 4 + 0 + 0 + False + False + False + False + True + False @@ -438,23 +468,20 @@ 0 0 - 0 - False - False + 0 + 1 + 4 + 5 + 0 + 0 + False + False + False + False + True + False - - - - GtkVBox - vbox78 - True - 0 - - 2 - True - True - GtkEntry @@ -462,14 +489,28 @@ Enter the full name of the commodity. Example: US Dollars True True + + changed + gnc_ui_commodity_changed_cb + Wed, 16 Apr 2003 06:17:13 GMT + True True 0 - 0 - False - False + 1 + 2 + 0 + 1 + 0 + 0 + True + False + False + False + True + False @@ -478,14 +519,28 @@ mnemonic_entry Enter the ticker symbol or currency code for the commodity. Example: USD True + + changed + gnc_ui_commodity_changed_cb + Wed, 16 Apr 2003 06:17:20 GMT + True True 0 - 0 - False - False + 1 + 2 + 1 + 2 + 0 + 0 + True + False + False + False + True + False @@ -499,9 +554,18 @@ False - 0 - False - False + 1 + 2 + 2 + 3 + 0 + 0 + True + False + False + False + True + False @@ -510,6 +574,11 @@ namespace_entry Enter the type of commodity. For stocks, this is often an exchange on which the stock is traded. You can choose an existing type from the list or enter a new type with the keyboard. True + + changed + gnc_ui_commodity_changed_cb + Wed, 16 Apr 2003 06:17:30 GMT + True True 0 @@ -527,9 +596,18 @@ 0 - 0 - False - False + 1 + 2 + 3 + 4 + 0 + 0 + True + False + False + False + True + False @@ -539,9 +617,18 @@ False 0 - 0 - False - False + 1 + 2 + 4 + 5 + 0 + 0 + False + False + False + False + True + True @@ -587,6 +674,226 @@ + + + GtkFrame + price_quote_frame + 3 + + 0 + GTK_SHADOW_ETCHED_IN + + 0 + False + True + + + + GtkVBox + vbox129 + 5 + False + 3 + + + GtkHBox + finance_quote_warning + False + 0 + + 0 + False + False + + + + GtkArrow + arrow1 + GTK_ARROW_RIGHT + GTK_SHADOW_OUT + 0.5 + 0.5 + 0 + 0 + + 0 + True + True + + + + + GtkLabel + label654 + False + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkArrow + arrow2 + GTK_ARROW_LEFT + GTK_SHADOW_OUT + 0.5 + 0.5 + 0 + 0 + + 0 + True + True + + + + + + GtkCheckButton + get_quote_check + True + + toggled + gnc_ui_commodity_quote_cb + Sun, 20 Apr 2003 03:35:34 GMT + + + False + True + + 0 + False + False + + + + + GtkTable + table2 + 2 + 2 + False + 3 + 3 + + 0 + True + True + + + + GtkLabel + source_label + + GTK_JUSTIFY_RIGHT + False + 1 + 0.5 + 0 + 0 + + 0 + 1 + 0 + 1 + 0 + 0 + False + False + False + False + True + False + + + + + GtkLabel + quote_tz_label + + GTK_JUSTIFY_RIGHT + False + 1 + 0.5 + 0 + 0 + + 0 + 1 + 1 + 2 + 0 + 0 + False + False + False + False + True + False + + + + + GtkHBox + source_box + False + 0 + + 1 + 2 + 0 + 1 + 0 + 0 + True + False + False + False + True + True + + + + Placeholder + + + + + GtkHBox + quote_tz_box + False + 0 + + 1 + 2 + 1 + 2 + 0 + 0 + False + False + False + False + True + True + + + + Placeholder + + + + + diff --git a/src/gnome-utils/dialog-account.c b/src/gnome-utils/dialog-account.c index 25a627c628..bf73c2f5f1 100644 --- a/src/gnome-utils/dialog-account.c +++ b/src/gnome-utils/dialog-account.c @@ -94,15 +94,6 @@ struct _AccountWindow GtkWidget * transfer_account_frame; GtkWidget * transfer_tree; - /* These probably don't belong here anymore, but until we figure out - what we want, we'll leave them alone. */ - GtkWidget * price_quote_frame; - GtkWidget * get_quote_check; - GtkWidget * source_label; - GtkWidget * source_menu; - GtkWidget * quote_tz_label; - GtkWidget * quote_tz_menu; - GtkWidget * tax_related_button; GtkWidget * placeholder_button; @@ -206,39 +197,6 @@ gnc_account_to_ui(AccountWindow *aw) placeholder = xaccAccountGetPlaceholder (account); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aw->placeholder_button), placeholder); - - if ((STOCK != aw->type) && (MUTUAL != aw->type) && (CURRENCY != aw->type)) - return; - - { - /* we'll let GetPriceSrc handle the account type checking... */ - const char* price_src = xaccAccountGetPriceSrc (account); - - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aw->get_quote_check), - price_src != NULL); - - if (price_src && aw->type != CURRENCY) - gtk_option_menu_set_history (GTK_OPTION_MENU (aw->source_menu), - gnc_price_source_internal2enum (price_src)); - } - - { - const char* quote_tz = xaccAccountGetQuoteTZ (account); - guint pos = 0; - - if (quote_tz) - { - pos = gnc_find_timezone_menu_position(quote_tz); - if(pos == 0) - { - PWARN("Unknown price quote timezone (%s), resetting to default.", - quote_tz ? quote_tz : "(null)"); - xaccAccountSetQuoteTZ (account, NULL); - } - } - - gtk_option_menu_set_history (GTK_OPTION_MENU (aw->quote_tz_menu), pos); - } } @@ -349,50 +307,6 @@ gnc_ui_to_account(AccountWindow *aw) if (safe_strcmp (string, old_string) != 0) xaccAccountSetCode (account, string); - if ((STOCK == aw->type) || (MUTUAL == aw->type) || (CURRENCY == aw->type)) - { - gboolean get_quote; - - get_quote = gtk_toggle_button_get_active - (GTK_TOGGLE_BUTTON (aw->get_quote_check)); - - if (!get_quote) - { - if (xaccAccountGetPriceSrc (account)) - xaccAccountSetPriceSrc (account, NULL); - } - else if (CURRENCY == aw->type) - { - gint code; - - old_string = xaccAccountGetPriceSrc (account); - if (safe_strcmp ("CURRENCY", old_string) != 0) - xaccAccountSetPriceSrc (account, "CURRENCY"); - - code = gnc_option_menu_get_active (aw->quote_tz_menu); - string = gnc_timezone_menu_position_to_string(code); - old_string = xaccAccountGetQuoteTZ (account); - if (safe_strcmp (string, old_string) != 0) - xaccAccountSetQuoteTZ (account, string); - } - else if ((STOCK == aw->type) || (MUTUAL == aw->type)) - { - gint code; - - code = gnc_option_menu_get_active (aw->source_menu); - string = gnc_price_source_enum2internal (code); - old_string = xaccAccountGetPriceSrc (account); - if (safe_strcmp (string, old_string) != 0) - xaccAccountSetPriceSrc (account, string); - - code = gnc_option_menu_get_active (aw->quote_tz_menu); - string = gnc_timezone_menu_position_to_string(code); - old_string = xaccAccountGetQuoteTZ (account); - if (safe_strcmp (string, old_string) != 0) - xaccAccountSetQuoteTZ (account, string); - } - } - string = gtk_editable_get_chars (GTK_EDITABLE(aw->notes_text), 0, -1); old_string = xaccAccountGetNotes (account); if (safe_strcmp (string, old_string) != 0) @@ -1156,7 +1070,6 @@ gnc_type_list_select_cb(GtkCList * type_list, gint row, gint column, GdkEventButton * event, gpointer data) { AccountWindow * aw = data; - gboolean get_quote; gboolean sensitive; if (aw == NULL) @@ -1172,23 +1085,6 @@ gnc_type_list_select_cb(GtkCList * type_list, gint row, gint column, last_used_account_type = aw->type; - get_quote = gtk_toggle_button_get_active - (GTK_TOGGLE_BUTTON (aw->get_quote_check)); - - sensitive = (aw->type == STOCK || - aw->type == MUTUAL || - aw->type == CURRENCY); - - gtk_widget_set_sensitive(aw->get_quote_check, sensitive); - gtk_widget_set_sensitive(aw->quote_tz_menu, sensitive && get_quote); - gtk_widget_set_sensitive(aw->quote_tz_label, sensitive && get_quote); - - sensitive = (aw->type == STOCK || - aw->type == MUTUAL); - - gtk_widget_set_sensitive(aw->source_menu, sensitive && get_quote); - gtk_widget_set_sensitive(aw->source_label, sensitive && get_quote); - sensitive = (aw->type != EQUITY && aw->type != CURRENCY && aw->type != STOCK && @@ -1211,12 +1107,6 @@ gnc_type_list_unselect_cb(GtkCList * type_list, gint row, gint column, AccountWindow * aw = data; aw->type = BAD_TYPE; - - gtk_widget_set_sensitive(aw->get_quote_check, FALSE); - gtk_widget_set_sensitive(aw->source_label, FALSE); - gtk_widget_set_sensitive(aw->source_menu, FALSE); - gtk_widget_set_sensitive(aw->quote_tz_label, FALSE); - gtk_widget_set_sensitive(aw->quote_tz_menu, FALSE); } @@ -1442,29 +1332,6 @@ opening_equity_cb (GtkWidget *w, gpointer data) gtk_widget_set_sensitive (aw->transfer_account_frame, !use_equity); } -static void -get_quote_check_cb (GtkWidget *w, gpointer data) -{ - AccountWindow *aw = data; - gboolean get_quote; - gboolean sensitive; - - get_quote = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)); - - sensitive = (aw->type == STOCK || - aw->type == MUTUAL || - aw->type == CURRENCY); - - gtk_widget_set_sensitive(aw->quote_tz_label, sensitive && get_quote); - gtk_widget_set_sensitive(aw->quote_tz_menu, sensitive && get_quote); - - sensitive = (aw->type == STOCK || - aw->type == MUTUAL); - - gtk_widget_set_sensitive(aw->source_label, sensitive && get_quote); - gtk_widget_set_sensitive(aw->source_menu, sensitive && get_quote); -} - /********************************************************************\ * gnc_account_window_create * * creates a window to create a new account. * @@ -1530,27 +1397,6 @@ gnc_account_window_create(AccountWindow *aw) aw->account_scu = glade_xml_get_widget (xml, "account_scu"); gnc_option_menu_init(aw->account_scu); - if (gnc_price_source_have_fq()) { - gtk_widget_destroy(glade_xml_get_widget (xml, "finance_quote_warning")); - } else { - gtk_widget_set_sensitive(glade_xml_get_widget (xml, "price_quote_frame"), - FALSE); - } - - aw->get_quote_check = glade_xml_get_widget (xml, "get_quote_check"); - gtk_signal_connect (GTK_OBJECT (aw->get_quote_check), "toggled", - GTK_SIGNAL_FUNC (get_quote_check_cb), aw); - - aw->source_label = glade_xml_get_widget (xml, "source_label"); - box = glade_xml_get_widget (xml, "source_box"); - aw->source_menu = gnc_ui_source_menu_create(aw_get_account (aw)); - gtk_box_pack_start(GTK_BOX(box), aw->source_menu, TRUE, TRUE, 0); - - aw->quote_tz_label = glade_xml_get_widget (xml, "quote_tz_label"); - box = glade_xml_get_widget (xml, "quote_tz_box"); - aw->quote_tz_menu = gnc_ui_quote_tz_menu_create(aw_get_account (aw)); - gtk_box_pack_start(GTK_BOX(box), aw->quote_tz_menu, TRUE, TRUE, 0); - box = glade_xml_get_widget (xml, "parent_scroll"); aw->top_level_account = xaccMallocAccount(gnc_get_current_book ()); diff --git a/src/gnome-utils/dialog-commodity.c b/src/gnome-utils/dialog-commodity.c index df5412cb98..b6033e4fbb 100644 --- a/src/gnome-utils/dialog-commodity.c +++ b/src/gnome-utils/dialog-commodity.c @@ -21,6 +21,14 @@ * Boston, MA 02111-1307, USA gnu@gnu.org * ********************************************************************/ +/** @addtogroup UI + @{ */ +/** @file dialog-commodity.c + @brief "select" and "new" commodity windows + @author Copyright (C) 2000 Bill Gribble +*/ + + #include "config.h" #include @@ -35,62 +43,71 @@ #include "messages.h" #include "window-help.h" +static short module = MOD_GUI; struct select_commodity_window { GtkWidget * dialog; GtkWidget * namespace_combo; + GtkWidget * namespace_entry; GtkWidget * commodity_combo; GtkWidget * commodity_entry; GtkWidget * select_user_prompt; - gnc_commodity_callback callback; - void * callback_data; - - char * default_exchange_code; - char * default_fullname; - char * default_mnemonic; - int default_fraction; + GtkWidget * ok_button; + + gnc_commodity * selection; + + const char * default_exchange_code; + const char * default_fullname; + const char * default_mnemonic; + int default_fraction; }; struct commodity_window { GtkWidget * dialog; + GtkWidget * commodity_info_frame; GtkWidget * fullname_entry; GtkWidget * mnemonic_entry; GtkWidget * namespace_combo; GtkWidget * code_entry; GtkWidget * fraction_spinbutton; - - gnc_commodity_callback callback; - void * callback_data; + GtkWidget * get_quote_check; + GtkWidget * source_label; + GtkWidget * source_menu; + GtkWidget * quote_tz_label; + GtkWidget * quote_tz_menu; + GtkWidget * ok_button; gnc_commodity *edit_commodity; }; +typedef struct select_commodity_window SelectCommodityWindow; +typedef struct commodity_window CommodityWindow; static gnc_commodity_help_callback help_callback = NULL; + +/* The commodity selection window */ static SelectCommodityWindow * -gnc_ui_select_commodity_create(const gnc_commodity * orig_sel, - gnc_commodity_callback callback, - void * callback_data); +gnc_ui_select_commodity_create(const gnc_commodity * orig_sel); -static void gnc_ui_select_commodity_ok_cb(GtkButton * button, - gpointer user_data); -static void gnc_ui_select_commodity_new_cb(GtkButton * button, - gpointer user_data); -static void gnc_ui_select_commodity_cancel_cb(GtkButton * button, - gpointer user_data); -static void gnc_ui_select_commodity_namespace_changed_cb(GtkEditable * entry, - gpointer user_data); -static void gnc_ui_commodity_ok_cb(GtkButton * button, gpointer user_data); -static void gnc_ui_commodity_cancel_cb(GtkButton * button, gpointer user_data); -static void gnc_ui_commodity_help_cb(GtkButton * button, gpointer user_data); +void gnc_ui_select_commodity_new_cb(GtkButton * button, + gpointer user_data); +void gnc_ui_select_commodity_changed_cb(GtkEditable * entry, + gpointer user_data); +void gnc_ui_select_commodity_namespace_changed_cb(GtkEditable * entry, + gpointer user_data); -static void -select_modal_callback(const gnc_commodity * arg, void * data) { - *((const gnc_commodity **)data) = arg; -} +/* The commodity creation window */ +void gnc_ui_commodity_changed_cb(GtkWidget * dummy, gpointer user_data); +void gnc_ui_commodity_ok_cb(GtkButton * button, gpointer user_data); +void gnc_ui_commodity_help_cb(GtkButton * button, gpointer user_data); +void gnc_ui_commodity_quote_cb(GtkWidget *w, gpointer data); +/******************************************************************** + * gnc_ui_commodity_set_help_callback + ********************************************************************/ + void gnc_ui_commodity_set_help_callback (gnc_commodity_help_callback cb) { @@ -104,56 +121,66 @@ gnc_ui_commodity_set_help_callback (gnc_commodity_help_callback cb) gnc_commodity * gnc_ui_select_commodity_modal_full(gnc_commodity * orig_sel, GtkWidget * parent, - char * user_message, - char * exchange_code, - char * fullname, - char * mnemonic, - int fraction) + const char * user_message, + const char * code, + const char * fullname, + const char * mnemonic) { gnc_commodity * retval = NULL; -#define PROMPT_SIZE 2048 - gchar user_prompt_text[PROMPT_SIZE] = ""; + const gchar *initial; + gchar *user_prompt_text; + SelectCommodityWindow * win; + gboolean done; + gint value; - SelectCommodityWindow * win = - gnc_ui_select_commodity_create(orig_sel, &select_modal_callback, &retval); - - win->default_exchange_code=exchange_code; + win = gnc_ui_select_commodity_create(orig_sel); + win->default_exchange_code=code; win->default_fullname=fullname; win->default_mnemonic=mnemonic; - if(user_message!=NULL) - { - strncat(user_prompt_text,user_message,PROMPT_SIZE-strlen(user_prompt_text)); - } - else if( exchange_code!=NULL || fullname!=NULL || mnemonic!=NULL) - { - strncat(user_prompt_text,_("\nPlease select a commodity to match:"),PROMPT_SIZE-strlen(user_prompt_text)); - } - if(fullname!=NULL) - { - strncat(user_prompt_text,_("\nCommodity: "),PROMPT_SIZE-strlen(user_prompt_text)); - strncat(user_prompt_text,fullname,PROMPT_SIZE-strlen(user_prompt_text)); - } - if(exchange_code!=NULL) - { - strncat(user_prompt_text,_("\nExchange code (CUSIP or similar): "),PROMPT_SIZE-strlen(user_prompt_text)); - strncat(user_prompt_text,exchange_code,PROMPT_SIZE-strlen(user_prompt_text)); - } - if(mnemonic!=NULL) - { - strncat(user_prompt_text,_("\nMnemonic(Ticker symbol or similar): "),PROMPT_SIZE-strlen(user_prompt_text)); - strncat(user_prompt_text,mnemonic,PROMPT_SIZE-strlen(user_prompt_text)); - } - - gtk_label_set_text ((GtkLabel *)(win->select_user_prompt), - user_prompt_text); - - if(parent) { + if (parent) gnome_dialog_set_parent(GNOME_DIALOG(win->dialog), GTK_WINDOW(parent)); + + if (user_message != NULL) + initial = user_message; + else if ((code != NULL) || (fullname != NULL) || (mnemonic != NULL)) + initial = _("\nPlease select a commodity to match:"); + else + initial = ""; + + user_prompt_text = + g_strdup_printf("%s%s%s%s%s%s%s", + initial, + fullname ? _("\nCommodity: ") : "", + fullname ? fullname : "", + code ? _("\nExchange code (CUSIP or similar): ") : "", + code ? code : "", + mnemonic ? _("\nMnemonic(Ticker symbol or similar): ") : "", + mnemonic ? mnemonic : ""); + gtk_label_set_text ((GtkLabel *)(win->select_user_prompt), + user_prompt_text); + + /* Run the dialog, handling the terminal conditions. */ + done = FALSE; + while (!done) { + switch (value = gnome_dialog_run(GNOME_DIALOG(win->dialog))) { + case 0: /* OK */ + DEBUG("case 0"); + retval = win->selection; + done = TRUE; + break; + case 1: /* New */ + DEBUG("case 1"); + break; + default: /* Cancel, Escape, Close, etc. */ + DEBUG("default: %d", value); + retval = NULL; + done = TRUE; + break; + } } - gtk_window_set_modal(GTK_WINDOW(win->dialog), TRUE); - gtk_widget_show (win->dialog); - gtk_main(); + gnome_dialog_close(GNOME_DIALOG(win->dialog)); /* Close and destroy */ + g_free(win); return retval; } @@ -164,73 +191,41 @@ gnc_ui_select_commodity_modal_full(gnc_commodity * orig_sel, gnc_commodity * gnc_ui_select_commodity_modal(gnc_commodity * orig_sel, - GtkWidget * parent) { + GtkWidget * parent) +{ return gnc_ui_select_commodity_modal_full(orig_sel, parent, NULL, NULL, NULL, - NULL, - 0); + NULL); } -static gint -select_commodity_close (GnomeDialog *dialog, gpointer data) -{ - SelectCommodityWindow *scw = data; - - g_free(scw); - - gtk_main_quit (); - - return FALSE; -} - /******************************************************************** * gnc_ui_select_commodity_create() ********************************************************************/ static SelectCommodityWindow * -gnc_ui_select_commodity_create(const gnc_commodity * orig_sel, - gnc_commodity_callback callback, - void * callback_data) { +gnc_ui_select_commodity_create(const gnc_commodity * orig_sel) +{ SelectCommodityWindow * retval = g_new0(SelectCommodityWindow, 1); GladeXML *xml; char * namespace; xml = gnc_glade_xml_new ("commodity.glade", "Commodity Selector Dialog"); - - glade_xml_signal_connect_data - (xml, "gnc_ui_select_commodity_ok_cb", - GTK_SIGNAL_FUNC (gnc_ui_select_commodity_ok_cb), retval); - - glade_xml_signal_connect_data - (xml, "gnc_ui_select_commodity_new_cb", - GTK_SIGNAL_FUNC (gnc_ui_select_commodity_new_cb), retval); - - glade_xml_signal_connect_data - (xml, "gnc_ui_select_commodity_cancel_cb", - GTK_SIGNAL_FUNC (gnc_ui_select_commodity_cancel_cb), retval); - - glade_xml_signal_connect_data - (xml, "gnc_ui_select_commodity_namespace_changed_cb", - GTK_SIGNAL_FUNC (gnc_ui_select_commodity_namespace_changed_cb), retval); + glade_xml_signal_autoconnect_full( xml, + gnc_glade_autoconnect_full_func, + retval ); retval->dialog = glade_xml_get_widget (xml, "Commodity Selector Dialog"); retval->namespace_combo = glade_xml_get_widget (xml, "namespace_combo"); retval->commodity_combo = glade_xml_get_widget (xml, "commodity_combo"); retval->commodity_entry = glade_xml_get_widget (xml, "commodity_entry"); retval->select_user_prompt = glade_xml_get_widget (xml, "select_user_prompt"); + retval->ok_button = glade_xml_get_widget (xml, "ok_button"); - retval->callback = callback; - retval->callback_data = callback_data; - - gtk_signal_connect (GTK_OBJECT(retval->dialog), "close", - GTK_SIGNAL_FUNC(select_commodity_close), retval); - - gtk_label_set_text ((GtkLabel *)retval->select_user_prompt, - ""); + gtk_label_set_text ((GtkLabel *)retval->select_user_prompt, ""); /* build the menus of namespaces and commodities */ namespace = @@ -245,11 +240,126 @@ gnc_ui_select_commodity_create(const gnc_commodity * orig_sel, } +/** + * This function is called whenever the user clicks on the "New" + * button in the commodity picker. Its function is pop up a new + * dialog alling the user to create a new commodity. + * + * @note This function is an internal helper function for the + * Commodity Selection dialog. It should not be used outside of the + * dialog-commodity.c file. + * + * @param entry A pointer to the "new" button widget in the dialog. + * + * @param user_data A pointer to the data structure describing the + * current state of the commodity picker. + */ +void +gnc_ui_select_commodity_new_cb(GtkButton * button, + gpointer user_data) +{ + SelectCommodityWindow * w = user_data; + + const char * namespace = gnc_ui_namespace_picker_ns (w->namespace_combo); + + const gnc_commodity * new_commodity = + gnc_ui_new_commodity_modal_full(namespace, + w->dialog, + w->default_exchange_code, + w->default_fullname, + w->default_mnemonic, + w->default_fraction); + if(new_commodity) { + char *namespace; + + namespace = + gnc_ui_update_namespace_picker(w->namespace_combo, + gnc_commodity_get_namespace + (new_commodity), + TRUE, FALSE); + g_free(namespace); + gnc_ui_update_commodity_picker(w->commodity_combo, + gnc_commodity_get_namespace(new_commodity), + gnc_commodity_get_printname(new_commodity)); + } +} + + +/** + * This function is called whenever the commodity combo box is + * changed. Its function is to determine if a valid commodity has + * been selected, record the selection, and update the OK button. + * + * @note This function is an internal helper function for the + * Commodity Selection dialog. It should not be used outside of the + * dialog-commodity.c file. + * + * @param entry A pointer to the commodity name entry widget in the + * dialog. + * + * @param user_data A pointer to the data structure describing the + * current state of the commodity picker. + */ +void +gnc_ui_select_commodity_changed_cb(GtkEditable * entry, + gpointer user_data) +{ + SelectCommodityWindow * w = user_data; + const char * namespace; + const char * fullname; + gboolean ok; + + ENTER("entry=%p, user_data=%p", entry, user_data); + namespace = gnc_ui_namespace_picker_ns (w->namespace_combo); + fullname = gtk_entry_get_text(GTK_ENTRY(w->commodity_entry)); + DEBUG("namespace=%s, name=%s", namespace, fullname); + w->selection = gnc_commodity_table_find_full(gnc_get_current_commodities(), + namespace, fullname); + + ok = (w->selection != NULL); + gtk_widget_set_sensitive(w->ok_button, ok); + gnome_dialog_set_default(GNOME_DIALOG(w->dialog), ok ? 0 : 2); + LEAVE("sensitive=%d, default = %d", ok, ok ? 0 : 2); +} + + +/** + * This function is called whenever the commodity namespace combo box + * is changed. Its function is to update the commodity name combo + * box with the strings that are appropriate to the selected + * namespace. + * + * @note This function is an internal helper function for the + * Commodity Selection dialog. It should not be used outside of the + * dialog-commodity.c file. + * + * @param entry A pointer to the commodity namespace entry widget in + * the dialog. + * + * @param user_data A pointer to the data structure describing the + * current state of the commodity picker. + */ +void +gnc_ui_select_commodity_namespace_changed_cb(GtkEditable * entry, + gpointer user_data) +{ + SelectCommodityWindow * w = user_data; + const char * namespace; + + ENTER("entry=%p, user_data=%p", entry, user_data); + namespace = gnc_ui_namespace_picker_ns (w->namespace_combo); + DEBUG("namespace=%s", namespace); + gnc_ui_update_commodity_picker(w->commodity_combo, namespace, NULL); + LEAVE(" "); +} + + /******************************************************************** * gnc_ui_update_commodity_picker ********************************************************************/ static int -g_strcmp(gconstpointer a, gconstpointer b) { +g_strcmp(gconstpointer a, gconstpointer b) +{ return strcmp(a, b); } @@ -296,111 +406,6 @@ gnc_ui_update_commodity_picker(GtkWidget * combobox, } -/******************************************************************** - * gnc_ui_select_commodity_destroy() - ********************************************************************/ - -void -gnc_ui_select_commodity_destroy(SelectCommodityWindow * w) { - if(w) { - gnome_dialog_close(GNOME_DIALOG(w->dialog)); - } -} - -/******************************************************************** - * gnc_ui_select_commodity_ok_cb() - ********************************************************************/ - -static void -gnc_ui_select_commodity_ok_cb(GtkButton * button, - gpointer user_data) -{ - SelectCommodityWindow * w = user_data; - const char * namespace; - char * fullname; - gnc_commodity * retval = NULL; - - namespace = gnc_ui_namespace_picker_ns (w->namespace_combo); - fullname = gtk_entry_get_text(GTK_ENTRY(w->commodity_entry)); - - retval = gnc_commodity_table_find_full(gnc_get_current_commodities(), - namespace, - fullname); - if(retval) { - if (w->callback) - (w->callback)(retval, w->callback_data); - gnc_ui_select_commodity_destroy(w); - } - else { - gnc_warning_dialog(_("You must select a commodity.\n" - "To create a new one, click \"New\"")); - } -} - - -/******************************************************************** - * gnc_ui_select_commodity_new_cb() - ********************************************************************/ - -static void -gnc_ui_select_commodity_new_cb(GtkButton * button, - gpointer user_data) { - SelectCommodityWindow * w = user_data; - - const char * namespace = gnc_ui_namespace_picker_ns (w->namespace_combo); - - const gnc_commodity * new_commodity = - gnc_ui_new_commodity_modal_full(namespace, - w->dialog, - w->default_exchange_code, - w->default_fullname, - w->default_mnemonic, - w->default_fraction); - if(new_commodity) { - char *namespace; - - namespace = - gnc_ui_update_namespace_picker(w->namespace_combo, - gnc_commodity_get_namespace - (new_commodity), - TRUE, FALSE); - g_free(namespace); - gnc_ui_update_commodity_picker(w->commodity_combo, - gnc_commodity_get_namespace(new_commodity), - gnc_commodity_get_printname(new_commodity)); - } -} - - -/******************************************************************** - * gnc_ui_select_commodity_cancel_cb() - ********************************************************************/ - -static void -gnc_ui_select_commodity_cancel_cb(GtkButton * button, - gpointer user_data) { - SelectCommodityWindow * w = user_data; - - if (w->callback) - (w->callback)(NULL, w->callback_data); - - gnc_ui_select_commodity_destroy(w); -} - -/******************************************************************** - * gnc_ui_select_commodity_namespace_changed_cb() - ********************************************************************/ - -static void -gnc_ui_select_commodity_namespace_changed_cb(GtkEditable * entry, - gpointer user_data) { - SelectCommodityWindow * w = user_data; - const char * namespace = gnc_ui_namespace_picker_ns (w->namespace_combo); - - gnc_ui_update_commodity_picker(w->commodity_combo, namespace, NULL); -} - - /******************************************************************** * gnc_ui_update_namespace_picker ********************************************************************/ @@ -409,7 +414,8 @@ char * gnc_ui_update_namespace_picker(GtkWidget * combobox, const char * init_string, gboolean include_iso, - gboolean include_all) { + gboolean include_all) +{ GList * namespaces; const char * active; @@ -497,66 +503,140 @@ gnc_ui_namespace_picker_ns (GtkWidget *combobox) return namespace; } -static gint -commodity_close (GnomeDialog *dialog, gpointer data) +/********************************************************************/ + +void +gnc_ui_commodity_quote_cb (GtkWidget *w, gpointer data) { - CommodityWindow *ncw = data; + CommodityWindow *cw = data; + gboolean get_quote, allow_src; + const char *text; - g_free(ncw); + get_quote = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)); - gtk_main_quit (); + text = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(cw->namespace_combo)->entry)); + allow_src = gnc_commodity_namespace_is_iso(text); + gtk_widget_set_sensitive(cw->source_label, get_quote && allow_src); + gtk_widget_set_sensitive(cw->source_menu, get_quote && allow_src); + gtk_widget_set_sensitive(cw->quote_tz_label, get_quote); + gtk_widget_set_sensitive(cw->quote_tz_menu, get_quote); - return FALSE; } -/******************************************************************** - * gnc_ui_new_commodity_create() - ********************************************************************/ +void +gnc_ui_commodity_changed_cb(GtkWidget * dummy, gpointer user_data) +{ + CommodityWindow * w = user_data; + const char * namespace; + const char * fullname; + const char * mnemonic; + gboolean ok; + ENTER("widget=%p, user_data=%p", dummy, user_data); + if (GTK_WIDGET_SENSITIVE(w->commodity_info_frame)) { + namespace = gnc_ui_namespace_picker_ns (w->namespace_combo); + fullname = gtk_entry_get_text(GTK_ENTRY(w->fullname_entry)); + mnemonic = gtk_entry_get_text(GTK_ENTRY(w->mnemonic_entry)); + DEBUG("namespace=%s, name=%s, mnemonic=%s", namespace, fullname, mnemonic); + ok = (fullname && namespace && mnemonic && + fullname[0] && namespace[0] && mnemonic[0]); + } else { + ok = TRUE; + } + gtk_widget_set_sensitive(w->ok_button, ok); + gnome_dialog_set_default(GNOME_DIALOG(w->dialog), ok ? 0 : 1); + LEAVE("sensitive=%d, default = %d", ok, ok ? 0 : 1); +} + +/** Build the new/edit commodity dialog box + */ static CommodityWindow * -gnc_ui_new_commodity_create(const char * selected_namespace, - gnc_commodity_callback callback, - void * callback_data) { +gnc_ui_new_commodity_dialog(const char * selected_namespace, + GtkWidget *parent, + const char * fullname, + const char * mnemonic, + const char * cusip, + int fraction) +{ CommodityWindow * retval = g_new0(CommodityWindow, 1); GtkWidget *help_button; + GtkWidget *box; GladeXML *xml; - char *namespace; + gboolean include_iso; + char *temp; + ENTER(" "); xml = gnc_glade_xml_new ("commodity.glade", "Commodity Dialog"); - glade_xml_signal_connect_data - (xml, "gnc_ui_commodity_ok_cb", - GTK_SIGNAL_FUNC (gnc_ui_commodity_ok_cb), retval); + glade_xml_signal_autoconnect_full( xml, + gnc_glade_autoconnect_full_func, + retval ); - glade_xml_signal_connect_data - (xml, "gnc_ui_commodity_cancel_cb", - GTK_SIGNAL_FUNC (gnc_ui_commodity_cancel_cb), retval); - - glade_xml_signal_connect_data - (xml, "gnc_ui_commodity_help_cb", - GTK_SIGNAL_FUNC (gnc_ui_commodity_help_cb), retval); + retval->dialog = glade_xml_get_widget (xml, "Commodity Dialog"); + if (parent) + gnome_dialog_set_parent(GNOME_DIALOG(retval->dialog), GTK_WINDOW(parent)); + retval->edit_commodity = NULL; help_button = glade_xml_get_widget (xml, "help_button"); if (!help_callback) gtk_widget_hide (help_button); - retval->dialog = glade_xml_get_widget (xml, "Commodity Dialog"); - - retval->edit_commodity = NULL; + /* Get widget pointers */ + retval->commodity_info_frame = glade_xml_get_widget (xml, "commodity_info_frame"); retval->fullname_entry = glade_xml_get_widget (xml, "fullname_entry"); retval->mnemonic_entry = glade_xml_get_widget (xml, "mnemonic_entry"); retval->namespace_combo = glade_xml_get_widget (xml, "namespace_combo"); retval->code_entry = glade_xml_get_widget (xml, "code_entry"); retval->fraction_spinbutton = glade_xml_get_widget (xml, "fraction_spinbutton"); + retval->ok_button = glade_xml_get_widget (xml, "ok_button"); + retval->get_quote_check = glade_xml_get_widget (xml, "get_quote_check"); + retval->source_label = glade_xml_get_widget (xml, "source_label"); + retval->quote_tz_label = glade_xml_get_widget (xml, "quote_tz_label"); - retval->callback = callback; - retval->callback_data = callback_data; - gtk_signal_connect (GTK_OBJECT(retval->dialog), "close", - GTK_SIGNAL_FUNC(commodity_close), retval); + /* Build custom widgets */ + box = glade_xml_get_widget (xml, "source_box"); + retval->source_menu = gnc_ui_source_menu_create(); + gtk_box_pack_start(GTK_BOX(box), retval->source_menu, TRUE, TRUE, 0); + box = glade_xml_get_widget (xml, "quote_tz_box"); + retval->quote_tz_menu = gnc_ui_quote_tz_menu_create(); + gtk_box_pack_start(GTK_BOX(box), retval->quote_tz_menu, TRUE, TRUE, 0); + + /* Commodity editing is next to nil */ + if (gnc_commodity_namespace_is_iso(selected_namespace)) { + gtk_widget_set_sensitive(retval->commodity_info_frame, FALSE); + include_iso = TRUE; + } else { + include_iso = FALSE; + } + + /* Are price quotes supported */ + if (gnc_price_source_have_fq()) { + gtk_widget_destroy(glade_xml_get_widget (xml, "finance_quote_warning")); + } else { + gtk_widget_set_sensitive(glade_xml_get_widget (xml, "price_quote_frame"), + FALSE); + } + + + /* Fill in any data, top to bottom */ + + gtk_entry_set_text (GTK_ENTRY (retval->fullname_entry), fullname ? fullname : ""); + gtk_entry_set_text (GTK_ENTRY (retval->mnemonic_entry), mnemonic ? mnemonic : ""); + temp = gnc_ui_update_namespace_picker(retval->namespace_combo, + selected_namespace, + include_iso, TRUE); + g_free(temp); + gtk_entry_set_text (GTK_ENTRY (retval->code_entry), cusip ? cusip : ""); + if (fraction > 0) + gtk_spin_button_set_value (GTK_SPIN_BUTTON (retval->fraction_spinbutton), + fraction); + + + /* Set up so activates default button */ gnome_dialog_editable_enters(GNOME_DIALOG(retval->dialog), GTK_EDITABLE(retval->fullname_entry)); gnome_dialog_editable_enters(GNOME_DIALOG(retval->dialog), @@ -564,156 +644,166 @@ gnc_ui_new_commodity_create(const char * selected_namespace, gnome_dialog_editable_enters(GNOME_DIALOG(retval->dialog), GTK_EDITABLE(retval->code_entry)); - namespace = gnc_ui_update_namespace_picker(retval->namespace_combo, - selected_namespace, - FALSE, TRUE); - g_free(namespace); - + LEAVE(" "); return retval; } -/******************************************************************** - * gnc_ui_edit_commodity_create() - ********************************************************************/ -static CommodityWindow * -gnc_ui_edit_commodity_create(gnc_commodity *commodity, - gnc_commodity_callback callback, - void * callback_data) { - CommodityWindow *retval; - const char *str; - char *namespace; +static void +gnc_ui_commodity_update_quote_info(CommodityWindow *win, + gnc_commodity *commodity) +{ + gboolean has_quote_src; + const char *quote_src, *quote_tz; + int pos = 0; - g_return_val_if_fail (commodity != NULL, NULL); + ENTER(" "); + has_quote_src = gnc_commodity_get_quote_flag (commodity); + quote_src = gnc_commodity_get_quote_source (commodity); + quote_tz = gnc_commodity_get_quote_tz (commodity); - retval = gnc_ui_new_commodity_create (NULL, callback, callback_data); - - retval->edit_commodity = commodity; - - str = gnc_commodity_get_fullname (commodity); - gtk_entry_set_text (GTK_ENTRY (retval->fullname_entry), - str ? str : ""); - - str = gnc_commodity_get_mnemonic (commodity); - gtk_entry_set_text (GTK_ENTRY (retval->mnemonic_entry), - str ? str : ""); - - namespace = gnc_ui_update_namespace_picker - (retval->namespace_combo, - gnc_commodity_get_namespace (commodity), - FALSE, TRUE); - g_free (namespace); - - str = gnc_commodity_get_exchange_code (commodity); - gtk_entry_set_text (GTK_ENTRY (retval->code_entry), - str ? str : ""); - - gtk_spin_button_set_value (GTK_SPIN_BUTTON (retval->fraction_spinbutton), - gnc_commodity_get_fraction (commodity)); - - return retval; -} - -static void -new_modal_callback(const gnc_commodity * arg, void * data) { - *((const gnc_commodity **)data) = arg; -} - -/******************************************************************** - * gnc_ui_new_commodity_modal_full() - ********************************************************************/ - -gnc_commodity * -gnc_ui_new_commodity_modal_full(const char * default_namespace, - GtkWidget * parent, - char * exchange_code, - char * fullname, - char * mnemonic, - int fraction) { - gnc_commodity * retval = NULL; - - CommodityWindow * win = - gnc_ui_new_commodity_create(default_namespace, &new_modal_callback, - &retval); - if(fullname!=NULL) - { - gtk_entry_set_text((GtkEntry *)(win->fullname_entry), - fullname); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (win->get_quote_check), + has_quote_src); + if (!gnc_commodity_is_iso(commodity)) + gtk_option_menu_set_history (GTK_OPTION_MENU (win->source_menu), + gnc_price_source_internal2enum (quote_src)); + if (quote_tz) { + pos = gnc_find_timezone_menu_position(quote_tz); + if(pos == 0) { + PWARN("Unknown price quote timezone (%s), resetting to default.", + quote_tz ? quote_tz : "(null)"); } - if(mnemonic!=NULL) - { - gtk_entry_set_text((GtkEntry *)(win->mnemonic_entry), - mnemonic); - } - if(exchange_code!=NULL) - { - gtk_entry_set_text((GtkEntry *)(win->code_entry), - exchange_code); - } - if(fraction>0) - { - gtk_spin_button_set_value (GTK_SPIN_BUTTON(win->fraction_spinbutton), - fraction); - } - /*(GtkWidget *)(win->namespace_combo);*/ - - - if(parent) { - gnome_dialog_set_parent(GNOME_DIALOG(win->dialog), GTK_WINDOW(parent)); } - gtk_window_set_modal(GTK_WINDOW(win->dialog), TRUE); - gtk_widget_show (win->dialog); - gtk_main(); - + gtk_option_menu_set_history (GTK_OPTION_MENU (win->quote_tz_menu), pos); + LEAVE(" "); +} + + +static gnc_commodity * +gnc_ui_common_commodity_modal(gnc_commodity *commodity, + GtkWidget * parent, + const char * namespace, + const char * code, + const char * fullname, + const char * mnemonic, + int fraction) +{ + CommodityWindow * win; + gnc_commodity *retval = NULL; + gboolean done; + gint value; + + ENTER(" "); + + /* If a commodity was provided, copy out the existing info */ + if (commodity) { + namespace = gnc_commodity_get_namespace (commodity); + fullname = gnc_commodity_get_fullname (commodity); + mnemonic = gnc_commodity_get_mnemonic (commodity); + code = gnc_commodity_get_exchange_code (commodity); + fraction = gnc_commodity_get_fraction (commodity); + } else { + /* Not allowed to create new currencies */ + if (gnc_commodity_namespace_is_iso(namespace)) { + namespace = NULL; + } + } + + win = gnc_ui_new_commodity_dialog(namespace, parent, fullname, + mnemonic, code, fraction); + + /* Update stock quote info based on existing commodity */ + if (commodity) { + gnc_ui_commodity_update_quote_info(win, commodity); + win->edit_commodity = commodity; + } + + /* Update stock quote sensitivities based on check box */ + gnc_ui_commodity_quote_cb(win->get_quote_check, win); + + /* Run the dialog, handling the terminal conditions. */ + done = FALSE; + while (!done) { + value = gnome_dialog_run(GNOME_DIALOG(win->dialog)); + switch (value) { + case 0: /* OK */ + retval = win->edit_commodity; + done = TRUE; + DEBUG("case 0"); + break; + case 2: /* Help */ + DEBUG("case 2"); + break; + default: /* Cancel, Escape, Close, etc. */ + DEBUG("default: %d", value); + retval = NULL; + done = TRUE; + break; + } + } + gnome_dialog_close(GNOME_DIALOG(win->dialog)); /* Close and destroy */ + g_free(win); + + LEAVE(" "); return retval; } -/******************************************************************** - * gnc_ui_new_commodity_modal() - ********************************************************************/ + +/** Create and run the new/edit commodity dialog. + */ +gnc_commodity * +gnc_ui_new_commodity_modal_full(const char * namespace, + GtkWidget * parent, + const char * exchange_code, + const char * fullname, + const char * mnemonic, + int fraction) +{ + gnc_commodity *result; + + ENTER(" "); + result = gnc_ui_common_commodity_modal(NULL, parent, namespace, fullname, + mnemonic, exchange_code, 10000); + LEAVE(" "); + return result; +} + +/** External routine for popping up the new commodity dialog box. + */ gnc_commodity * gnc_ui_new_commodity_modal(const char * default_namespace, - GtkWidget * parent) { - return gnc_ui_new_commodity_modal_full(default_namespace, - parent, - NULL, - NULL, - NULL, - 0); + GtkWidget * parent) +{ + gnc_commodity *result; + + ENTER(" "); + result = gnc_ui_common_commodity_modal(NULL, parent, default_namespace, NULL, + NULL, NULL, 0); + LEAVE(" "); + return result; } /******************************************************************** * gnc_ui_edit_commodity_modal() ********************************************************************/ +/** Given an existing commodity, uses the + * gnc_ui_new_commodity_dialog() routine to build a basic edit + * dialog, then fills in the price quote information at the bottom of + * the dialog. + */ gboolean gnc_ui_edit_commodity_modal(gnc_commodity *commodity, GtkWidget * parent) { - gnc_commodity * retval = NULL; + gnc_commodity *result; - CommodityWindow * win = - gnc_ui_edit_commodity_create(commodity, &new_modal_callback, &retval); - if(parent) { - gnome_dialog_set_parent(GNOME_DIALOG(win->dialog), GTK_WINDOW(parent)); - } - gtk_window_set_modal(GTK_WINDOW(win->dialog), TRUE); - gtk_widget_show (win->dialog); - gtk_main(); - - return (retval != NULL); -} - -/******************************************************************** - * gnc_ui_commodity_destroy() - ********************************************************************/ - -void -gnc_ui_commodity_destroy(CommodityWindow * w) { - if(w) { - gnome_dialog_close(GNOME_DIALOG(w->dialog)); - } + ENTER(" "); + result = gnc_ui_common_commodity_modal(commodity, parent, NULL, NULL, + NULL, NULL, 0); + LEAVE(" "); + return result != NULL; } @@ -721,9 +811,10 @@ gnc_ui_commodity_destroy(CommodityWindow * w) { * gnc_ui_commodity_ok_cb() ********************************************************************/ -static void +void gnc_ui_commodity_ok_cb(GtkButton * button, - gpointer user_data) { + gpointer user_data) +{ CommodityWindow * w = user_data; const char * fullname = gtk_entry_get_text(GTK_ENTRY(w->fullname_entry)); @@ -732,11 +823,22 @@ gnc_ui_commodity_ok_cb(GtkButton * button, const char * code = gtk_entry_get_text(GTK_ENTRY(w->code_entry)); int fraction = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(w->fraction_spinbutton)); - + const char *string; gnc_commodity * c; + gint selection; - if (gnc_commodity_namespace_is_iso (namespace)) - { + ENTER(" "); + /* Special case currencies */ + if (gnc_commodity_namespace_is_iso (namespace)) { + if (w->edit_commodity) { + c = w->edit_commodity; + gnc_commodity_set_quote_flag (c, gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON (w->get_quote_check))); + selection = gnc_option_menu_get_active (w->quote_tz_menu); + string = gnc_timezone_menu_position_to_string(selection); + gnc_commodity_set_quote_tz(c, string); + return; + } gnc_warning_dialog_parented(w->dialog, _("You may not create a new national " "currency.")); @@ -758,6 +860,7 @@ gnc_ui_commodity_ok_cb(GtkButton * button, if (!w->edit_commodity) { c = gnc_commodity_new(fullname, namespace, mnemonic, code, fraction); + w->edit_commodity = c; } else { c = w->edit_commodity; @@ -771,17 +874,19 @@ gnc_ui_commodity_ok_cb(GtkButton * button, gnc_commodity_set_fraction (c, fraction); } + gnc_commodity_set_quote_flag (c, gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON (w->get_quote_check))); + + selection = gnc_option_menu_get_active (w->source_menu); + string = gnc_price_source_enum2internal (selection); + gnc_commodity_set_quote_source(c, string); + + selection = gnc_option_menu_get_active (w->quote_tz_menu); + string = gnc_timezone_menu_position_to_string(selection); + gnc_commodity_set_quote_tz(c, string); + /* remember the commodity */ c = gnc_commodity_table_insert(gnc_get_current_commodities(), c); - - /* if there's a callback (generally to fill in some fields with - * info about the commodity) call it */ - if(w->callback) { - (w->callback)(c, w->callback_data); - } - - /* close the dialog */ - gnc_ui_commodity_destroy(w); } else { gnc_warning_dialog_parented(w->dialog, @@ -789,6 +894,7 @@ gnc_ui_commodity_ok_cb(GtkButton * button, "\"Symbol/abbreviation\",\n" "and \"Type\" for the commodity.")); } + LEAVE(" "); } @@ -796,26 +902,10 @@ gnc_ui_commodity_ok_cb(GtkButton * button, * gnc_ui_commodity_help_cb() ********************************************************************/ -static void +void gnc_ui_commodity_help_cb(GtkButton * button, - gpointer user_data) { + gpointer user_data) +{ if (help_callback) help_callback (); } - - -/******************************************************************** - * gnc_ui_commodity_cancel_cb() - ********************************************************************/ - -static void -gnc_ui_commodity_cancel_cb(GtkButton * button, - gpointer user_data) { - CommodityWindow * w = user_data; - - if (w->callback) { - (w->callback)(NULL, w->callback_data); - } - - gnc_ui_commodity_destroy(w); -} diff --git a/src/gnome-utils/dialog-commodity.h b/src/gnome-utils/dialog-commodity.h index f840680431..920f593020 100644 --- a/src/gnome-utils/dialog-commodity.h +++ b/src/gnome-utils/dialog-commodity.h @@ -21,6 +21,13 @@ * Boston, MA 02111-1307, USA gnu@gnu.org * ********************************************************************/ +/** @addtogroup UI + @{ */ +/** @file dialog-commodity.h + @brief "select" and "new" commodity windows + @author Copyright (C) 2000 Bill Gribble +*/ + #ifndef GNC_DIALOG_COMMODITY_H #define GNC_DIALOG_COMMODITY_H @@ -29,63 +36,208 @@ #include "gnc-commodity.h" #include "gnc-engine.h" -typedef struct select_commodity_window SelectCommodityWindow; -typedef struct commodity_window CommodityWindow; - -typedef void (* gnc_commodity_callback)(const gnc_commodity *, void * data); typedef void (* gnc_commodity_help_callback)(void); +/** This function is used to set the action routine for the help + * button in the commodity dialog windows. If the action routine is + * unset, the help button will not be visible to the user. + * + * @param cb The function to be called when the user clicks the help + * button. */ void gnc_ui_commodity_set_help_callback (gnc_commodity_help_callback cb); -void gnc_ui_select_commodity_destroy(SelectCommodityWindow * w); -void gnc_ui_commodity_destroy(CommodityWindow * w); - -/*Offer the user to select a commodity matching exchange_code, - fullname and mnemonic. If the user decides to create a new one, those - values are used as default. If fullname is NULL, the user won't be - told he has to match anything in perticular.*/ +/** @name Commodity Selection */ +/** @{ */ +/** Ask the user to select a commodity from the existing set of + * commodities. Arguments to this function determine the message + * placed at the top of the dialog but force no restriction on the + * commodities that may be chosen. The user will also have the + * option of creating a new commodity from this dialog box.. If the + * user decides to create a new one, those provided values are used + * as default values for the new commodity. + * + * @param orig_sel A pointer to a commodity that should initially be + * selected in the dialog box. + * + * @param parent The parent window of the new dialog. + * + * @param user_message A string that will be installed in the top of + * the dialog box as an instruction to the user. If NULL, a generic + * instruction will be used. + * + * @param exchange_code If present, a note will be added to the user + * instruction providing this exchange specific code, and this will + * be the default exchange code for any newly created commodities. + * + * @param fullname If present, a note will be added to the user + * instruction providing this commodity's full name, and this will be + * the default fullname for any newly created commodities. + * + * @param mnemonic If present, a note will be added to the user + * instruction providing this commodity's mnemonic, and this will be + * the default mnemonic for any newly created commodities. + * + * @return The commodity selected. May or may not be a newly created + * commodity. + */ gnc_commodity * gnc_ui_select_commodity_modal_full(gnc_commodity * orig_sel, GtkWidget * parent, - char * user_message, - char * exchange_code, - char * fullname, - char * mnemonic, - int fraction); + const char * user_message, + const char * exchange_code, + const char * fullname, + const char * mnemonic); + +/** Ask the user to select a commodity from the existing set of + * commodities. The user will also have the + * option of creating a new commodity from this dialog box.. If the + * user decides to create a new one, those provided values are used + * as default values for the new commodity. + * + * @param orig_sel A pointer to a commodity that should initially be + * selected in the dialog box. + * + * @return The commodity selected. May or may not be a newly created + * commodity. + */ gnc_commodity * gnc_ui_select_commodity_modal(gnc_commodity * orig_sel, GtkWidget * parent); +/** @} */ +/** @name Commodity Creation or Modification */ +/** @{ */ + +/** Ask the user to provide the information necessary to create a new + * commodity. + * + * @param namespace If present, this will be the default namespace + * for the new commodity. This value will be ignored if it is the + * namespace for ISO 4217 currencies. + * + * @param parent The parent window of the new dialog. + * + * @param user_message A string that will be installed in the top of + * the dialog box as an instruction to the user. If NULL, a generic + * instruction will be used. + * + * @param exchange_code If present, this will be the default exchange + * code for the new commodity. + * + * @param fullname If present, this will be the default fullname for + * the new commodity. + * + * @param mnemonic If present, this will be the default mnemonic for + * the new commodity. + * + * @param fraction If present, this will be the default fraction for + * the new commodity. If absent, a default of 1000 will be used. + * + * @return The newly created commodity, or NULL if the user cancelled. + */ gnc_commodity * -gnc_ui_new_commodity_modal_full(const char * default_namespace, +gnc_ui_new_commodity_modal_full(const char * namespace, GtkWidget * parent, - char * exchange_code, - char * fullname, - char * mnemonic, + const char * exchange_code, + const char * fullname, + const char * mnemonic, int fraction); +/** Ask the user to provide the information necessary to create a new + * commodity. + * + * @param namespace If present, this will be the default namespace + * for the new commodity. This value will be ignored if it is the + * namespace for ISO 4217 currencies. + * + * @param parent The parent window of the new dialog. + * + * @return The newly created commodity, or NULL if the user cancelled. + */ gnc_commodity * gnc_ui_new_commodity_modal(const char * default_namespace, GtkWidget * parent ); +/** Allow the user to edit the information about a commodity. For + * currencies, only the price quote information may be changed. For + * any other commodity, all aspects of the commodity information may + * be changed except that the namespace may not be changed to + * indicate a currency. The new information overwrites any old + * information, so this routine may not be used to create new + * commodities. + * + * @param commodity The commodity to edit. + * + * @param parent The parent window of the new dialog. + * + * @return The newly created commodity, or NULL if the user cancelled. + */ gboolean gnc_ui_edit_commodity_modal(gnc_commodity *commodity, GtkWidget * parent); +/** @} */ + +/** @name Auxiliary Dialog Functions */ +/** @{ */ + +/** Given a combo box, fill in the known commodity namespaces and then + * select one. + * + * @param combobox The combo box to populate with information. + * + * @param sel The namespace that should be initially selected when + * the combo box appears. + * + * @param include_iso Set to TRUE if the combo box should inlude the + * ISO4217 namespace for currencies. FALSE if the currency namespace + * should not be included. This flag has precedence over the + * following flag. + * + * @param include_all Set to TRUE if the combo box should include all + * known namespaces, both application and user defined. FALSE if + * only the default application namespaces should be included. + * + * @return The currently selected namespace. + * + * @note The returned string must be freed by the caller. + */ char * gnc_ui_update_namespace_picker(GtkWidget * combobox, const char * sel, gboolean include_iso, gboolean include_all); +/** Given a combo box, return the currently selected namespaces. + * + * @param combobox The combo box of namespaces. + * + * @return The currently selected namespace. + * + * @note This string is owned by the engine and must not be freed by + * the caller. + */ const char * gnc_ui_namespace_picker_ns (GtkWidget *combobox); +/** Given a combo box, fill in all the known commodities for the + * specified namespace, and then select one. + * + * @param combobox The combo box to populate with information. + * + * @param namespace All commodities with this namespace will be added + * to the combo box. + * + * @param sel The commodity that should be initially selected when + * the combo box appears. + */ void gnc_ui_update_commodity_picker(GtkWidget * combobox, const char * namespace, const char * sel); +/** @} */ #endif +/** @} */ diff --git a/src/gnome-utils/dialog-utils.c b/src/gnome-utils/dialog-utils.c index 5d30a3e1b4..503978d93f 100644 --- a/src/gnome-utils/dialog-utils.c +++ b/src/gnome-utils/dialog-utils.c @@ -51,7 +51,7 @@ static short module = MOD_GUI; * Returns: the menu * \*******************************************************************/ GtkWidget * -gnc_ui_source_menu_create(Account *account) +gnc_ui_source_menu_create(void) { gint i; GtkMenu *menu; @@ -118,7 +118,7 @@ gnc_timezone_menu_position_to_string(guint pos) } GtkWidget * -gnc_ui_quote_tz_menu_create(Account *account) +gnc_ui_quote_tz_menu_create(void) { GtkMenu *menu; GtkWidget *item; diff --git a/src/gnome-utils/dialog-utils.h b/src/gnome-utils/dialog-utils.h index 4c283bad43..c33bc67b62 100644 --- a/src/gnome-utils/dialog-utils.h +++ b/src/gnome-utils/dialog-utils.h @@ -54,14 +54,14 @@ struct _GNCOptionInfo * Args: account - account to use to set default choice * * Returns: the menu * \*******************************************************************/ -GtkWidget * gnc_ui_source_menu_create (Account *account); +GtkWidget * gnc_ui_source_menu_create (void); /********************************************************************\ * price quote timezone handling */ guint gnc_find_timezone_menu_position(const gchar *timezone); gchar * gnc_timezone_menu_position_to_string(guint pos); -GtkWidget * gnc_ui_quote_tz_menu_create (Account *account); +GtkWidget * gnc_ui_quote_tz_menu_create (void); GtkWidget * gnc_build_option_menu (GNCOptionInfo *option_info, gint num_options); diff --git a/src/gnome/glade/account.glade b/src/gnome/glade/account.glade index 1c1342ccf1..026cdb3a38 100644 --- a/src/gnome/glade/account.glade +++ b/src/gnome/glade/account.glade @@ -408,162 +408,6 @@ - - GtkFrame - price_quote_frame - 3 - - 0 - GTK_SHADOW_ETCHED_IN - - 0 - False - True - - - - GtkVBox - vbox129 - 3 - False - 3 - - - GtkCheckButton - get_quote_check - True - - False - True - - 0 - False - False - - - - - GtkHBox - hbox103 - False - 2 - - 0 - True - True - - - - GtkVBox - vbox116 - True - 0 - - 0 - False - False - - - - GtkLabel - source_label - - GTK_JUSTIFY_RIGHT - False - 1 - 0.5 - 0 - 0 - - 0 - False - False - - - - - GtkLabel - quote_tz_label - - GTK_JUSTIFY_RIGHT - False - 1 - 0.5 - 0 - 0 - - 0 - False - False - - - - - - GtkVBox - vbox117 - True - 0 - - 0 - True - True - - - - GtkHBox - source_box - False - 0 - - 0 - True - True - - - - Placeholder - - - - - GtkHBox - quote_tz_box - False - 0 - - 0 - True - True - - - - Placeholder - - - - - - - GtkLabel - finance_quote_warning - False - - GTK_JUSTIFY_CENTER - False - 0.5 - 0.5 - 0 - 0 - - 0 - False - False - - - - - GtkFrame frame32 diff --git a/src/import-export/import-commodity-matcher.c b/src/import-export/import-commodity-matcher.c index 9b0b057bd1..813287a90d 100755 --- a/src/import-export/import-commodity-matcher.c +++ b/src/import-export/import-commodity-matcher.c @@ -117,11 +117,10 @@ gnc_commodity * gnc_import_select_commodity(char * exchange_code, { retval=gnc_ui_select_commodity_modal_full(NULL, NULL, - _("Please select a commodity to match the following exchange code.\nPlease note that the exchange code of the commodity you select will be overwritten.\n"), + _("Please select a commodity to match the following exchange specific code.\nPlease note that the exchange code of the commodity you select will be overwritten.\n"), exchange_code, default_fullname, - default_mnemonic, - 0); + default_mnemonic); } if (retval != NULL&& diff --git a/src/scm/price-quotes.scm b/src/scm/price-quotes.scm index 65178d8e55..4256dc1955 100644 --- a/src/scm/price-quotes.scm +++ b/src/scm/price-quotes.scm @@ -353,38 +353,9 @@ (define (gnc:book-add-quotes book) - (define (find-quotables group) - ;; Return a list of accounts for whose commodities we should get - ;; quotes. - (define (quotable-currency-account? a) - (let ((commodity (gnc:account-get-commodity a))) - (equal? (gnc:commodity-get-namespace commodity) "ISO4217"))) - - (define (quotable-account? a) - (let ((type (gw:enum--val->sym (gnc:account-get-type a) - #f)) - (src (gnc:account-get-price-src a)) - (balance (not (gnc:numeric-zero-p (gnc:account-get-balance a))))) - - (if (not type) (set! type '())) - (if (symbol? type) (set! type (list type))) - (if (and src - (or (memq 'stock type) - (memq 'mutual-fund type) - (and (memq 'currency type) - (quotable-currency-account? a)))) - a - #f))) - - (let ((quotables (filter quotable-account? (gnc:group-get-subaccounts group)))) - (if (null? quotables) - #f - quotables)) - ) - - (define (accounts->fq-call-data account-list) - ;; Take a list of accounts that should be "quotable" -- i.e. they - ;; have a price-source, and are of the right type, and return a + (define (book->commodity->fq-call-data book) + ;; Call helper that walks all of the defined commodities to see if + ;; any are marked for quote retrieval. This function returns a ;; list of info needed for the relevant Finance::Quote calls, and ;; a list of the corresponding commodities. Also perform a bit of ;; optimization, merging calls for symbols to the same @@ -400,51 +371,42 @@ ;; (commodity-4 currency-4 tz-4) ...) ;; ...) - (define (account->fq-cmd account) - ;; Returns (cons fq-method-sym - ;; (list commodity currency assumed-timezone-str)) - (let* ((commodity (gnc:account-get-commodity account)) - (currency (gnc:default-currency)) - (src (and account (gnc:account-get-price-src account))) - (tz (gnc:account-get-quote-tz account)) - (fq-method-sym (and src (gnc:price-source-internal2fq src))) - (mnemonic (and commodity (gnc:commodity-get-mnemonic commodity)))) - (and - commodity - currency - fq-method-sym - mnemonic - (list fq-method-sym commodity currency tz)))) + (let* ((ct (gnc:book-get-commodity-table book)) + (big-list (gnc:commodity-table-get-quotable-commodities-info ct "")) + (commodity-list #f) + (currency-list (filter + (lambda (a) (not (equal? (cadr a) (caddr a)))) + (call-with-values + (lambda () (partition! + (lambda (cmd) + (not (string=? (car cmd) "currency"))) + big-list)) + (lambda (a b) (set! commodity-list a) b)))) + (quote-hash (make-hash-table 31))) - (let* ((big-list (delete #f (map account->fq-cmd account-list))) - (cmd-list #f) - (currency-cmd-list (call-with-values - (lambda () (partition! - (lambda (cmd) - (not (equal? (car cmd) "currency"))) - big-list)) - (lambda (a b) (set! cmd-list a) b))) - (cmd-hash (make-hash-table 31))) + (if (null? big-list) + #f + (begin - ;; Now collect symbols going to the same backend. - (item-list->hash! cmd-list cmd-hash car cdr hash-ref hash-set! #t) + ;; Now collect symbols going to the same backend. + (item-list->hash! commodity-list quote-hash car cdr hash-ref hash-set! #t) - ;; Now translate to just what finance-quote-helper expects. - (append - (hash-fold - (lambda (key value prior-result) - (cons (cons key value) - prior-result)) - '() - cmd-hash) - (map (lambda (cmd) (cons (car cmd) (list (cdr cmd)))) - currency-cmd-list)))) + ;; Now translate to just what finance-quote-helper expects. + (append + (hash-fold + (lambda (key value prior-result) + (cons (cons key value) + prior-result)) + '() + quote-hash) + (map (lambda (cmd) (cons (car cmd) (list (cdr cmd)))) + currency-list)))))) (define (fq-call-data->fq-calls fq-call-data) - ;; take an output element from accounts->fq-call-data and return a - ;; list where the gnc_commodities have been converted to their - ;; fq-suitable symbol strings. i.e. turn the former into the - ;; latter: + ;; take an output element from book->commodity->fq-call-data and + ;; return a list where the gnc_commodities have been converted to + ;; their fq-suitable symbol strings. i.e. turn the former into + ;; the latter: ;; ;; ("yahoo" (commodity-1 currency-1 tz-1) ;; (commodity-2 currency-2 tz-2) ...) @@ -613,8 +575,7 @@ ;; now, they'll result in funny formatting. (let* ((group (gnc:book-get-group book)) - (quotables (and group (find-quotables group))) - (fq-call-data (and quotables (accounts->fq-call-data quotables))) + (fq-call-data (book->commodity->fq-call-data book)) (fq-calls (and fq-call-data (apply append (map fq-call-data->fq-calls fq-call-data)))) @@ -642,11 +603,11 @@ (keep-going? #t)) (cond - ((eq? quotables #f) + ((eq? fq-call-data #f) (set! keep-going? #f) (if (gnc:ui-is-running?) - (gnc:error-dialog (_ "No accounts marked for quote retrieval.")) - (gnc:warn (_ "No accounts marked for quote retrieval.")))) + (gnc:error-dialog (_ "No commodities marked for quote retrieval.")) + (gnc:warn (_ "No commodities marked for quote retrieval.")))) ((eq? fq-results #f) (set! keep-going? #f) (if (gnc:ui-is-running?)