dialog-commodity.c

Go to the documentation of this file.
00001 /********************************************************************
00002  * dialog-commodity.c -- "select" and "new" commodity windows       *
00003  *                       (GnuCash)                                  *
00004  * Copyright (C) 2000 Bill Gribble <grib@billgribble.com>           *
00005  * Copyright (c) 2006 David Hampton <hampton@employees.org>         *
00006  *                                                                  *
00007  * This program is free software; you can redistribute it and/or    *
00008  * modify it under the terms of the GNU General Public License as   *
00009  * published by the Free Software Foundation; either version 2 of   *
00010  * the License, or (at your option) any later version.              *
00011  *                                                                  *
00012  * This program is distributed in the hope that it will be useful,  *
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00015  * GNU General Public License for more details.                     *
00016  *                                                                  *
00017  * You should have received a copy of the GNU General Public License*
00018  * along with this program; if not, contact:                        *
00019  *                                                                  *
00020  * Free Software Foundation           Voice:  +1-617-542-5942       *
00021  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00022  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
00023  ********************************************************************/
00024 
00036 #include "config.h"
00037 
00038 #include <gtk/gtk.h>
00039 #include <glib/gi18n.h>
00040 #include <stdio.h>
00041 
00042 #include "dialog-commodity.h"
00043 #include "dialog-utils.h"
00044 #include "gnc-engine.h"
00045 #include "gnc-gtk-utils.h"
00046 #include "gnc-gui-query.h"
00047 #include "gnc-ui-util.h"
00048 #include "gnc-ui.h"
00049 
00050 static QofLogModule log_module = GNC_MOD_GUI;
00051 
00052 enum {
00053   SOURCE_COL_NAME = 0,
00054   SOURCE_COL_FQ_SUPPORTED,
00055   NUM_SOURCE_COLS
00056 };
00057 
00058 struct select_commodity_window {
00059   GtkWidget * dialog;
00060   GtkWidget * namespace_combo;
00061   GtkWidget * commodity_combo;
00062   GtkWidget * select_user_prompt;
00063   GtkWidget * ok_button;
00064 
00065   gnc_commodity * selection;
00066 
00067   const char * default_cusip;
00068   const char * default_fullname;
00069   const char * default_mnemonic;
00070   int          default_fraction;
00071 };
00072 
00073 struct commodity_window {
00074   GtkWidget * dialog;
00075   GtkWidget * table;
00076   GtkWidget * fullname_entry;
00077   GtkWidget * mnemonic_entry;
00078   GtkWidget * namespace_combo;
00079   GtkWidget * code_entry;
00080   GtkWidget * fraction_spinbutton;
00081   GtkWidget * get_quote_check;
00082   GtkWidget * source_label;
00083   GtkWidget * source_button[SOURCE_MAX];
00084   GtkWidget * source_menu[SOURCE_MAX];
00085   GtkWidget * quote_tz_label;
00086   GtkWidget * quote_tz_menu;
00087   GtkWidget * ok_button;
00088 
00089   guint comm_section_top;
00090   guint comm_section_bottom;
00091   guint fq_section_top;
00092   guint fq_section_bottom;
00093 
00094   gboolean     is_currency;
00095   gnc_commodity *edit_commodity;
00096 };
00097 
00098 typedef struct select_commodity_window SelectCommodityWindow;
00099 typedef struct commodity_window CommodityWindow;
00100 
00101 static gnc_commodity_help_callback help_callback = NULL;
00102 
00103 
00104 /* The commodity selection window */
00105 static SelectCommodityWindow *
00106 gnc_ui_select_commodity_create(const gnc_commodity * orig_sel,
00107                                dialog_commodity_mode mode);
00108 void gnc_ui_select_commodity_new_cb(GtkButton * button,
00109                                     gpointer user_data);
00110 void gnc_ui_select_commodity_changed_cb(GtkComboBoxEntry *cbe,
00111                                         gpointer user_data);
00112 void gnc_ui_select_commodity_namespace_changed_cb(GtkComboBoxEntry *cbe,
00113                                                   gpointer user_data);
00114 
00115 /* The commodity creation window */
00116 void gnc_ui_commodity_changed_cb(GtkWidget * dummy, gpointer user_data);
00117 void gnc_ui_commodity_quote_info_cb(GtkWidget *w, gpointer data);
00118 gboolean gnc_ui_commodity_dialog_to_object(CommodityWindow * w);
00119 
00120 #if 0
00121 static void gnc_ui_select_commodity_response_cb (GtkDialog * dialog, gint response, gpointer data);
00122 #endif
00123 
00124 
00125 /********************************************************************
00126  * gnc_ui_commodity_set_help_callback
00127  ********************************************************************/
00128 
00129 void
00130 gnc_ui_commodity_set_help_callback (gnc_commodity_help_callback cb)
00131 {
00132   help_callback = cb;
00133 }
00134 
00135 
00136 /********************************************************************
00137  * gnc_ui_select_commodity_modal_full()
00138  ********************************************************************/
00139 gnc_commodity * 
00140 gnc_ui_select_commodity_modal_full(gnc_commodity * orig_sel, 
00141                                    GtkWidget * parent,
00142                                    dialog_commodity_mode mode,
00143                                    const char * user_message,
00144                                    const char * cusip,
00145                                    const char * fullname,
00146                                    const char * mnemonic)
00147 {
00148   gnc_commodity * retval = NULL;
00149   const gchar *initial;
00150   gchar *user_prompt_text;
00151   SelectCommodityWindow * win;
00152   gboolean done;
00153   gint value;
00154   
00155   win = gnc_ui_select_commodity_create(orig_sel, mode);
00156   win->default_cusip=cusip;
00157   win->default_fullname=fullname;
00158   win->default_mnemonic=mnemonic;
00159   
00160   if (parent)
00161     gtk_window_set_transient_for (GTK_WINDOW (win->dialog), GTK_WINDOW (parent));
00162 
00163   if (user_message != NULL)
00164     initial = user_message;
00165   else if ((cusip != NULL) || (fullname != NULL) || (mnemonic != NULL))
00166     initial = _("\nPlease select a commodity to match:");
00167   else
00168     initial = "";
00169 
00170   user_prompt_text =
00171     g_strdup_printf("%s%s%s%s%s%s%s",
00172                     initial,
00173                     fullname ? _("\nCommodity: ") : "",
00174                     fullname ? fullname : "",
00175                     cusip    ? _("\nExchange code (CUSIP or similar): ") : "",
00176                     cusip    ? cusip : "",
00177                     mnemonic ? _("\nMnemonic(Ticker symbol or similar): ") : "",
00178                     mnemonic ? mnemonic : "");
00179    gtk_label_set_text ((GtkLabel *)(win->select_user_prompt),
00180                       user_prompt_text);
00181    g_free(user_prompt_text);
00182 
00183   /* Run the dialog, handling the terminal conditions. */
00184   done = FALSE;
00185   while (!done) {
00186     switch (value = gtk_dialog_run(GTK_DIALOG(win->dialog))) {
00187      case GTK_RESPONSE_OK:
00188       DEBUG("case OK");
00189       retval = win->selection;
00190       done = TRUE;
00191       break;
00192      case GNC_RESPONSE_NEW:
00193       DEBUG("case NEW");
00194       gnc_ui_select_commodity_new_cb(NULL, win);
00195       break;
00196      default:   /* Cancel, Escape, Close, etc. */
00197       DEBUG("default: %d", value);
00198       retval = NULL;
00199       done = TRUE;
00200       break;
00201     }
00202   }
00203   gtk_widget_destroy (GTK_WIDGET (win->dialog)); /* Close and destroy */
00204   g_free(win);
00205   
00206   return retval;
00207 }
00208 
00209 /********************************************************************
00210  * gnc_ui_select_commodity_modal()
00211  ********************************************************************/
00212 
00213 gnc_commodity *
00214 gnc_ui_select_commodity_modal(gnc_commodity * orig_sel,
00215                               GtkWidget * parent,
00216                               dialog_commodity_mode mode)
00217 {
00218   return gnc_ui_select_commodity_modal_full(orig_sel, 
00219                                             parent,
00220                                             mode,
00221                                             NULL,
00222                                             NULL,
00223                                             NULL,
00224                                             NULL);
00225 }
00226 
00227 
00228 /********************************************************************
00229  * gnc_ui_select_commodity_create()
00230  ********************************************************************/
00231 
00232 static SelectCommodityWindow *
00233 gnc_ui_select_commodity_create(const gnc_commodity * orig_sel,
00234                                dialog_commodity_mode mode)
00235 {
00236   SelectCommodityWindow * retval = g_new0(SelectCommodityWindow, 1);
00237   GladeXML *xml;
00238   const char *title, *text;
00239   gchar *namespace;
00240   GtkWidget *button, *label;
00241 
00242   xml = gnc_glade_xml_new ("commodity.glade", "Security Selector Dialog");
00243   glade_xml_signal_autoconnect_full( xml,
00244                                      gnc_glade_autoconnect_full_func,
00245                                      retval );
00246 
00247   retval->dialog = glade_xml_get_widget (xml, "Security Selector Dialog");
00248   retval->namespace_combo = glade_xml_get_widget (xml, "namespace_cbe");
00249   retval->commodity_combo = glade_xml_get_widget (xml, "commodity_cbe");
00250   retval->select_user_prompt = glade_xml_get_widget (xml, "select_user_prompt");
00251   retval->ok_button = glade_xml_get_widget (xml, "ok_button");
00252   label = glade_xml_get_widget (xml, "item_label");
00253 
00254   gtk_combo_box_remove_text(GTK_COMBO_BOX(retval->namespace_combo), 0);
00255   gtk_combo_box_remove_text(GTK_COMBO_BOX(retval->commodity_combo), 0);
00256   gnc_cbe_require_list_item(GTK_COMBO_BOX_ENTRY(retval->namespace_combo));
00257   gnc_cbe_require_list_item(GTK_COMBO_BOX_ENTRY(retval->commodity_combo));
00258 
00259   gtk_label_set_text (GTK_LABEL (retval->select_user_prompt), "");
00260 
00261 #ifdef DRH
00262   g_signal_connect (G_OBJECT (retval->dialog), "close",
00263                     G_CALLBACK (select_commodity_close), retval);
00264   g_signal_connect (G_OBJECT (retval->dialog), "response",
00265                     G_CALLBACK (gnc_ui_select_commodity_response_cb), retval);
00266 #endif
00267 
00268   switch (mode) {
00269     case DIAG_COMM_ALL:
00270       title = _("Select security/currency");
00271       text = _("_Security/currency:");
00272       break;
00273     case DIAG_COMM_NON_CURRENCY:
00274       title = _("Select security");
00275       text = _("_Security:");
00276       break;
00277     case DIAG_COMM_CURRENCY:
00278     default:
00279       title = _("Select currency");
00280       text = _("Cu_rrency:");
00281       button = glade_xml_get_widget (xml, "new_button");
00282       gtk_widget_destroy(button);
00283       break;
00284   }
00285   gtk_window_set_title (GTK_WINDOW(retval->dialog), title);
00286   gtk_label_set_text_with_mnemonic (GTK_LABEL(label), text);
00287 
00288   /* build the menus of namespaces and commodities */
00289   gnc_ui_update_namespace_picker(retval->namespace_combo,
00290                                  gnc_commodity_get_namespace(orig_sel),
00291                                  mode);
00292   namespace = gnc_ui_namespace_picker_ns(retval->namespace_combo);
00293   gnc_ui_update_commodity_picker(retval->commodity_combo, namespace,
00294                                  gnc_commodity_get_printname(orig_sel));
00295   g_free(namespace);
00296   return retval;
00297 }
00298 
00299 
00314 void
00315 gnc_ui_select_commodity_new_cb(GtkButton * button,
00316                                gpointer user_data)
00317 {
00318   SelectCommodityWindow * w = user_data;
00319 
00320   gchar * namespace = gnc_ui_namespace_picker_ns (w->namespace_combo);
00321 
00322   const gnc_commodity * new_commodity = 
00323     gnc_ui_new_commodity_modal_full(namespace,
00324                                     w->dialog,
00325                                     w->default_cusip,
00326                                     w->default_fullname,
00327                                     w->default_mnemonic,
00328                                     w->default_fraction);
00329   if(new_commodity) {
00330     gnc_ui_update_namespace_picker(w->namespace_combo, 
00331                                    gnc_commodity_get_namespace(new_commodity),
00332                                    DIAG_COMM_ALL);
00333     gnc_ui_update_commodity_picker(w->commodity_combo,
00334                                    gnc_commodity_get_namespace(new_commodity),
00335                                    gnc_commodity_get_printname(new_commodity));
00336   }
00337   g_free(namespace);
00338 }
00339 
00340 
00356 void
00357 gnc_ui_select_commodity_changed_cb (GtkComboBoxEntry *cbe,
00358                                     gpointer user_data)
00359 {
00360   SelectCommodityWindow * w = user_data;
00361   gchar *namespace, *fullname;
00362   gboolean ok;
00363 
00364   ENTER("cbe=%p, user_data=%p", cbe, user_data);
00365   namespace = gnc_ui_namespace_picker_ns (w->namespace_combo);
00366   fullname = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w->commodity_combo));
00367   DEBUG("namespace=%s, name=%s", namespace, fullname);
00368   w->selection = gnc_commodity_table_find_full(gnc_get_current_commodities(), 
00369                                                namespace, fullname);
00370   g_free(fullname);
00371   g_free(namespace);
00372 
00373   ok = (w->selection != NULL);
00374   gtk_widget_set_sensitive(w->ok_button, ok);
00375   gtk_dialog_set_default_response(GTK_DIALOG(w->dialog), ok ? 0 : 2);
00376   LEAVE("sensitive=%d, default = %d", ok, ok ? 0 : 2);
00377 }
00378 
00379 
00396 void
00397 gnc_ui_select_commodity_namespace_changed_cb (GtkComboBoxEntry *cbe,
00398                                               gpointer user_data)
00399 {
00400   SelectCommodityWindow * w = user_data;
00401   gchar *namespace;
00402 
00403   ENTER("cbe=%p, user_data=%p", cbe, user_data);
00404   namespace = gnc_ui_namespace_picker_ns (w->namespace_combo);
00405   DEBUG("namespace=%s", namespace);
00406   gnc_ui_update_commodity_picker(w->commodity_combo, namespace, NULL);
00407   g_free(namespace);
00408   LEAVE(" ");
00409 }
00410 
00411 
00412 /********************************************************************
00413  * gnc_ui_update_commodity_picker
00414  ********************************************************************/
00415 static int 
00416 collate(gconstpointer a, gconstpointer b)
00417 {
00418   if (!a)
00419     return -1;
00420   if (!b)
00421     return 1;
00422   return g_utf8_collate(a, b);
00423 }
00424 
00425 
00426 void
00427 gnc_ui_update_commodity_picker (GtkWidget *cbe,
00428                                 const gchar * namespace,
00429                                 const gchar * init_string)
00430 {
00431   GList      * commodities; 
00432   GList      * iterator = NULL;
00433   GList      * commodity_items = NULL;
00434   GtkComboBox *combo_box;
00435   GtkTreeModel *model;
00436   gnc_commodity_table *table;
00437   gint current = 0, match = 0;
00438   gchar *name;
00439 
00440   g_return_if_fail(GTK_IS_COMBO_BOX_ENTRY(cbe));
00441   g_return_if_fail(namespace);
00442 
00443   /* Erase the old entries */
00444   combo_box = GTK_COMBO_BOX(cbe);
00445   model = gtk_combo_box_get_model(combo_box);
00446   gtk_list_store_clear(GTK_LIST_STORE(model));
00447   gtk_combo_box_set_active(combo_box, -1);
00448 
00449   table = gnc_book_get_commodity_table (gnc_get_current_book ());
00450   commodities = gnc_commodity_table_get_commodities(table, namespace);
00451   for(iterator = commodities; iterator; iterator = iterator->next) {
00452     commodity_items = 
00453       g_list_append(commodity_items, 
00454                     (gpointer) gnc_commodity_get_printname(iterator->data));
00455   }
00456   g_list_free(commodities);
00457 
00458   commodity_items = g_list_sort(commodity_items, collate);
00459   for (iterator = commodity_items; iterator; iterator = iterator->next) {
00460     name = (char *)iterator->data;
00461     gtk_combo_box_append_text(combo_box, name);
00462     if (init_string && g_utf8_collate(name, init_string) == 0)
00463        match = current;
00464      current++;
00465   }
00466 
00467   gtk_combo_box_set_active(combo_box, match);
00468   g_list_free(commodity_items);
00469 }
00470 
00471 
00472 /********************************************************************
00473  * gnc_ui_update_namespace_picker
00474  ********************************************************************/
00475 
00476 #if 0
00477 void
00478 gnc_ui_select_commodity_destroy(SelectCommodityWindow * w) {
00479   g_return_if_fail (w != NULL);
00480 
00481   gtk_widget_destroy (GTK_WIDGET (w->dialog));
00482 }
00483 
00484 /********************************************************************
00485  * gnc_ui_select_commodity_ok_cb()
00486  ********************************************************************/
00487 
00488 static void
00489 gnc_ui_select_commodity_response_cb (GtkDialog * dialog, gint response, gpointer data)
00490 {
00491   SelectCommodityWindow * w = data;
00492   gchar *namespace;
00493   const gchar *fullname;
00494   gnc_commodity *commodity = NULL;
00495 
00496   switch (response) {
00497    case GTK_RESPONSE_OK:
00498     namespace = gnc_ui_namespace_picker_ns (w->namespace_combo);
00499     fullname = gtk_entry_get_text (GTK_ENTRY (w->commodity_entry));
00500 
00501     commodity = gnc_commodity_table_find_full (gnc_get_current_commodities (),
00502                                                namespace, fullname);
00503     g_free(namespace);
00504 
00505     if (commodity != NULL) {
00506       if (w->callback != NULL)
00507         (w->callback) (commodity, w->callback_data);
00508       gnc_ui_select_commodity_destroy (w);
00509     } else {
00510       gnc_warning_dialog (dialog,
00511                          _("You must select a commodity. "
00512                            "To create a new one, click \"New\""));
00513     }
00514     break;
00515    case GNC_RESPONSE_NEW:
00516     namespace = gnc_ui_namespace_picker_ns (w->namespace_combo);
00517 
00518     commodity = gnc_ui_new_commodity_modal_full (namespace,
00519                                                  w->dialog,
00520                                                  w->default_cusip,
00521                                                  w->default_fullname,
00522                                                  w->default_mnemonic,
00523                                                  w->default_fraction);
00524     if (commodity != NULL) {
00525       namespace =
00526         gnc_ui_update_namespace_picker (w->namespace_combo,
00527                                         gnc_commodity_get_namespace
00528                                         (commodity), TRUE, FALSE);
00529       gnc_ui_update_commodity_picker (w->commodity_combo,
00530                                       gnc_commodity_get_namespace (commodity),
00531                                       gnc_commodity_get_printname (commodity));
00532     }
00533     g_free(namespace);
00534     break;
00535    default:
00536     if (w->callback != NULL)
00537       (w->callback) (NULL, w->callback_data);
00538 
00539     gnc_ui_select_commodity_destroy (w);
00540     break;
00541   }
00542 }
00543 #endif
00544 
00545 /********************************************************************
00546  *
00547  * Commodity Selector dialog routines are above this line.
00548  *
00549  * Commodity New/Edit dialog routines are below this line.
00550  *
00551  ********************************************************************/
00552 
00553 static void
00554 gnc_set_commodity_section_sensitivity (GtkWidget *widget, gpointer user_data)
00555 {
00556   CommodityWindow *cw = user_data;
00557   guint offset = 0;
00558 
00559   gtk_container_child_get(GTK_CONTAINER(cw->table), widget,
00560                           "top-attach", &offset,
00561                           NULL);
00562 
00563   if ((offset < cw->comm_section_top) || (offset >= cw->comm_section_bottom))
00564     return;
00565   gtk_widget_set_sensitive(widget, !cw->is_currency);
00566 }
00567 
00568 static void
00569 gnc_ui_update_commodity_info (CommodityWindow *cw)
00570 {
00571   gtk_container_foreach(GTK_CONTAINER(cw->table),
00572                         gnc_set_commodity_section_sensitivity, cw);
00573 }
00574 
00575 static void
00576 gnc_set_fq_sensitivity (GtkWidget *widget, gpointer user_data)
00577 {
00578   CommodityWindow *cw = user_data;
00579   guint offset = 0;
00580 
00581   gtk_container_child_get(GTK_CONTAINER(cw->table), widget,
00582                           "top-attach", &offset,
00583                           NULL);
00584 
00585   if ((offset < cw->fq_section_top) || (offset >= cw->fq_section_bottom))
00586     return;
00587   g_object_set(widget, "sensitive", FALSE, NULL);
00588 }
00589 
00590 static void
00591 gnc_ui_update_fq_info (CommodityWindow *cw)
00592 {
00593   gtk_container_foreach(GTK_CONTAINER(cw->table),
00594                         gnc_set_fq_sensitivity, cw);
00595 }
00596 
00597 /********************************************************************
00598  * gnc_ui_update_namespace_picker
00599  ********************************************************************/
00600 
00601 void
00602 gnc_ui_update_namespace_picker (GtkWidget *cbe,
00603                                 const char * init_string,
00604                                 dialog_commodity_mode mode)
00605 {
00606   GtkComboBox *combo_box;
00607   GtkTreeModel *model;
00608   GList *namespaces, *node;
00609   gint current = 0, match = 0;
00610 
00611   g_return_if_fail(GTK_IS_COMBO_BOX_ENTRY(cbe));
00612 
00613   /* Erase the old entries */
00614   combo_box = GTK_COMBO_BOX(cbe);
00615   model = gtk_combo_box_get_model(combo_box);
00616   gtk_list_store_clear(GTK_LIST_STORE(model));
00617   gtk_combo_box_set_active(combo_box, -1);
00618 
00619   /* fetch a list of the namespaces */
00620   switch (mode) {
00621     case DIAG_COMM_ALL:
00622       namespaces =
00623         gnc_commodity_table_get_namespaces (gnc_get_current_commodities());
00624       break;
00625 
00626    case DIAG_COMM_NON_CURRENCY:
00627      namespaces =
00628        gnc_commodity_table_get_namespaces (gnc_get_current_commodities());
00629      node = g_list_find_custom (namespaces, GNC_COMMODITY_NS_CURRENCY, collate);
00630      if (node) {
00631        namespaces = g_list_remove_link (namespaces, node);
00632        g_list_free_1 (node);
00633      }
00634 
00635      if (gnc_commodity_namespace_is_iso (init_string))
00636        init_string = NULL;
00637      break;
00638 
00639    case DIAG_COMM_CURRENCY:
00640    default:
00641     namespaces = g_list_prepend (NULL, GNC_COMMODITY_NS_CURRENCY);
00642     break;     
00643   }
00644 
00645   /* stick them in the combobox */
00646   namespaces = g_list_sort(namespaces, collate);
00647   for (node = namespaces; node; node = node->next) {
00648     if (g_utf8_collate(node->data, GNC_COMMODITY_NS_LEGACY) == 0)
00649       continue;
00650      gtk_combo_box_append_text(combo_box, node->data);
00651      if (init_string && (g_utf8_collate(node->data, init_string) == 0))
00652        match = current;
00653      current++;
00654   }
00655 
00656   gtk_combo_box_set_active(combo_box, match);
00657   g_list_free(namespaces);
00658 }
00659 
00660 gchar *
00661 gnc_ui_namespace_picker_ns (GtkWidget *cbe)
00662 {
00663   char *namespace;
00664 
00665   g_return_val_if_fail(GTK_IS_COMBO_BOX_ENTRY (cbe), NULL);
00666 
00667   namespace = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cbe));
00668 
00669   if (safe_strcmp (namespace, GNC_COMMODITY_NS_ISO) == 0) {
00670     /* In case the user types in ISO4217, map it to CURRENCY. */
00671     g_free(namespace);
00672     return strdup(GNC_COMMODITY_NS_CURRENCY);
00673   } else
00674     return namespace;
00675 }
00676 
00677 /********************************************************************/
00678 
00679 void
00680 gnc_ui_commodity_quote_info_cb (GtkWidget *w, gpointer data)
00681 {
00682   CommodityWindow *cw = data;
00683   gboolean get_quote, allow_src, active;
00684   gchar *text;
00685   gint i;
00686 
00687   ENTER(" ");
00688   get_quote = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
00689 
00690   text = gtk_combo_box_get_active_text(GTK_COMBO_BOX(cw->namespace_combo));
00691   allow_src = !gnc_commodity_namespace_is_iso(text);
00692   g_free(text);
00693   gtk_widget_set_sensitive(cw->source_label, get_quote && allow_src);
00694 
00695   for (i = SOURCE_SINGLE; i < SOURCE_MAX; i++) {
00696     if (!cw->source_button[i])
00697       continue;
00698     active =
00699       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cw->source_button[i]));
00700     gtk_widget_set_sensitive(cw->source_button[i], get_quote && allow_src);
00701     gtk_widget_set_sensitive(cw->source_menu[i], get_quote && allow_src && active);
00702   }
00703   gtk_widget_set_sensitive(cw->quote_tz_label, get_quote);
00704   gtk_widget_set_sensitive(cw->quote_tz_menu, get_quote);
00705   LEAVE(" ");
00706 }
00707 
00708 void
00709 gnc_ui_commodity_changed_cb(GtkWidget * dummy, gpointer user_data)
00710 {
00711   CommodityWindow * w = user_data;
00712   gchar *namespace;
00713   const char * fullname;
00714   const char * mnemonic;
00715   gboolean ok;
00716 
00717   ENTER("widget=%p, user_data=%p", dummy, user_data);
00718   if (!w->is_currency) {
00719     namespace = gnc_ui_namespace_picker_ns (w->namespace_combo);
00720     fullname  = gtk_entry_get_text(GTK_ENTRY(w->fullname_entry));
00721     mnemonic  = gtk_entry_get_text(GTK_ENTRY(w->mnemonic_entry));
00722     DEBUG("namespace=%s, name=%s, mnemonic=%s", namespace, fullname, mnemonic);
00723     ok = (fullname    && namespace    && mnemonic &&
00724           fullname[0] && namespace[0] && mnemonic[0]);
00725     g_free(namespace);
00726   } else {
00727     ok = TRUE;
00728   }
00729   gtk_widget_set_sensitive(w->ok_button, ok);
00730   gtk_dialog_set_default_response(GTK_DIALOG(w->dialog), ok ? 0 : 1);
00731   LEAVE("sensitive=%d, default = %d", ok, ok ? 0 : 1);
00732 }
00733 
00734 /********************************************************************\
00735  * gnc_ui_source_menu_create                                        *
00736  *   create the menu of stock quote sources                         *
00737  *                                                                  *
00738  * Args:    account - account to use to set default choice          *
00739  * Returns: the menu                                                *
00740  \*******************************************************************/
00741 static GtkWidget *
00742 gnc_ui_source_menu_create(QuoteSourceType type)
00743 {
00744   gint i, max;
00745   const gchar *name;
00746   gboolean supported;
00747   GtkListStore *store;
00748   GtkTreeIter iter;
00749   GtkWidget *combo;
00750   GtkCellRenderer *renderer;
00751   gnc_quote_source *source;
00752 
00753   store = gtk_list_store_new(NUM_SOURCE_COLS, G_TYPE_STRING, G_TYPE_BOOLEAN);
00754   if (type == SOURCE_CURRENCY) {
00755     gtk_list_store_append(store, &iter);
00756     gtk_list_store_set(store, &iter, 
00757                        SOURCE_COL_NAME, _("Currency"),
00758                        SOURCE_COL_FQ_SUPPORTED, TRUE,
00759                        -1);
00760   } else {
00761     max = gnc_quote_source_num_entries(type);
00762     for (i = 0; i < max; i++) {
00763         source = gnc_quote_source_lookup_by_ti(type, i);
00764         if (source == NULL)
00765           break;
00766         name = gnc_quote_source_get_user_name(source);
00767         supported = gnc_quote_source_get_supported(source);
00768         gtk_list_store_append(store, &iter);
00769         gtk_list_store_set(store, &iter,
00770                            SOURCE_COL_NAME, name,
00771                            SOURCE_COL_FQ_SUPPORTED, supported,
00772                            -1);
00773       }
00774   }
00775 
00776   combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
00777   g_object_unref(store);
00778   renderer = gtk_cell_renderer_text_new();
00779   gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), renderer, TRUE);
00780   gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(combo), renderer,
00781                                 "text", SOURCE_COL_NAME);
00782   gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(combo), renderer,
00783                                 "sensitive", SOURCE_COL_FQ_SUPPORTED);
00784   gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
00785   gtk_widget_show(combo);
00786   return combo;
00787 }
00788 
00789 /********************************************************************\
00790  * price quote timezone handling
00791  */
00792 
00793 static gchar *
00794 known_timezones[] =
00795 {
00796   "Asia/Tokyo",
00797   "Australia/Sydney",
00798   "America/New_York",
00799   "America/Chicago",
00800   "Europe/London",
00801   "Europe/Paris",
00802   NULL
00803 };
00804 
00805 static guint
00806 gnc_find_timezone_menu_position(const gchar *timezone)
00807 {
00808   /* returns 0 on failure, position otherwise. */
00809   gboolean found = FALSE;
00810   guint i = 0;
00811   while(!found && known_timezones[i]) {
00812     if(safe_strcmp(timezone, known_timezones[i]) != 0) {
00813       i++;
00814     } else {
00815       found = TRUE;
00816     }
00817   }
00818   if(found) return i + 1;
00819   return 0;
00820 }
00821 
00822 static gchar *
00823 gnc_timezone_menu_position_to_string(guint pos)
00824 {
00825   if(pos == 0) return NULL;
00826   return known_timezones[pos - 1];
00827 }
00828 
00829 static GtkWidget *
00830 gnc_ui_quote_tz_menu_create(void)
00831 {
00832   GtkWidget  *combo;
00833   gchar     **itemstr;
00834 
00835   /* add items here as needed, but bear in mind that right now these
00836      must be timezones that GNU libc understands.  Also, I'd prefer if
00837      we only add things here we *know* we need.  That's because in
00838      order to be portable to non GNU OSes, we may have to support
00839      whatever we add here manually on those systems. */
00840 
00841   combo = gtk_combo_box_new_text();
00842   gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Use local time"));
00843   for(itemstr = &known_timezones[0]; *itemstr; itemstr++) {
00844     gtk_combo_box_append_text(GTK_COMBO_BOX(combo), *itemstr);
00845   }
00846 
00847   gtk_widget_show(combo);
00848   return combo;
00849 }
00850 
00853 static CommodityWindow *
00854 gnc_ui_build_commodity_dialog(const char * selected_namespace,
00855                             GtkWidget  *parent,
00856                             const char * fullname,
00857                             const char * mnemonic,
00858                             const char * cusip,
00859                             int          fraction,
00860                             gboolean     edit)
00861 {
00862   CommodityWindow * retval = g_new0(CommodityWindow, 1);
00863   GtkWidget *help_button;
00864   GtkWidget *box;
00865   GtkWidget *menu;
00866   GtkWidget *widget, *sec_label;
00867   GladeXML *xml;
00868   gboolean include_iso;
00869   const gchar *title;
00870   gchar *text;
00871 
00872   ENTER(" ");
00873   xml = gnc_glade_xml_new ("commodity.glade", "Security Dialog");
00874 
00875   glade_xml_signal_autoconnect_full( xml,
00876                                      gnc_glade_autoconnect_full_func,
00877                                      retval );
00878 
00879   retval->dialog = glade_xml_get_widget (xml, "Security Dialog");
00880   if (parent != NULL)
00881     gtk_window_set_transient_for (GTK_WINDOW (retval->dialog), GTK_WINDOW (parent));
00882   retval->edit_commodity = NULL;
00883 
00884   help_button = glade_xml_get_widget (xml, "help_button");
00885   if (!help_callback)
00886     gtk_widget_hide (help_button);
00887 
00888   /* Determine the commodity section of the dialog */
00889   retval->table = glade_xml_get_widget (xml, "edit_table");
00890   sec_label = glade_xml_get_widget (xml, "security_label");
00891   gtk_container_child_get(GTK_CONTAINER(retval->table), sec_label,
00892                           "bottom-attach", &retval->comm_section_top, NULL);
00893   widget = glade_xml_get_widget (xml, "quote_label");
00894   gtk_container_child_get(GTK_CONTAINER(retval->table), widget,
00895                           "top-attach", &retval->comm_section_bottom, NULL);
00896 
00897   /* Get widget pointers */
00898   retval->fullname_entry = glade_xml_get_widget (xml, "fullname_entry");
00899   retval->mnemonic_entry = glade_xml_get_widget (xml, "mnemonic_entry");
00900   retval->namespace_combo = glade_xml_get_widget (xml, "namespace_cbe");
00901   retval->code_entry = glade_xml_get_widget (xml, "code_entry");
00902   retval->fraction_spinbutton = glade_xml_get_widget (xml,
00903                                                       "fraction_spinbutton");
00904   retval->ok_button = glade_xml_get_widget (xml, "ok_button");
00905   retval->get_quote_check = glade_xml_get_widget (xml, "get_quote_check");
00906   retval->source_label = glade_xml_get_widget (xml, "source_label");
00907   retval->source_button[SOURCE_SINGLE] = glade_xml_get_widget (xml, "single_source_button");
00908   retval->source_button[SOURCE_MULTI] = glade_xml_get_widget (xml, "multi_source_button");
00909   retval->quote_tz_label = glade_xml_get_widget (xml, "quote_tz_label");
00910 
00911 
00912   /* Build custom widgets */
00913   box = glade_xml_get_widget (xml, "single_source_box");
00914   if (gnc_commodity_namespace_is_iso(selected_namespace)) {
00915     menu = gnc_ui_source_menu_create(SOURCE_CURRENCY);
00916   } else {
00917     menu = gnc_ui_source_menu_create(SOURCE_SINGLE);
00918   }
00919   retval->source_menu[SOURCE_SINGLE] = menu;
00920   gtk_box_pack_start(GTK_BOX(box), menu, TRUE, TRUE, 0);
00921 
00922   box = glade_xml_get_widget (xml, "multi_source_box");
00923   menu = gnc_ui_source_menu_create(SOURCE_MULTI);
00924   retval->source_menu[SOURCE_MULTI] = menu;
00925   gtk_box_pack_start(GTK_BOX(box), menu, TRUE, TRUE, 0);
00926 
00927   if (gnc_quote_source_num_entries(SOURCE_UNKNOWN)) {
00928     retval->source_button[SOURCE_UNKNOWN] =
00929       glade_xml_get_widget (xml, "unknown_source_button");
00930     box = glade_xml_get_widget (xml, "unknown_source_box");
00931     menu = gnc_ui_source_menu_create(SOURCE_UNKNOWN);
00932     retval->source_menu[SOURCE_UNKNOWN] = menu;
00933     gtk_box_pack_start(GTK_BOX(box), menu, TRUE, TRUE, 0);
00934   } else {
00935     guint row;
00936 
00937     widget = glade_xml_get_widget (xml, "unknown_source_alignment");
00938     gtk_container_child_get(GTK_CONTAINER(retval->table), widget,
00939                             "top-attach", &row, NULL);
00940     gtk_table_set_row_spacing(GTK_TABLE(retval->table), row, 0);
00941     gtk_widget_destroy(widget);
00942     widget = glade_xml_get_widget (xml, "unknown_source_box");
00943     gtk_widget_destroy(widget);
00944   }
00945 
00946   box = glade_xml_get_widget (xml, "quote_tz_box");
00947   retval->quote_tz_menu = gnc_ui_quote_tz_menu_create();
00948   gtk_box_pack_start(GTK_BOX(box), retval->quote_tz_menu, TRUE, TRUE, 0);
00949 
00950 
00951   /* Commodity editing is next to nil */
00952   if (gnc_commodity_namespace_is_iso(selected_namespace)) {
00953     retval->is_currency = TRUE;
00954     gnc_ui_update_commodity_info (retval);
00955     include_iso = TRUE;
00956     title = _("Edit currency");
00957     text = g_strdup_printf("<b>%s</b>", _("Currency Information"));
00958   } else {
00959     include_iso = FALSE;
00960     title = edit ? _("Edit security") : _("New security");
00961     text = g_strdup_printf("<b>%s</b>", _("Security Information"));
00962   }
00963   gtk_window_set_title(GTK_WINDOW(retval->dialog), title);
00964   gtk_label_set_markup(GTK_LABEL(sec_label), text);
00965   g_free(text);
00966 
00967   /* Are price quotes supported */
00968   if (gnc_quote_source_fq_installed()) {
00969     gtk_widget_destroy(glade_xml_get_widget (xml, "finance_quote_warning"));
00970   } else {
00971     /* Determine the price quote of the dialog */
00972     widget = glade_xml_get_widget (xml, "fq_warning_alignment");
00973     gtk_container_child_get(GTK_CONTAINER(retval->table), widget,
00974                             "bottom-attach", &retval->fq_section_top, NULL);
00975     widget = glade_xml_get_widget (xml, "quote_tz_alignment");
00976     gtk_container_child_get(GTK_CONTAINER(retval->table), widget,
00977                             "bottom-attach", &retval->fq_section_bottom, NULL);
00978     gnc_ui_update_fq_info (retval);
00979   }
00980 
00981 
00982 #ifdef DRH
00983   g_signal_connect (G_OBJECT (retval->dialog), "close",
00984                     G_CALLBACK (commodity_close), retval);
00985 #endif
00986   /* Fill in any data, top to bottom */
00987   
00988   gtk_entry_set_text (GTK_ENTRY (retval->fullname_entry), fullname ? fullname : "");
00989   gtk_entry_set_text (GTK_ENTRY (retval->mnemonic_entry), mnemonic ? mnemonic : "");
00990   gnc_cbe_add_completion(GTK_COMBO_BOX_ENTRY(retval->namespace_combo));
00991   gtk_combo_box_remove_text(GTK_COMBO_BOX(retval->namespace_combo), 0);
00992   gnc_ui_update_namespace_picker(retval->namespace_combo,
00993                                  selected_namespace,
00994                                  include_iso ? DIAG_COMM_ALL : DIAG_COMM_NON_CURRENCY);
00995   gtk_entry_set_text (GTK_ENTRY (retval->code_entry), cusip ? cusip : "");
00996   if (fraction > 0)
00997     gtk_spin_button_set_value (GTK_SPIN_BUTTON (retval->fraction_spinbutton),
00998                                fraction);
00999 
01000   LEAVE(" ");
01001   return retval;
01002 }
01003 
01004 
01005 static void
01006 gnc_ui_commodity_update_quote_info(CommodityWindow *win,
01007                                    gnc_commodity *commodity)
01008 {
01009   gnc_quote_source *source;
01010   QuoteSourceType type;
01011   gboolean has_quote_src;
01012   const char *quote_tz;
01013   int pos = 0;
01014 
01015   ENTER(" ");
01016   has_quote_src = gnc_commodity_get_quote_flag (commodity);
01017   source = gnc_commodity_get_quote_source (commodity);
01018   if (source == NULL)
01019     source = gnc_commodity_get_default_quote_source (commodity);
01020   quote_tz = gnc_commodity_get_quote_tz (commodity);
01021 
01022   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (win->get_quote_check),
01023                                 has_quote_src);
01024   if (!gnc_commodity_is_iso(commodity)) {
01025     type = gnc_quote_source_get_type(source);
01026     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(win->source_button[type]), TRUE);
01027     gtk_combo_box_set_active(GTK_COMBO_BOX(win->source_menu[type]),
01028                              gnc_quote_source_get_index(source));
01029   }
01030 
01031   if (quote_tz) {
01032     pos = gnc_find_timezone_menu_position(quote_tz);
01033 //    if(pos == 0) {
01034 //      PWARN("Unknown price quote timezone (%s), resetting to default.",
01035 //          quote_tz ? quote_tz : "(null)");
01036 //    }
01037   }
01038   gtk_combo_box_set_active(GTK_COMBO_BOX(win->quote_tz_menu), pos);
01039   LEAVE(" ");
01040 }
01041 
01042 
01043 static gnc_commodity *
01044 gnc_ui_common_commodity_modal(gnc_commodity *commodity,
01045                               GtkWidget * parent,
01046                               const char * namespace,
01047                               const char * cusip,
01048                               const char * fullname,
01049                               const char * mnemonic,
01050                               int fraction)
01051 {
01052   CommodityWindow * win;
01053   gnc_commodity *retval = NULL;
01054   gboolean done;
01055   gint value;
01056 
01057   ENTER(" ");
01058 
01059   /* If a commodity was provided, copy out the existing info */
01060   if (commodity) {
01061     namespace = gnc_commodity_get_namespace (commodity);
01062     fullname = gnc_commodity_get_fullname (commodity);
01063     mnemonic = gnc_commodity_get_mnemonic (commodity);
01064     cusip = gnc_commodity_get_cusip (commodity);
01065     fraction = gnc_commodity_get_fraction (commodity);
01066   } else {
01067     /* Not allowed to create new currencies */
01068     if (gnc_commodity_namespace_is_iso(namespace)) {
01069       namespace = NULL;
01070     }
01071   }
01072 
01073   win = gnc_ui_build_commodity_dialog(namespace, parent, fullname,
01074                                     mnemonic, cusip, fraction,
01075                                     (commodity != NULL));
01076 
01077   /* Update stock quote info based on existing commodity */
01078   gnc_ui_commodity_update_quote_info(win, commodity);
01079   win->edit_commodity = commodity;
01080 
01081   /* Update stock quote sensitivities based on check box */
01082   gnc_ui_commodity_quote_info_cb(win->get_quote_check, win);
01083 
01084   /* Run the dialog, handling the terminal conditions. */
01085   done = FALSE;
01086   while (!done) {
01087     value = gtk_dialog_run(GTK_DIALOG(win->dialog));
01088     switch (value) {
01089      case GTK_RESPONSE_OK:
01090       DEBUG("case OK");
01091       done = gnc_ui_commodity_dialog_to_object(win);
01092       retval = win->edit_commodity;
01093       break;
01094      case GTK_RESPONSE_HELP:
01095       DEBUG("case HELP");
01096       if (help_callback)
01097         help_callback ();
01098       break;
01099      default:   /* Cancel, Escape, Close, etc. */
01100       DEBUG("default: %d", value);
01101       retval = NULL;
01102       done = TRUE;
01103       break;
01104     }
01105   }
01106   gtk_widget_destroy (GTK_WIDGET (win->dialog)); /* Close and destroy */
01107   g_free(win);
01108 
01109   LEAVE(" ");
01110   return retval;
01111 }
01112 
01113 
01114 
01117 gnc_commodity * 
01118 gnc_ui_new_commodity_modal_full(const char * namespace, 
01119                                 GtkWidget * parent,
01120                                 const char * cusip,
01121                                 const char * fullname,
01122                                 const char * mnemonic,
01123                                 int fraction)
01124 {
01125   gnc_commodity *result;
01126 
01127   ENTER(" ");
01128   result = gnc_ui_common_commodity_modal(NULL, parent, namespace, cusip,
01129                                          fullname, mnemonic, 10000);
01130   LEAVE(" ");
01131   return result;
01132 }
01133 
01136 gnc_commodity *
01137 gnc_ui_new_commodity_modal(const char * default_namespace,
01138                            GtkWidget * parent)
01139 {
01140   gnc_commodity *result;
01141 
01142   ENTER(" ");
01143   result = gnc_ui_common_commodity_modal(NULL, parent, default_namespace, NULL,
01144                                          NULL, NULL, 0);
01145   LEAVE(" ");
01146   return result;
01147 }
01148 
01149 /********************************************************************
01150  * gnc_ui_edit_commodity_modal()
01151  ********************************************************************/
01152 
01158 gboolean
01159 gnc_ui_edit_commodity_modal(gnc_commodity *commodity,
01160                             GtkWidget * parent)
01161 {
01162   gnc_commodity *result;
01163 
01164   ENTER(" ");
01165   result = gnc_ui_common_commodity_modal(commodity, parent, NULL, NULL,
01166                                          NULL, NULL, 0);
01167   LEAVE(" ");
01168   return result != NULL;
01169 }
01170 
01171 
01172 /********************************************************************
01173  * gnc_ui_commodity_dialog_to_object()
01174  ********************************************************************/
01175 
01176 gboolean
01177 gnc_ui_commodity_dialog_to_object(CommodityWindow * w)
01178 {
01179   gnc_quote_source *source;
01180   QuoteSourceType type;
01181   const char * fullname  = gtk_entry_get_text(GTK_ENTRY(w->fullname_entry));
01182   gchar *namespace = gnc_ui_namespace_picker_ns (w->namespace_combo);
01183   const char * mnemonic  = gtk_entry_get_text(GTK_ENTRY(w->mnemonic_entry));
01184   const char * code      = gtk_entry_get_text(GTK_ENTRY(w->code_entry));
01185   QofBook * book = gnc_get_current_book ();
01186   int fraction = gtk_spin_button_get_value_as_int
01187     (GTK_SPIN_BUTTON(w->fraction_spinbutton));
01188   const char *string;
01189   gnc_commodity * c;
01190   gint selection;
01191 
01192   ENTER(" ");
01193   /* Special case currencies */
01194   if (gnc_commodity_namespace_is_iso (namespace)) {
01195     if (w->edit_commodity) {
01196       c = w->edit_commodity;
01197       gnc_commodity_begin_edit(c);
01198       gnc_commodity_user_set_quote_flag (c, gtk_toggle_button_get_active
01199                                     (GTK_TOGGLE_BUTTON (w->get_quote_check)));
01200       selection = gtk_combo_box_get_active(GTK_COMBO_BOX(w->quote_tz_menu));
01201       string = gnc_timezone_menu_position_to_string(selection);
01202       gnc_commodity_set_quote_tz(c, string);
01203       gnc_commodity_commit_edit(c);
01204       return TRUE;
01205     }
01206     gnc_warning_dialog(w->dialog,
01207                        _("You may not create a new national currency."));
01208     return FALSE;
01209   }
01210 
01211   if(fullname && fullname[0] &&
01212      namespace && namespace[0] &&
01213      mnemonic && mnemonic[0]) {
01214     c = gnc_commodity_table_lookup (gnc_get_current_commodities(),
01215                                     namespace, mnemonic);
01216 
01217     if ((!w->edit_commodity && c) ||
01218         (w->edit_commodity && c && (c != w->edit_commodity))) {
01219       gnc_warning_dialog (w->dialog, _("That commodity already exists."));
01220       g_free(namespace);
01221       return