GnuCash 2.4.99
dialog-preferences.c
Go to the documentation of this file.
00001 /********************************************************************\
00002  * dialog-preferences.c -- preferences dialog                       *
00003  *                                                                  *
00004  * Copyright (C) 2005 David Hampton                                 *
00005  * Copyright (C) 2011 Robert Fewell                                 *
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 
00060 #include "config.h"
00061 
00062 #include <gtk/gtk.h>
00063 #include <glib/gi18n.h>
00064 
00065 #include "dialog-utils.h"
00066 #include "gnc-currency-edit.h"
00067 #include "gnc-date-edit.h"
00068 #include "gnc-gconf-utils.h"
00069 #include "gnc-gobject-utils.h"
00070 #include "gnc-period-select.h"
00071 #include "gnc-engine.h"
00072 #include "Account.h"
00073 #include "gnc-ui.h"
00074 #include "gnc-ui-util.h"
00075 #include "gnc-component-manager.h"
00076 #include "dialog-preferences.h"
00077 
00078 #define DIALOG_PREFERENCES_CM_CLASS     "dialog-newpreferences"
00079 #define GCONF_SECTION                   "dialogs/preferences"
00080 #define PREFIX_LEN                      sizeof("gconf/") - 1
00081 #define WIDGET_HASH                     "widget_hash"
00082 #define NOTEBOOK                        "notebook"
00083 
00085 static QofLogModule log_module = GNC_MOD_PREFS;
00086 
00087 void gnc_preferences_response_cb(GtkDialog *dialog, gint response, GtkDialog *unused);
00088 
00089 
00092 typedef struct addition_t
00093 {
00096     gchar *filename;
00100     gchar *widgetname;
00103     gchar *tabname;
00106     gboolean full_page;
00107 } addition;
00108 
00112 GSList *add_ins = NULL;
00113 
00114 
00125 static void
00126 gnc_account_separator_prefs_cb (GConfEntry *unused, GtkWidget *dialog)
00127 {
00128     GtkWidget *label, *image;
00129     gchar *sample;
00130     GList *invalid_account_names;
00131     QofBook *book;
00132 
00133     label = g_object_get_data(G_OBJECT(dialog), "sample_account");
00134     DEBUG("Sample Account pointer is %p", label );
00135     /* Translators: Both %s will be the account separator character; the
00136        resulting string is a demonstration how the account separator
00137        character will look like. You can replace these three account
00138        names with other account names that are more suitable for your
00139        language - just keep in mind to have exactly two %s in your
00140        translation. */
00141     sample = g_strdup_printf(_("Income%sSalary%sTaxable"),
00142                              gnc_get_account_separator_string(),
00143                              gnc_get_account_separator_string());
00144     PINFO(" Label set to '%s'", sample);
00145     gtk_label_set_text(GTK_LABEL(label), sample);
00146     g_free(sample);
00147 
00148     /* Check if the new separator clashes with existing account names */
00149     image = g_object_get_data(G_OBJECT(dialog), "separator_error");
00150     DEBUG("Separator Error Image pointer is %p", image );
00151     book = gnc_get_current_book();
00152     invalid_account_names = gnc_account_list_name_violations ( book,
00153                             gnc_get_account_separator_string() );
00154     if ( invalid_account_names )
00155     {
00156         gchar *message = gnc_account_name_violations_errmsg ( gnc_get_account_separator_string(),
00157                          invalid_account_names );
00158         gnc_warning_dialog(dialog, "%s", message);
00159         gtk_widget_set_tooltip_text(GTK_WIDGET(image), message);
00160         gtk_widget_show (GTK_WIDGET(image));
00161         g_free ( message );
00162     }
00163     else
00164         gtk_widget_hide (GTK_WIDGET(image));
00165 
00166     g_list_free ( invalid_account_names );
00167 }
00168 
00169 
00181 static gint
00182 gnc_prefs_compare_addins (addition *a,
00183                           addition *b)
00184 {
00185     return g_utf8_collate(a->tabname, b->tabname);
00186 }
00187 
00188 
00208 static void
00209 gnc_preferences_add_page_internal (const gchar *filename,
00210                                    const gchar *widgetname,
00211                                    const gchar *tabname,
00212                                    gboolean full_page)
00213 {
00214     addition *add_in, *preexisting;
00215     gboolean error = FALSE;
00216     GSList *ptr;
00217 
00218     ENTER("file %s, widget %s, tab %s full page %d",
00219           filename, widgetname, tabname, full_page);
00220 
00221     add_in = g_malloc(sizeof(addition));
00222     if (add_in == NULL)
00223     {
00224         g_critical("Unable to allocate memory.\n");
00225         LEAVE("no memory");
00226         return;
00227     }
00228 
00229     add_in->filename   = g_strdup(filename);
00230     add_in->widgetname = g_strdup(widgetname);
00231     add_in->tabname    = g_strdup(tabname);
00232     add_in->full_page  = full_page;
00233     if (!add_in->filename || !add_in->widgetname || !add_in->tabname)
00234     {
00235         g_critical("Unable to allocate memory.\n");
00236         g_free(add_in->filename);
00237         g_free(add_in->widgetname);
00238         g_free(add_in->tabname);
00239         g_free(add_in);
00240         LEAVE("no memory");
00241         return;
00242     }
00243 
00244     ptr = g_slist_find_custom(add_ins, add_in, (GCompareFunc)gnc_prefs_compare_addins);
00245     if (ptr)
00246     {
00247         /* problem? */
00248         preexisting = ptr->data;
00249 
00250         if (preexisting->full_page)
00251         {
00252             g_warning("New tab %s(%s/%s/%s) conflicts with existing tab %s(%s/%s/full)",
00253                       add_in->tabname, add_in->filename, add_in->widgetname,
00254                       add_in->full_page ? "full" : "partial",
00255                       preexisting->tabname, preexisting->filename, preexisting->widgetname);
00256             error = TRUE;
00257         }
00258         else if (add_in->full_page)
00259         {
00260             g_warning("New tab %s(%s/%s/%s) conflicts with existing tab %s(%s/%s/partial)",
00261                       add_in->tabname, add_in->filename, add_in->widgetname,
00262                       add_in->full_page ? "full" : "partial",
00263                       preexisting->tabname, preexisting->filename, preexisting->widgetname);
00264             error = TRUE;
00265         }
00266     }
00267 
00268     if (error)
00269     {
00270         g_free(add_in->filename);
00271         g_free(add_in->widgetname);
00272         g_free(add_in->tabname);
00273         g_free(add_in);
00274         LEAVE("err");
00275         return;
00276     }
00277     else
00278     {
00279         add_ins = g_slist_append(add_ins, add_in);
00280     }
00281     LEAVE("");
00282 }
00283 
00284 
00285 /*  This function adds a full page of preferences to the preferences
00286  *  dialog.  When the dialog is created, the specified content will be
00287  *  pulled from the specified glade file and added to the preferences
00288  *  dialog with the specified tab name.  The tab name may not be
00289  *  duplicated.  For example, the Business code might have a full page
00290  *  of its own preferences. */
00291 void
00292 gnc_preferences_add_page (const gchar *filename,
00293                           const gchar *widgetname,
00294                           const gchar *tabname)
00295 {
00296     gnc_preferences_add_page_internal(filename, widgetname, tabname, TRUE);
00297 }
00298 
00299 
00300 /*  This function adds a partial page of preferences to the
00301  *  preferences dialog.  When the dialog is created, the specified
00302  *  content will be pulled from the glade file and added to the
00303  *  preferences dialog with the specified tab name.  The tab name
00304  *  may be duplicated.  For example, the HBCI preferences may share a
00305  *  "Data Import" page with QIF and other methods. */
00306 void
00307 gnc_preferences_add_to_page (const gchar *filename,
00308                              const gchar *widgetname,
00309                              const gchar *tabname)
00310 {
00311     gnc_preferences_add_page_internal(filename, widgetname, tabname, FALSE);
00312 }
00313 
00314 
00315 /*******************************************************************/
00316 
00330 static void
00331 gnc_prefs_build_widget_table (GtkBuilder *builder,
00332                               GtkWidget *dialog)
00333 {
00334     GHashTable *table;
00335     GSList *interesting, *runner;
00336     const gchar *name;
00337     const gchar *wname;
00338     GtkWidget *widget;
00339 
00340     table = g_object_get_data(G_OBJECT(dialog), WIDGET_HASH);
00341 
00342     interesting = gtk_builder_get_objects(builder);
00343 
00344     for (runner = interesting; runner; runner = g_slist_next(runner))
00345     {
00346         widget = runner->data;
00347         if (GTK_IS_WIDGET(widget))
00348         {
00349             wname = gtk_widget_get_name(widget);
00350             name = gtk_buildable_get_name(GTK_BUILDABLE(widget));
00351             DEBUG("Widget type is %s and buildable get name is %s", wname, name);
00352             if (g_str_has_prefix (name, "gconf"))
00353                 g_hash_table_insert(table, (gchar *)name, widget);
00354         }
00355     }
00356     g_slist_free(interesting);
00357 }
00358 
00359 
00365 struct copy_data
00366 {
00368     GtkTable *table_from;
00370     GtkTable *table_to;
00373     gint row_offset;
00374 };
00375 
00376 
00377 static GtkWidget *
00378 gnc_prefs_find_page (GtkNotebook *notebook, const gchar *name)
00379 {
00380     int n_pages, i;
00381     GtkWidget *child;
00382     const gchar *child_name;
00383 
00384     g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
00385     g_return_val_if_fail (name, NULL);
00386 
00387     ENTER("");
00388 
00389     n_pages = gtk_notebook_get_n_pages (notebook);
00390 
00391     for (i = 0; i < n_pages; i++)
00392     {
00393         child = gtk_notebook_get_nth_page (notebook, i);
00394         g_return_val_if_fail (child, NULL);
00395 
00396         child_name = gtk_notebook_get_tab_label_text (notebook, child);
00397         g_return_val_if_fail (child_name, NULL);
00398 
00399         if (g_utf8_collate (name, child_name) == 0)
00400         {
00401             LEAVE("found at index: %d", i);
00402             return child;
00403         }
00404     }
00405 
00406     LEAVE("not found");
00407     return NULL;
00408 }
00409 
00410 
00423 static void
00424 gnc_prefs_move_table_entry (GtkWidget *child,
00425                             gpointer data)
00426 {
00427     struct copy_data *copydata = data;
00428     GtkAttachOptions x_opts, y_opts;
00429     gint bottom, top, left, right, x_pad, y_pad;
00430 
00431     ENTER("child %p, copy data %p", child, data);
00432     gtk_container_child_get(GTK_CONTAINER(copydata->table_from), child,
00433                             "bottom-attach", &bottom,
00434                             "left-attach", &left,
00435                             "right-attach", &right,
00436                             "top-attach", &top,
00437                             "x-options", &x_opts,
00438                             "x-padding", &x_pad,
00439                             "y-options", &y_opts,
00440                             "y-padding", &y_pad,
00441                             NULL);
00442 
00443     gtk_widget_ref(child);
00444     gtk_container_remove(GTK_CONTAINER(copydata->table_from), child);
00445     gtk_table_attach(copydata->table_to, child, left, right,
00446                      top + copydata->row_offset, bottom + copydata->row_offset,
00447                      x_opts, y_opts, x_pad, y_pad);
00448     gtk_widget_unref(child);
00449     LEAVE(" ");
00450 }
00451 
00452 
00464 static void
00465 gnc_preferences_build_page (gpointer data,
00466                             gpointer user_data)
00467 {
00468     GtkBuilder *builder;
00469     GtkWidget *dialog, *existing_content, *new_content, *label;
00470     GtkNotebook *notebook;
00471     addition *add_in;
00472     struct copy_data copydata;
00473     gint rows, cols;
00474     gchar **widgetname;
00475     gint i;
00476 
00477     ENTER("add_in %p, dialog %p", data, user_data);
00478     add_in = (addition *)data;
00479     dialog = user_data;
00480 
00481     DEBUG("Opening %s to get %s", add_in->filename, add_in->widgetname);
00482     builder = gtk_builder_new();
00483 
00484     /* Adjustments etc... must come before dialog information */
00485     widgetname = g_strsplit(add_in->widgetname, ",", -1);
00486 
00487     for (i = 0; widgetname[i]; i++)
00488     {
00489         DEBUG("Opening %s to get content %s", add_in->filename, widgetname[i]);
00490         gnc_builder_add_from_file (builder, add_in->filename, widgetname[i]);
00491     }
00492 
00493     DEBUG("Widget Content is %s", widgetname[i - 1]);
00494     new_content = GTK_WIDGET(gtk_builder_get_object (builder, widgetname[i - 1]));
00495 
00496     g_strfreev(widgetname);
00497     DEBUG("done");
00498 
00499     /* Add to the list of interesting widgets */
00500     gnc_prefs_build_widget_table(builder, dialog);
00501 
00502     /* Connect the signals in this glade file. The dialog is passed in
00503      * so the the callback can find "interesting" widgets from other
00504      * glade files if necessary (via the WIDGET_HASH hash table). */
00505     gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, dialog);
00506 
00507     /* Prepare for recursion */
00508     notebook = g_object_get_data(G_OBJECT(dialog), NOTEBOOK);
00509 
00510     if (add_in->full_page)
00511     {
00512         label = gtk_label_new(add_in->tabname);
00513         gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
00514         gtk_notebook_append_page(notebook, new_content, label);
00515         g_object_unref(G_OBJECT(builder));
00516         LEAVE("appended page");
00517         return;
00518     }
00519 
00520     /* Copied tables must match the size of the main table */
00521     if (!GTK_IS_TABLE(new_content))
00522     {
00523         g_critical("The object name %s in file %s is not a GtkTable.  It cannot "
00524                    "be added to the preferences dialog.",
00525                    add_in->widgetname, add_in->filename);
00526         g_object_unref(G_OBJECT(builder));
00527         LEAVE("");
00528         return;
00529     }
00530     g_object_get(G_OBJECT(new_content), "n-columns", &cols, NULL);
00531     if (cols != 4)
00532     {
00533         g_critical("The table %s in file %s does not have four columns.  It cannot "
00534                    "be added to the preferences dialog.",
00535                    add_in->widgetname, add_in->filename);
00536         g_object_unref(G_OBJECT(builder));
00537         LEAVE("");
00538         return;
00539     }
00540 
00541     /* Does the page exist or must we create it */
00542     existing_content = gnc_prefs_find_page(notebook, add_in->tabname);
00543 
00544     if (!existing_content)
00545     {
00546         /* No existing content with this name.  Create a blank page */
00547         rows = 0;
00548         existing_content = gtk_table_new(0, 4, FALSE);
00549         gtk_container_set_border_width(GTK_CONTAINER(existing_content), 6);
00550         label = gtk_label_new(add_in->tabname);
00551         gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
00552         gtk_notebook_append_page(notebook, existing_content, label);
00553         gtk_widget_show_all(existing_content);
00554         DEBUG("created new page %s, appended it", add_in->tabname);
00555     }
00556     else
00557     {
00558         g_object_get(G_OBJECT(existing_content), "n-rows", &rows, NULL);
00559         DEBUG("found existing page %s", add_in->tabname);
00560     }
00561 
00562     /* Maybe add a spacer row */
00563     DEBUG("rows is %d", rows);
00564     if (rows > 0)
00565     {
00566         label = gtk_label_new("");
00567         gtk_widget_show(label);
00568         gtk_table_attach(GTK_TABLE(existing_content), label, 0, 1, rows, rows + 1,
00569                          GTK_FILL, GTK_FILL, 0, 0);
00570         rows++;
00571     }
00572 
00573     /* Now copy all the entries in the table */
00574     copydata.table_from = GTK_TABLE(new_content);
00575     copydata.table_to = GTK_TABLE(existing_content);
00576     copydata.row_offset = rows;
00577     gtk_container_foreach(GTK_CONTAINER(new_content), gnc_prefs_move_table_entry,
00578                           &copydata);
00579 
00580     g_object_ref_sink(new_content);
00581     g_object_unref(G_OBJECT(builder));
00582 
00583     LEAVE("added content to page");
00584 }
00585 
00586 
00587 static gint
00588 tab_cmp (GtkWidget *page_a, GtkWidget *page_b, GtkNotebook *notebook)
00589 {
00590     return g_utf8_collate (gtk_notebook_get_tab_label_text (notebook, page_a),
00591                            gtk_notebook_get_tab_label_text (notebook, page_b));
00592 }
00593 
00594 
00595 static void
00596 gnc_prefs_sort_pages (GtkNotebook *notebook)
00597 {
00598     gint n_pages, i;
00599     GList *tabs = NULL, *iter = NULL;
00600 
00601     g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
00602 
00603     /* gather tabs */
00604     n_pages = gtk_notebook_get_n_pages (notebook);
00605     for (i = n_pages - 1; i >= 0; i--)
00606         tabs = g_list_prepend (tabs, gtk_notebook_get_nth_page (notebook, i));
00607 
00608     /* sort in local copy */
00609     tabs = g_list_sort_with_data (tabs, (GCompareDataFunc) tab_cmp, notebook);
00610 
00611     /* reorder tabs */
00612     for (i = 0, iter = tabs; iter; i++, iter = iter->next)
00613         gtk_notebook_reorder_child (notebook, GTK_WIDGET (iter->data), i);
00614 
00615     g_list_free (tabs);
00616 }
00617 
00618 
00619 /*******************************/
00620 /* Dynamically added Callbacks */
00621 /*******************************/
00622 
00632 static void
00633 gnc_prefs_font_button_user_cb (GtkFontButton *fb,
00634                                gpointer user_data)
00635 {
00636     const gchar *key, *font;
00637 
00638     g_return_if_fail(GTK_IS_FONT_BUTTON(fb));
00639     key = gtk_buildable_get_name(GTK_BUILDABLE(fb)) + PREFIX_LEN;
00640     font = gtk_font_button_get_font_name(fb);
00641 
00642     DEBUG("font_button %s set", key);
00643     gnc_gconf_set_string(key, NULL, font, NULL);
00644 }
00645 
00646 
00656 static void
00657 gnc_prefs_font_button_gconf_cb (GtkFontButton *fb,
00658                                 GConfEntry *entry)
00659 {
00660     const gchar *font;
00661 
00662     g_return_if_fail(GTK_IS_FONT_BUTTON(fb));
00663     ENTER("fb %p, entry %p", fb, entry);
00664 
00665     font = gconf_value_get_string(entry->value);
00666 
00667     g_signal_handlers_block_by_func(G_OBJECT(fb),
00668                                     G_CALLBACK(gnc_prefs_font_button_user_cb), NULL);
00669     gtk_font_button_set_font_name(fb, font);
00670     g_signal_handlers_unblock_by_func(G_OBJECT(fb),
00671                                       G_CALLBACK(gnc_prefs_font_button_user_cb), NULL);
00672     LEAVE(" ");
00673 }
00674 
00675 
00683 static void
00684 gnc_prefs_connect_font_button (GtkFontButton *fb)
00685 {
00686     const gchar *name;
00687     gchar *font;
00688 
00689     g_return_if_fail(GTK_IS_FONT_BUTTON(fb));
00690 
00691     /* Lookup font name based upon gconf setting */
00692     name = gtk_buildable_get_name(GTK_BUILDABLE(fb)) + PREFIX_LEN;
00693     font = gnc_gconf_get_string(name, NULL, NULL);
00694 
00695     gtk_font_button_set_font_name(fb, font);
00696     DEBUG(" font_button %s set", name);
00697     g_free(font);
00698 
00699     g_signal_connect(G_OBJECT(fb), "font_set",
00700                      G_CALLBACK(gnc_prefs_font_button_user_cb), NULL);
00701 
00702     gtk_widget_show_all(GTK_WIDGET(fb));
00703 }
00704 
00705 /****************************************************************************/
00706 
00718 static void
00719 gnc_prefs_radio_button_user_cb (GtkRadioButton *button,
00720                                 gpointer user_data)
00721 {
00722     gchar *key, *button_name;
00723     gboolean active;
00724 
00725     g_return_if_fail(GTK_IS_RADIO_BUTTON(button));
00726     active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
00727     if (!active)
00728         return;
00729 
00730     /* Copy the widget name and split into gconf key and button value parts */
00731     key = g_strdup(gtk_buildable_get_name(GTK_BUILDABLE(button)) + PREFIX_LEN);
00732     button_name = strrchr(key, '/');
00733     *button_name++ = '\0';
00734 
00735     DEBUG("Radio button group %s now set to %s", key, button_name);
00736     gnc_gconf_set_string(key, NULL, button_name, NULL);
00737     g_free(key);
00738 }
00739 
00740 
00749 static void
00750 gnc_prefs_radio_button_gconf_cb (GtkRadioButton *button)
00751 {
00752     g_return_if_fail(GTK_IS_RADIO_BUTTON(button));
00753     ENTER("button %p", button);
00754     g_signal_handlers_block_by_func(G_OBJECT(button),
00755                                     G_CALLBACK(gnc_prefs_radio_button_user_cb), NULL);
00756     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
00757     g_signal_handlers_unblock_by_func(G_OBJECT(button),
00758                                       G_CALLBACK(gnc_prefs_radio_button_user_cb), NULL);
00759     LEAVE(" ");
00760 }
00761 
00762 
00772 static void
00773 gnc_prefs_connect_radio_button (GtkRadioButton *button)
00774 {
00775     gchar *key, *button_name, *value;
00776     gboolean active;
00777     GSList *group;
00778 
00779     g_return_if_fail(GTK_IS_RADIO_BUTTON(button));
00780 
00781     /* Copy the widget name and split into gconf key and button name parts */
00782     key = g_strdup(gtk_buildable_get_name(GTK_BUILDABLE(button)) + PREFIX_LEN);
00783     button_name = strrchr(key, '/');
00784     *button_name++ = '\0';
00785 
00786     /* Get the current value. */
00787     value = gnc_gconf_get_string(key, NULL, NULL);
00788     if (value)
00789     {
00790         active = (g_utf8_collate(value, button_name) == 0);
00791     }
00792     else
00793     {
00794         /* Sigh. There's no gconf default for this key. Use the first
00795          * button in the dialog, which is the last button in the list. */
00796         group =  gtk_radio_button_get_group(button);
00797         active = (button != g_slist_nth_data(group, g_slist_length(group)));
00798     }
00799     DEBUG(" Radio set %s, button %s initially set to %d", key, button_name, active);
00800 
00801     /* Wire up the button */
00802     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), active);
00803     g_signal_connect(G_OBJECT(button), "toggled",
00804                      G_CALLBACK(gnc_prefs_radio_button_user_cb), NULL);
00805     g_free(value);
00806     g_free(key);
00807 }
00808 
00809 /****************************************************************************/
00810 
00820 static void
00821 gnc_prefs_check_button_user_cb (GtkCheckButton *button,
00822                                 gpointer user_data)
00823 {
00824     const gchar *name;
00825     gboolean active;
00826 
00827     g_return_if_fail(GTK_IS_CHECK_BUTTON(button));
00828     name = gtk_buildable_get_name(GTK_BUILDABLE(button)) + PREFIX_LEN;
00829     active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
00830     DEBUG("Checkbox %s now %sactive", name, active ? "" : "in");
00831     gnc_gconf_set_bool(name, NULL, active, NULL);
00832 }
00833 
00834 
00844 static void
00845 gnc_prefs_check_button_gconf_cb (GtkCheckButton *button,
00846                                  gboolean active)
00847 {
00848     g_return_if_fail(GTK_IS_CHECK_BUTTON(button));
00849     ENTER("button %p, active %d", button, active);
00850     g_signal_handlers_block_by_func(G_OBJECT(button),
00851                                     G_CALLBACK(gnc_prefs_check_button_user_cb), NULL);
00852     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), active);
00853     g_signal_handlers_unblock_by_func(G_OBJECT(button),
00854                                       G_CALLBACK(gnc_prefs_check_button_user_cb), NULL);
00855     LEAVE(" ");
00856 }
00857 
00858 
00867 static void
00868 gnc_prefs_connect_check_button (GtkCheckButton *button)
00869 {
00870     const gchar *name;
00871     gboolean active;
00872 
00873     name = gtk_buildable_get_name(GTK_BUILDABLE(button)) + PREFIX_LEN;
00874     active = gnc_gconf_get_bool(name, NULL, NULL);
00875     DEBUG(" Checkbox %s initially %sactive", name, active ? "" : "in");
00876     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), active);
00877     g_signal_connect(G_OBJECT(button), "toggled",
00878                      G_CALLBACK(gnc_prefs_check_button_user_cb), NULL);
00879 }
00880 
00881 /****************************************************************************/
00882 
00892 static void
00893 gnc_prefs_spin_button_user_cb (GtkSpinButton *spin,
00894                                gpointer user_data)
00895 {
00896     const gchar *name;
00897     gdouble value;
00898 
00899     g_return_if_fail(GTK_IS_SPIN_BUTTON(spin));
00900     name = gtk_buildable_get_name(GTK_BUILDABLE(spin)) + PREFIX_LEN;
00901     value = gtk_spin_button_get_value(spin);
00902     DEBUG("Spin button %s has value %f", name, value);
00903     gnc_gconf_set_float(name, NULL, value, NULL);
00904 }
00905 
00906 
00916 static void
00917 gnc_prefs_spin_button_gconf_cb (GtkSpinButton *spin,
00918                                 gdouble value)
00919 {
00920     g_return_if_fail(GTK_IS_SPIN_BUTTON(spin));
00921     ENTER("button %p, value %f", spin, value);
00922     g_signal_handlers_block_by_func(G_OBJECT(spin),
00923                                     G_CALLBACK(gnc_prefs_spin_button_user_cb), NULL);
00924     gtk_spin_button_set_value(spin, value);
00925     g_signal_handlers_unblock_by_func(G_OBJECT(spin),
00926                                       G_CALLBACK(gnc_prefs_spin_button_user_cb), NULL);
00927     LEAVE(" ");
00928 }
00929 
00930 
00939 static void
00940 gnc_prefs_connect_spin_button (GtkSpinButton *spin)
00941 {
00942     const gchar *name;
00943     gdouble value;
00944 
00945     g_return_if_fail(GTK_IS_SPIN_BUTTON(spin));
00946     name = gtk_buildable_get_name(GTK_BUILDABLE(spin)) + PREFIX_LEN;
00947     value = gnc_gconf_get_float(name, NULL, NULL);
00948     gtk_spin_button_set_value(spin, value);
00949     DEBUG(" Spin button %s has initial value %f", name, value);
00950     g_signal_connect(G_OBJECT(spin), "value-changed",
00951                      G_CALLBACK(gnc_prefs_spin_button_user_cb), NULL);
00952 }
00953 
00954 /****************************************************************************/
00955 
00965 static void
00966 gnc_prefs_combo_box_user_cb (GtkComboBox *box,
00967                              gpointer user_data)
00968 {
00969     const gchar *name;
00970     gint active;
00971 
00972     g_return_if_fail(GTK_IS_COMBO_BOX(box));
00973     name = gtk_buildable_get_name(GTK_BUILDABLE(box)) + PREFIX_LEN;
00974     active = gtk_combo_box_get_active(box);
00975     DEBUG("Combo box %s set to item %d", name, active);
00976     gnc_gconf_set_int(name, NULL, active, NULL);
00977 }
00978 
00979 
00989 static void
00990 gnc_prefs_combo_box_gconf_cb (GtkComboBox *box,
00991                               gint value)
00992 {
00993     g_return_if_fail(GTK_IS_COMBO_BOX(box));
00994     ENTER("box %p, value %d", box, value);
00995     g_signal_handlers_block_by_func(G_OBJECT(box),
00996                                     G_CALLBACK(gnc_prefs_combo_box_user_cb), NULL);
00997     gtk_combo_box_set_active(box, value);
00998     g_signal_handlers_unblock_by_func(G_OBJECT(box),
00999                                       G_CALLBACK(gnc_prefs_combo_box_user_cb), NULL);
01000     LEAVE(" ");
01001 }
01002 
01003 
01011 static void
01012 gnc_prefs_connect_combo_box (GtkComboBox *box)
01013 {
01014     const gchar *name;
01015     gint active;
01016 
01017     g_return_if_fail(GTK_IS_COMBO_BOX(box));
01018     name = gtk_buildable_get_name(GTK_BUILDABLE(box)) + PREFIX_LEN;
01019     active = gnc_gconf_get_int(name, NULL, NULL);
01020     gtk_combo_box_set_active(GTK_COMBO_BOX(box), active);
01021     DEBUG(" Combo box %s set to item %d", name, active);
01022     g_signal_connect(G_OBJECT(box), "changed",
01023                      G_CALLBACK(gnc_prefs_combo_box_user_cb), NULL);
01024 }
01025 
01026 /****************************************************************************/
01027 
01037 static void
01038 gnc_prefs_currency_edit_user_cb (GNCCurrencyEdit *gce,
01039                                  gpointer user_data)
01040 {
01041     const gchar *name, *mnemonic;
01042     gnc_commodity *currency;
01043 
01044     g_return_if_fail(GNC_IS_CURRENCY_EDIT(gce));
01045     name  = g_object_get_data(G_OBJECT(gce), "name");
01046     currency = gnc_currency_edit_get_currency(gce);
01047     mnemonic = gnc_commodity_get_mnemonic(currency);
01048 
01049     DEBUG("Currency edit %s set to %s", name, mnemonic);
01050     gnc_gconf_set_string(name, NULL, mnemonic, NULL);
01051 }
01052 
01053 
01063 static void
01064 gnc_prefs_currency_edit_gconf_cb (GNCCurrencyEdit *gce,
01065                                   GConfEntry *entry)
01066 {
01067     const gchar *mnemonic;
01068     gnc_commodity *currency;
01069 
01070     g_return_if_fail(GNC_IS_CURRENCY_EDIT(gce));
01071     ENTER("gce %p, entry %p", gce, entry);
01072 
01073     mnemonic = gconf_value_get_string(entry->value);
01074     DEBUG("gce %p, mnemonic %s", gce, mnemonic);
01075     currency = gnc_commodity_table_lookup(gnc_get_current_commodities(),
01076                                           GNC_COMMODITY_NS_CURRENCY, mnemonic);
01077 
01078     /* If there isn't any such commodity, get the default */
01079     if (!currency)
01080     {
01081         currency = gnc_locale_default_currency();
01082         DEBUG("gce %p, default currency mnemonic %s",
01083               gce, gnc_commodity_get_mnemonic(currency));
01084     }
01085 
01086     g_signal_handlers_block_by_func(G_OBJECT(gce),
01087                                     G_CALLBACK(gnc_prefs_currency_edit_user_cb), NULL);
01088     gnc_currency_edit_set_currency(GNC_CURRENCY_EDIT(gce), currency);
01089     g_signal_handlers_unblock_by_func(G_OBJECT(gce),
01090                                       G_CALLBACK(gnc_prefs_currency_edit_user_cb), NULL);
01091     LEAVE(" ");
01092 }
01093 
01094 
01102 static void
01103 gnc_prefs_connect_currency_edit (GNCCurrencyEdit *gce, const gchar *boxname )
01104 {
01105     gnc_commodity *currency;
01106     const gchar *name;
01107     gchar *mnemonic;
01108 
01109     g_return_if_fail(GNC_IS_CURRENCY_EDIT(gce));
01110 
01111     /* Lookup commodity based upon gconf setting */
01112     name = boxname + PREFIX_LEN;
01113 
01114     g_object_set_data(G_OBJECT(gce), "name", g_strdup(name) );
01115 
01116     mnemonic = gnc_gconf_get_string(name, NULL, NULL);
01117     currency = gnc_commodity_table_lookup(gnc_get_current_commodities(),
01118                                           GNC_COMMODITY_NS_CURRENCY, mnemonic);
01119     if (mnemonic)
01120         g_free(mnemonic);
01121 
01122     /* If there isn't any such commodity, get the default */
01123     if (!currency)
01124         currency = gnc_locale_default_currency();
01125 
01126     gnc_currency_edit_set_currency(GNC_CURRENCY_EDIT(gce), currency);
01127     DEBUG(" Currency edit %s set to %s", name,
01128           gnc_commodity_get_mnemonic(currency));
01129 
01130     g_signal_connect(G_OBJECT(gce), "changed",
01131                      G_CALLBACK(gnc_prefs_currency_edit_user_cb), NULL);
01132 
01133     gtk_widget_show_all(GTK_WIDGET(gce));
01134 }
01135 
01136 /****************************************************************************/
01137 
01146 static void
01147 gnc_prefs_entry_user_cb (GtkEntry *entry,
01148                          gpointer user_data)
01149 {
01150     const gchar *name, *text;
01151 
01152     g_return_if_fail(GTK_IS_ENTRY(entry));
01153     name = gtk_buildable_get_name(GTK_BUILDABLE(entry)) + PREFIX_LEN;
01154     text = gtk_entry_get_text(entry);
01155     DEBUG("entry %s set to '%s'", name, text);
01156     gnc_gconf_set_string(name, NULL, text, NULL);
01157 }
01158 
01159 
01168 static void
01169 gnc_prefs_entry_gconf_cb (GtkEntry *entry,
01170                           const gchar *value)
01171 {
01172     g_return_if_fail(GTK_IS_ENTRY(entry));
01173     ENTER("entry %p, value '%s'", entry, value);
01174     g_signal_handlers_block_by_func(G_OBJECT(entry),
01175                                     G_CALLBACK(gnc_prefs_entry_user_cb), NULL);
01176     gtk_entry_set_text(entry, value);
01177     g_signal_handlers_unblock_by_func(G_OBJECT(entry),
01178                                       G_CALLBACK(gnc_prefs_entry_user_cb), NULL);
01179     LEAVE(" ");
01180 }
01181 
01182 
01190 static void
01191 gnc_prefs_connect_entry (GtkEntry *entry)
01192 {
01193     const gchar *name;
01194     gchar *text;
01195 
01196     g_return_if_fail(GTK_IS_ENTRY(entry));
01197     name = gtk_buildable_get_name(GTK_BUILDABLE(entry)) + PREFIX_LEN;
01198     text = gnc_gconf_get_string(name, NULL, NULL);
01199     gtk_entry_set_text(GTK_ENTRY(entry), text ? text : "");
01200     DEBUG(" Entry %s set to '%s'", name ? name : "(null)", text ? text : "(null)");
01201     g_free(text);
01202     g_signal_connect(G_OBJECT(entry), "changed",
01203                      G_CALLBACK(gnc_prefs_entry_user_cb), NULL);
01204 }
01205 
01206 /****************************************************************************/
01207 
01217 static void
01218 gnc_prefs_period_select_user_cb (GncPeriodSelect *period,
01219                                  gpointer user_data)
01220 {
01221     const gchar *name;
01222     gint active;
01223 
01224     g_return_if_fail(GNC_IS_PERIOD_SELECT(period));
01225     name  = g_object_get_data(G_OBJECT(period), "name");
01226     active = gnc_period_select_get_active(period);
01227     DEBUG("period select %s set to item %d", name, active);
01228     gnc_gconf_set_int(name, NULL, active, NULL);
01229 }
01230 
01231 
01241 static void
01242 gnc_prefs_period_select_gconf_cb (GncPeriodSelect *period,
01243                                   gint value)
01244 {
01245     g_return_if_fail(GNC_IS_PERIOD_SELECT(period));
01246     ENTER("period %p, value %d", period, value);
01247     g_signal_handlers_block_by_func(G_OBJECT(period),
01248                                     G_CALLBACK(gnc_prefs_period_select_user_cb), NULL);
01249     gnc_period_select_set_active(period, value);
01250     g_signal_handlers_unblock_by_func(G_OBJECT(period),
01251                                       G_CALLBACK(gnc_prefs_period_select_user_cb), NULL);
01252     LEAVE(" ");
01253 }
01254 
01255 
01263 static void
01264 gnc_prefs_connect_period_select (GncPeriodSelect *period, const gchar *boxname )
01265 {
01266     const gchar *name;
01267     gint active;
01268     QofBook *book;
01269     KvpFrame *book_frame;
01270     gint64 month, day;
01271     GDate fy_end;
01272 
01273     g_return_if_fail(GNC_IS_PERIOD_SELECT(period));
01274     book = gnc_get_current_book();
01275     book_frame = qof_book_get_slots(book);
01276     month = kvp_frame_get_gint64(book_frame, "/book/fyear_end/month");
01277     day = kvp_frame_get_gint64(book_frame, "/book/fyear_end/day");
01278     if (g_date_valid_dmy(day, month, 2005 /* not leap year */))
01279     {
01280         g_date_clear(&fy_end, 1);
01281         g_date_set_dmy(&fy_end, day, month, G_DATE_BAD_YEAR);
01282         gnc_period_select_set_fy_end(period, &fy_end);
01283     }
01284 
01285     name = boxname + PREFIX_LEN;
01286 
01287     g_object_set_data(G_OBJECT(period), "name", g_strdup(name) );
01288 
01289     active = gnc_gconf_get_int(name, NULL, NULL);
01290     gnc_period_select_set_active(period, active);
01291     DEBUG(" Period select %s set to item %d", name, active);
01292     g_signal_connect(G_OBJECT(period), "changed",
01293                      G_CALLBACK(gnc_prefs_period_select_user_cb), NULL);
01294 }
01295 
01296 /****************************************************************************/
01297 
01307 static void
01308 gnc_prefs_date_edit_user_cb (GNCDateEdit *gde,
01309                              gpointer user_data)
01310 {
01311     const gchar *name;
01312     time_t time;
01313 
01314     g_return_if_fail(GNC_IS_DATE_EDIT(gde));
01315     name  = g_object_get_data(G_OBJECT(gde), "name");
01316     time = gnc_date_edit_get_date(gde);
01317 
01318     DEBUG("date_edit %s set", name);
01319     gnc_gconf_set_int(name, NULL, time, NULL);
01320 }
01321 
01322 
01332 static void
01333 gnc_prefs_date_edit_gconf_cb (GNCDateEdit *gde,
01334                               GConfEntry *entry)
01335 {
01336     time_t time;
01337 
01338     g_return_if_fail(GNC_IS_DATE_EDIT(gde));
01339     ENTER("date_edit %p, entry %p", gde, entry);
01340 
01341     time = gconf_value_get_int(entry->value);
01342 
01343     g_signal_handlers_block_by_func(G_OBJECT(gde),
01344                                     G_CALLBACK(gnc_prefs_date_edit_user_cb), NULL);
01345     gnc_date_edit_set_time(GNC_DATE_EDIT(gde), time);
01346     g_signal_handlers_unblock_by_func(G_OBJECT(gde),
01347                                       G_CALLBACK(gnc_prefs_date_edit_user_cb), NULL);
01348     LEAVE(" ");
01349 }
01350 
01351 
01359 static void
01360 gnc_prefs_connect_date_edit (GNCDateEdit *gde , const gchar *boxname )
01361 {
01362     const gchar *name;
01363     time_t time;
01364 
01365     g_return_if_fail(GNC_IS_DATE_EDIT(gde));
01366 
01367     /* Lookup the date based upon gconf setting */
01368     name = boxname + PREFIX_LEN;
01369 
01370     g_object_set_data(G_OBJECT(gde), "name", g_strdup(name) );
01371 
01372     time = gnc_gconf_get_int(name, NULL, NULL);
01373 
01374     gnc_date_edit_set_time(GNC_DATE_EDIT(gde), time);
01375     DEBUG(" date_edit %s set", name);
01376 
01377     g_signal_connect(G_OBJECT(gde), "date_changed",
01378                      G_CALLBACK(gnc_prefs_date_edit_user_cb), NULL);
01379 
01380     gtk_widget_show_all(GTK_WIDGET(gde));
01381 }
01382 
01383 
01384 /****************************************************************************/
01385 
01386 /********************/
01387 /*    Callbacks     */
01388 /********************/
01389 
01403 void
01404 gnc_preferences_response_cb(GtkDialog *dialog, gint response, GtkDialog *unused)
01405 {
01406     switch (response)
01407     {
01408     case GTK_RESPONSE_HELP:
01409         gnc_gnome_help(HF_HELP, HL_GLOBPREFS);
01410         break;
01411 
01412     default:
01413         gnc_save_window_size(GCONF_SECTION, GTK_WINDOW(dialog));
01414         gnc_unregister_gui_component_by_data(DIALOG_PREFERENCES_CM_CLASS,
01415                                              dialog);
01416         gnc_gconf_general_remove_cb(
01417             KEY_ACCOUNT_SEPARATOR,
01418             (GncGconfGeneralCb)gnc_account_separator_prefs_cb,
01419             dialog);
01420         gnc_gconf_remove_notification(G_OBJECT(dialog), NULL,
01421                                       DIALOG_PREFERENCES_CM_CLASS);
01422         gtk_widget_destroy(GTK_WIDGET(dialog));
01423         break;
01424     }
01425 }
01426 
01427 
01428 /********************/
01429 /*    Creation      */
01430 /********************/
01431 
01443 static void
01444 gnc_prefs_connect_one (const gchar *name,
01445                        GtkWidget *widget,
01446                        gpointer user_data)
01447 {
01448     /* These tests must be ordered from more specific widget to less
01449      * specific widget. */
01450 
01451     if (GTK_IS_FONT_BUTTON(widget))
01452     {
01453         DEBUG("  %s - entry", name);
01454         gnc_prefs_connect_font_button(GTK_FONT_BUTTON(widget));
01455     }
01456     else if (GTK_IS_RADIO_BUTTON(widget))
01457     {
01458         DEBUG("  %s - radio button", name);
01459         gnc_prefs_connect_radio_button(GTK_RADIO_BUTTON(widget));
01460     }
01461     else if (GTK_IS_CHECK_BUTTON(widget))
01462     {
01463         DEBUG("  %s - check button", name);
01464         gnc_prefs_connect_check_button(GTK_CHECK_BUTTON(widget));
01465     }
01466     else if (GTK_IS_SPIN_BUTTON(widget))
01467     {
01468         DEBUG("  %s - spin button", name);
01469         gnc_prefs_connect_spin_button(GTK_SPIN_BUTTON(widget));
01470     }
01471     else if (GTK_IS_COMBO_BOX(widget))
01472     {
01473         DEBUG("  %s - combo box", name);
01474         gnc_prefs_connect_combo_box(GTK_COMBO_BOX(widget));
01475     }
01476     else if (GTK_IS_ENTRY(widget))
01477     {
01478         DEBUG("  %s - entry", name);
01479         gnc_prefs_connect_entry(GTK_ENTRY(widget));
01480     }
01481     else if (GTK_IS_HBOX(widget))
01482     {
01483         /* Test custom widgets are all children of a hbox */
01484         GtkWidget *widget_child;
01485         GList* child = gtk_container_get_children(GTK_CONTAINER(widget));
01486         widget_child = child->data;
01487         g_list_free(child);
01488         DEBUG("  %s - hbox", name);
01489         DEBUG("Hbox widget type is %s and name is %s", gtk_widget_get_name(GTK_WIDGET(widget_child)), name);
01490 
01491         if (GNC_IS_CURRENCY_EDIT(widget_child))
01492         {
01493             DEBUG("  %s - currency_edit", name);
01494             gnc_prefs_connect_currency_edit(GNC_CURRENCY_EDIT(widget_child), name );
01495         }
01496         else if (GNC_IS_PERIOD_SELECT(widget_child))
01497         {
01498             DEBUG("  %s - period_Select", name);
01499             gnc_prefs_connect_period_select(GNC_PERIOD_SELECT(widget_child), name );
01500         }
01501         else if (GNC_IS_DATE_EDIT(widget_child))
01502         {
01503             DEBUG("  %s - date_edit", name);
01504             gnc_prefs_connect_date_edit(GNC_DATE_EDIT(widget_child), name );
01505         }
01506     }
01507     else
01508     {
01509         DEBUG("  %s - unsupported %s", name,
01510               G_OBJECT_TYPE_NAME(G_OBJECT(widget)));
01511     }
01512 }
01513 
01514 
01526 static GtkWidget *
01527 gnc_preferences_dialog_create(void)
01528 {
01529     GtkBuilder *builder;
01530     GtkWidget *dialog, *notebook, *label, *image;
01531     GtkWidget *box, *date, *period, *currency;
01532     GHashTable *table;
01533     GDate* gdate;
01534     gchar buf[128];
01535     gnc_commodity *locale_currency;
01536     const gchar *currency_name;
01537 
01538     ENTER("");
01539     DEBUG("Opening dialog-preferences.glade:");
01540     builder = gtk_builder_new();
01541 
01542     gnc_builder_add_from_file (builder, "dialog-preferences.glade", "auto_decimal_places_adj");
01543     gnc_builder_add_from_file (builder, "dialog-preferences.glade", "autosave_interval_minutes_adj");
01544     gnc_builder_add_from_file (builder, "dialog-preferences.glade", "date_backmonth_adj");
01545     gnc_builder_add_from_file (builder, "dialog-preferences.glade", "max_transactions_adj");
01546     gnc_builder_add_from_file (builder, "dialog-preferences.glade", "new_search_limit_adj");
01547     gnc_builder_add_from_file (builder, "dialog-preferences.glade", "retain_days_adj");
01548     gnc_builder_add_from_file (builder, "dialog-preferences.glade", "tab_width_adj");
01549     gnc_builder_add_from_file (builder, "dialog-preferences.glade", "GnuCash Preferences");
01550     dialog = GTK_WIDGET(gtk_builder_get_object (builder, "GnuCash Preferences"));
01551 
01552     DEBUG("autoconnect");
01553     gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, dialog);
01554 
01555     DEBUG("done");
01556 
01557     notebook = GTK_WIDGET(gtk_builder_get_object (builder, "notebook1"));
01558     table = g_hash_table_new(g_str_hash, g_str_equal);
01559     g_object_set_data(G_OBJECT(dialog), NOTEBOOK, notebook);
01560     g_object_set_data_full(G_OBJECT(dialog), WIDGET_HASH,
01561                            table, (GDestroyNotify)g_hash_table_destroy);
01562 
01563     box = GTK_WIDGET(gtk_builder_get_object (builder, "gconf/window/pages/account_tree/summary/start_period"));
01564     period = gnc_period_select_new(TRUE);
01565     gtk_widget_show (period);
01566     gtk_box_pack_start (GTK_BOX (box), period, TRUE, TRUE, 0);
01567 
01568     box = GTK_WIDGET(gtk_builder_get_object (builder, "gconf/window/pages/account_tree/summary/start_date"));
01569     date = gnc_date_edit_new(time(NULL), FALSE, FALSE);
01570     gtk_widget_show (date);
01571     gtk_box_pack_start (GTK_BOX (box), date, TRUE, TRUE, 0);
01572 
01573     box = GTK_WIDGET(gtk_builder_get_object (builder, "gconf/window/pages/account_tree/summary/end_period"));
01574     period = gnc_period_select_new(FALSE);
01575     gtk_widget_show (period);
01576     gtk_box_pack_start (GTK_BOX (box), period, TRUE, TRUE, 0);
01577 
01578     box = GTK_WIDGET(gtk_builder_get_object (builder, "gconf/window/pages/account_tree/summary/end_date"));
01579     date = gnc_date_edit_new(time(NULL), FALSE, FALSE);
01580     gtk_widget_show (date);
01581     gtk_box_pack_start (GTK_BOX (box), date, TRUE, TRUE, 0);
01582 
01583     box = GTK_WIDGET(gtk_builder_get_object (builder, "gconf/general/currency_other"));
01584     currency = gnc_currency_edit_new();
01585     gnc_currency_edit_set_currency (GNC_CURRENCY_EDIT(currency), gnc_default_currency());
01586     gtk_widget_show (currency);
01587     gtk_box_pack_start(GTK_BOX (box), currency, TRUE, TRUE, 0);
01588 
01589     box = GTK_WIDGET(gtk_builder_get_object (builder, "gconf/general/report/currency_other"));
01590     currency = gnc_currency_edit_new();
01591     gnc_currency_edit_set_currency (GNC_CURRENCY_EDIT(currency), gnc_default_currency());
01592     gtk_widget_show (currency);
01593     gtk_box_pack_start(GTK_BOX (box), currency, TRUE, TRUE, 0);
01594 
01595 
01596     /* Add to the list of interesting widgets */
01597     gnc_prefs_build_widget_table(builder, dialog);
01598 
01599     g_slist_foreach(add_ins, gnc_preferences_build_page, dialog);
01600 
01601     /* Sort tabs alphabetically */
01602     gnc_prefs_sort_pages(GTK_NOTEBOOK(notebook));
01603     gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 0);
01604 
01605     DEBUG("We have the following interesting widgets:");
01606     g_hash_table_foreach(table, (GHFunc)gnc_prefs_connect_one, dialog);
01607     DEBUG("Done with interesting widgets.");
01608 
01609     /* Other stuff */
01610     gdate = g_date_new_dmy(31, G_DATE_JULY, 2005);
01611     g_date_strftime(buf, sizeof(buf), "%x", gdate);
01612     label = GTK_WIDGET(gtk_builder_get_object (builder, "locale_date_sample"));
01613     gtk_label_set_text(GTK_LABEL(label), buf);
01614     g_date_free(gdate);
01615 
01616     locale_currency = gnc_locale_default_currency ();
01617     currency_name = gnc_commodity_get_printname(locale_currency);
01618     label = GTK_WIDGET(gtk_builder_get_object (builder, "locale_currency"));
01619     gtk_label_set_label(GTK_LABEL(label), currency_name);
01620     label = GTK_WIDGET(gtk_builder_get_object (builder, "locale_currency2"));
01621     gtk_label_set_label(GTK_LABEL(label), currency_name);
01622 
01623     label = GTK_WIDGET(gtk_builder_get_object (builder, "sample_account"));
01624     g_object_set_data(G_OBJECT(dialog), "sample_account", label);
01625 
01626     image = GTK_WIDGET(gtk_builder_get_object (builder, "separator_error"));
01627     g_object_set_data(G_OBJECT(dialog), "separator_error", image);
01628 
01629     gnc_account_separator_prefs_cb(NULL, dialog);
01630 
01631     g_object_unref(G_OBJECT(builder));
01632 
01633     LEAVE("dialog %p", dialog);
01634     return dialog;
01635 }
01636 
01637 
01638 /*************************************/
01639 /*    GConf common callback code     */
01640 /*************************************/
01641 
01662 static gboolean
01663 gnc_prefs_nearest_match (gpointer key,
01664                          gpointer value,
01665                          gpointer user_data)
01666 {
01667     const gchar *widget_name = key;
01668     const gchar *gconf_name = user_data;
01669 
01670     return (strncmp(widget_name, gconf_name, strlen(gconf_name)) == 0);
01671 }
01672 
01673 
01685 static void
01686 gnc_preferences_gconf_changed (GConfClient *client,
01687                                guint cnxn_id,
01688                                GConfEntry *entry,
01689                                gpointer dialog)
01690 {
01691     GConfValue *value;
01692     const gchar *key, *string_value;
01693     gchar  **parts, *name, *group_name = NULL;
01694     GtkWidget *widget;
01695     GHashTable *table;
01696 
01697     ENTER("key %s, value %p", entry->key, entry->value);
01698     key = gconf_entry_get_key(entry);
01699     value = gconf_entry_get_value(entry);
01700     if (!value)
01701     {
01702         /* Values can be unset */
01703         LEAVE("Unset valued for %s", key);
01704         return;
01705     }
01706 
01707     parts = g_strsplit(entry->key, "/", 4);
01708     name = g_strconcat("gconf/", parts[3], NULL);
01709     g_strfreev(parts);
01710     DEBUG("proposed widget name %s", name);
01711 
01712     /* Can't just do a glade lookup here because not all of the widgets
01713      * came from the same xml file. That's why the extra hash table. */
01714     table = g_object_get_data(G_OBJECT(dialog), WIDGET_HASH);
01715     widget = g_hash_table_lookup(table, name);
01716     if ((widget == NULL) && (entry->value->type == GCONF_VALUE_STRING))
01717     {
01718         string_value = gconf_value_get_string(entry->value);
01719         group_name = name;
01720         name = g_strjoin("/", group_name, string_value, NULL);
01721         DEBUG("proposed widget name %s", name);
01722         widget = g_hash_table_lookup(table, name);
01723         if (widget == NULL)
01724         {
01725             /* Mutter, mutter. Someone must have typed a bad string into
01726              * gconf.  Force the value to a legal string.  Do this by
01727              * directly setting the first widget in the group. This will
01728              * ensure synchronization of Gnucash, Gconf, and the Prefs
01729              * Dialog. */
01730             DEBUG("bad value");
01731             widget = g_hash_table_find(table, gnc_prefs_nearest_match, group_name);
01732             if (widget)
01733             {
01734                 DEBUG("forcing %s", gtk_widget_get_name(widget));
01735                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE);
01736             }
01737             g_free(group_name);
01738             g_free(name);
01739             LEAVE("no exact match");
01740             return;
01741         }
01742         g_free(group_name);
01743     }
01744     if (widget != NULL)
01745     {
01746         /* These tests must be ordered from more specific widget to less
01747          * specific widget. */
01748 
01749         if (GTK_IS_FONT_BUTTON(widget))
01750         {
01751             DEBUG("widget %p - font button", widget);
01752             gnc_prefs_font_button_gconf_cb(GTK_FONT_BUTTON(widget), entry);
01753         }
01754         else if (GTK_IS_RADIO_BUTTON(widget))
01755         {
01756             DEBUG("widget %p - radio button", widget);
01757             gnc_prefs_radio_button_gconf_cb(GTK_RADIO_BUTTON(widget));
01758         }
01759         else if (GTK_IS_CHECK_BUTTON(widget))
01760         {
01761             DEBUG("widget %p - check button", widget);
01762             gnc_prefs_check_button_gconf_cb(GTK_CHECK_BUTTON(widget),
01763                                             gconf_value_get_bool(entry->value));
01764         }
01765         else if (GTK_IS_SPIN_BUTTON(widget))
01766         {
01767             DEBUG("widget %p - spin button", widget);
01768             gnc_prefs_spin_button_gconf_cb(GTK_SPIN_BUTTON(widget),
01769                                            gconf_value_get_float(entry->value));
01770         }
01771         else if (GTK_IS_COMBO_BOX(widget))
01772         {
01773             DEBUG("widget %p - combo_box", widget);
01774             gnc_prefs_combo_box_gconf_cb(GTK_COMBO_BOX(widget),
01775                                          gconf_value_get_int(entry->value));
01776         }
01777         else if (GTK_IS_ENTRY(widget))
01778         {
01779             DEBUG("widget %p - entry", widget);
01780             gnc_prefs_entry_gconf_cb(GTK_ENTRY(widget),
01781                                      gconf_value_get_string(entry->value));
01782         }
01783         else if (GTK_IS_HBOX(widget))
01784         {
01785             /* Test custom widgets are all children of a hbox */
01786             GtkWidget *widget_child;
01787             GList* child = gtk_container_get_children(GTK_CONTAINER(widget));
01788             widget_child = child->data;
01789             g_list_free(child);
01790 
01791             DEBUG("  %s - hbox", name);
01792             DEBUG("Hbox gconf name is %s and widget get name is %s", name, gtk_widget_get_name(GTK_WIDGET(widget_child)));
01793 
01794             if (GNC_IS_CURRENCY_EDIT(widget_child))
01795             {
01796                 DEBUG("widget %p - currency_edit", widget_child);
01797                 gnc_prefs_currency_edit_gconf_cb(GNC_CURRENCY_EDIT(widget_child), entry);
01798             }
01799             else if (GNC_IS_PERIOD_SELECT(widget_child))
01800             {
01801                 DEBUG("widget %p - period_select", widget_child);
01802                 gnc_prefs_period_select_gconf_cb(GNC_PERIOD_SELECT(widget_child),
01803                                                  gconf_value_get_int(entry->value));
01804             }
01805             else if (GNC_IS_DATE_EDIT(widget_child))
01806             {
01807                 DEBUG("widget %p - date_edit", widget_child);
01808                 gnc_prefs_date_edit_gconf_cb(GNC_DATE_EDIT(widget_child), entry);
01809             }
01810         }
01811         else
01812         {
01813             DEBUG("widget %p - unsupported %s", widget,
01814                   G_OBJECT_TYPE_NAME(G_OBJECT(widget)));
01815         }
01816     }
01817     g_free(name);
01818     LEAVE(" ");
01819 }
01820 
01821 
01836 static gboolean
01837 show_handler (const char *class, gint component_id,
01838               gpointer user_data, gpointer iter_data)
01839 {
01840     GtkWidget *dialog;
01841 
01842     ENTER(" ");
01843     dialog = GTK_WIDGET(user_data);
01844     gtk_window_present(GTK_WINDOW(dialog));
01845     LEAVE(" ");
01846     return(TRUE);
01847 }
01848 
01849 
01856 static void
01857 close_handler (gpointer user_data)
01858 {
01859     GtkWidget *dialog;
01860 
01861     ENTER(" ");
01862     dialog = GTK_WIDGET(user_data);
01863     gnc_unregister_gui_component_by_data(DIALOG_PREFERENCES_CM_CLASS, dialog);
01864     gtk_widget_destroy(dialog);
01865     LEAVE(" ");
01866 }
01867 
01868 
01869 /*  This function creates the preferences dialog and presents it to
01870  *  the user.  The preferences dialog is a singleton, so if a
01871  *  preferences dialog already exists it will be raised to the top of
01872  *  the window stack instead of creating a new dialog. */
01873 void
01874 gnc_preferences_dialog (void)
01875 {
01876     GtkWidget *dialog;
01877 
01878     ENTER("");
01879     if (gnc_forall_gui_components(DIALOG_PREFERENCES_CM_CLASS,
01880                                   show_handler, NULL))
01881     {
01882         LEAVE("existing window");
01883         return;
01884     }
01885 
01886     dialog = gnc_preferences_dialog_create();
01887 
01888     gnc_restore_window_size(GCONF_SECTION, GTK_WINDOW(dialog));
01889     gtk_widget_show(dialog);
01890 
01891     gnc_gconf_add_notification(G_OBJECT(dialog), NULL,
01892                                gnc_preferences_gconf_changed,
01893                                DIALOG_PREFERENCES_CM_CLASS);
01894     gnc_gconf_general_register_cb(KEY_ACCOUNT_SEPARATOR,
01895                                   (GncGconfGeneralCb)gnc_account_separator_prefs_cb,
01896                                   dialog);
01897     gnc_register_gui_component(DIALOG_PREFERENCES_CM_CLASS,
01898                                NULL, close_handler, dialog);
01899 
01900     LEAVE(" ");
01901 }
01902 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines