GnuCash  5.6-150-g038405b370+
dialog-preferences.c
Go to the documentation of this file.
1 /********************************************************************\
2  * dialog-preferences.c -- preferences dialog *
3  * *
4  * Copyright (C) 2005 David Hampton *
5  * Copyright (C) 2011 Robert Fewell *
6  * Copyright (C) 2013 Geert Janssens *
7  * *
8  * This program is free software; you can redistribute it and/or *
9  * modify it under the terms of the GNU General Public License as *
10  * published by the Free Software Foundation; either version 2 of *
11  * the License, or (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License*
19  * along with this program; if not, contact: *
20  * *
21  * Free Software Foundation Voice: +1-617-542-5942 *
22  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
23  * Boston, MA 02110-1301, USA gnu@gnu.org *
24 \********************************************************************/
25 
63 #include <config.h>
64 
65 #include <gtk/gtk.h>
66 #include <glib/gi18n.h>
67 
68 #include "dialog-utils.h"
69 #include "gnc-currency-edit.h"
70 #include "gnc-date-edit.h"
71 #include "gnc-gobject-utils.h"
72 #include "gnc-period-select.h"
73 #include "gnc-engine.h"
74 #include "Account.h"
75 #include "gnc-prefs.h"
76 #include "gnc-ui.h"
77 #include "gnc-ui-util.h"
78 #include <gnc-session.h>
79 #include "gnc-component-manager.h"
80 #include "dialog-preferences.h"
81 #include "dialog-doclink-utils.h"
82 
83 #define DIALOG_PREFERENCES_CM_CLASS "dialog-newpreferences"
84 #define GNC_PREFS_GROUP "dialogs.preferences"
85 #define PREF_PREFIX_LEN sizeof("pref/") - 1
86 #define PREFS_WIDGET_HASH "prefs_widget_hash"
87 #define NOTEBOOK "notebook"
88 
90 static QofLogModule log_module = GNC_MOD_PREFS;
91 
92 void gnc_preferences_response_cb (GtkDialog *dialog, gint response, GtkDialog *unused);
93 void gnc_account_separator_pref_changed_cb (GtkEntry *entry, GtkWidget *dialog);
94 void gnc_save_on_close_expires_cb (GtkToggleButton *button, GtkWidget *dialog);
95 gboolean gnc_preferences_delete_event_cb (GtkWidget *widget,
96  GdkEvent *event,
97  gpointer user_data);
98 
101 typedef struct addition_t
102 {
105  gchar *filename;
109  gchar *widgetname;
112  gchar *tabname;
115  gboolean full_page;
116 } addition;
117 
121 GSList *add_ins = NULL;
122 
123 static gchar *gnc_account_separator_is_valid (const gchar *separator,
124  gchar **normalized_separator)
125 {
126  QofBook *book;
127  GList *conflict_accts = NULL;
128  gchar *message = NULL;
129 
130  if (!gnc_current_session_exist())
131  return NULL;
132 
133  book = gnc_get_current_book ();
134  *normalized_separator = gnc_normalize_account_separator (separator);
135  conflict_accts = gnc_account_list_name_violations (book, *normalized_separator);
136  if (conflict_accts)
137  message = gnc_account_name_violations_errmsg (*normalized_separator,
138  conflict_accts);
139 
140  g_list_free_full (conflict_accts, g_free);
141  return message;
142 }
143 
154 void
155 gnc_account_separator_pref_changed_cb (GtkEntry *entry, GtkWidget *dialog)
156 {
157  GtkWidget *label, *image;
158  gchar *sample;
159  gchar *separator = NULL;
160 
161  gchar *conflict_msg = gnc_account_separator_is_valid (gtk_entry_get_text (entry), &separator);
162 
163  label = g_object_get_data (G_OBJECT(dialog), "sample_account");
164  DEBUG("Sample Account pointer is %p", label);
165  /* Translators: Both %s will be the account separator character; the
166  resulting string is a demonstration how the account separator
167  character will look like. You can replace these three account
168  names with other account names that are more suitable for your
169  language - just keep in mind to have exactly two %s in your
170  translation. */
171  sample = g_strdup_printf (_("Income%sSalary%sTaxable"),
172  separator, separator);
173  PINFO(" Label set to '%s'", sample);
174  gtk_label_set_text (GTK_LABEL(label), sample);
175  g_free (sample);
176 
177  /* Check if the new separator clashes with existing account names */
178  image = g_object_get_data (G_OBJECT(dialog), "separator_error");
179  DEBUG("Separator Error Image pointer is %p", image);
180 
181  if (conflict_msg)
182  {
183  gtk_widget_set_tooltip_text (GTK_WIDGET(image), conflict_msg);
184  gtk_widget_show (GTK_WIDGET(image));
185  g_free (conflict_msg);
186  }
187  else
188  gtk_widget_hide (GTK_WIDGET(image));
189 
190  g_free (separator);
191 }
192 
193 
203 static gboolean
204 gnc_account_separator_validate (GtkWidget *dialog)
205 {
206  GtkWidget *entry = g_object_get_data (G_OBJECT(dialog), "account-separator");
207  gboolean ret = TRUE;
208  gchar *separator = NULL;
209  gchar *conflict_msg = gnc_account_separator_is_valid (gtk_entry_get_text (GTK_ENTRY(entry)), &separator);
210 
211  /* Check if the new separator clashes with existing account names */
212  if (conflict_msg)
213  {
214  GtkWidget *msg_dialog, *msg_label;
215  GtkBuilder *builder;
216  gint response;
217 
218  builder = gtk_builder_new ();
219  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "separator_validation_dialog");
220 
221  msg_dialog = GTK_WIDGET(gtk_builder_get_object (builder, "separator_validation_dialog"));
222 
223  msg_label = GTK_WIDGET(gtk_builder_get_object (builder, "conflict_message"));
224 
225  gtk_label_set_text (GTK_LABEL(msg_label), conflict_msg);
226 
227  g_object_unref (G_OBJECT(builder));
228  gtk_widget_show_all (msg_dialog);
229 
230  response = gtk_dialog_run (GTK_DIALOG(msg_dialog));
231  if (response == GTK_RESPONSE_ACCEPT) // reset to original
232  {
233  gchar *original_sep = g_object_get_data (G_OBJECT(entry), "original_text");
234 
235  if (original_sep != NULL)
236  gtk_entry_set_text (GTK_ENTRY(entry), original_sep);
237  }
238  else
239  ret = FALSE;
240 
241  g_free (conflict_msg);
242  gtk_widget_destroy (msg_dialog);
243  }
244  g_free (separator);
245  return ret;
246 }
247 
248 
257 static void
258 gnc_preferences_select_account_page (GtkDialog *dialog)
259 {
260  GtkWidget *notebook = g_object_get_data (G_OBJECT(dialog), NOTEBOOK);
261  GList *children = gtk_container_get_children (GTK_CONTAINER(notebook));
262 
263  if (children)
264  {
265  GtkWidget *acc_page = NULL;
266  GList *node;
267 
268  for (node = children; node; node = node->next)
269  {
270  if (g_strcmp0 (gtk_widget_get_name (GTK_WIDGET(node->data)), "accounts_page") == 0)
271  acc_page = node->data;
272  }
273 
274  if (acc_page)
275  gtk_notebook_set_current_page (GTK_NOTEBOOK(notebook),
276  gtk_notebook_page_num (GTK_NOTEBOOK(notebook),
277  acc_page));
278  }
279  g_list_free (children);
280 }
281 
282 
288 void
289 gnc_save_on_close_expires_cb (GtkToggleButton *button, GtkWidget *dialog)
290 {
291  GtkWidget *spinner = g_object_get_data (G_OBJECT(dialog),
292  "save_on_close_wait_time");
293  gtk_widget_set_sensitive (spinner, gtk_toggle_button_get_active (button));
294 }
295 
307 static gint
308 gnc_prefs_compare_addins (addition *a,
309  addition *b)
310 {
311  return g_utf8_collate (a->tabname, b->tabname);
312 }
313 
314 
334 static void
335 gnc_preferences_add_page_internal (const gchar *filename,
336  const gchar *widgetname,
337  const gchar *tabname,
338  gboolean full_page)
339 {
340  addition *add_in, *preexisting;
341  gboolean error = FALSE;
342  GSList *ptr;
343 
344  ENTER("file %s, widget %s, tab %s full page %d",
345  filename, widgetname, tabname, full_page);
346 
347  add_in = g_malloc (sizeof(addition));
348  if (add_in == NULL)
349  {
350  g_critical ("Unable to allocate memory.\n");
351  LEAVE("no memory");
352  return;
353  }
354 
355  add_in->filename = g_strdup (filename);
356  add_in->widgetname = g_strdup (widgetname);
357  add_in->tabname = g_strdup (tabname);
358  add_in->full_page = full_page;
359  if (!add_in->filename || !add_in->widgetname || !add_in->tabname)
360  {
361  g_critical ("Unable to allocate memory.\n");
362  g_free (add_in->filename);
363  g_free (add_in->widgetname);
364  g_free (add_in->tabname);
365  g_free (add_in);
366  LEAVE("no memory");
367  return;
368  }
369 
370  ptr = g_slist_find_custom (add_ins, add_in, (GCompareFunc)gnc_prefs_compare_addins);
371  if (ptr)
372  {
373  /* problem? */
374  preexisting = ptr->data;
375 
376  if (preexisting->full_page)
377  {
378  g_warning ("New tab %s(%s/%s/%s) conflicts with existing tab %s(%s/%s/full)",
379  add_in->tabname, add_in->filename, add_in->widgetname,
380  add_in->full_page ? "full" : "partial",
381  preexisting->tabname, preexisting->filename, preexisting->widgetname);
382  error = TRUE;
383  }
384  else if (add_in->full_page)
385  {
386  g_warning ("New tab %s(%s/%s/%s) conflicts with existing tab %s(%s/%s/partial)",
387  add_in->tabname, add_in->filename, add_in->widgetname,
388  add_in->full_page ? "full" : "partial",
389  preexisting->tabname, preexisting->filename, preexisting->widgetname);
390  error = TRUE;
391  }
392  }
393 
394  if (error)
395  {
396  g_free (add_in->filename);
397  g_free (add_in->widgetname);
398  g_free (add_in->tabname);
399  g_free (add_in);
400  LEAVE("err");
401  return;
402  }
403  else
404  {
405  add_ins = g_slist_append (add_ins, add_in);
406  }
407  LEAVE("");
408 }
409 
410 
411 /* This function adds a full page of preferences to the preferences
412  * dialog. When the dialog is created, the specified content will be
413  * pulled from the specified glade file and added to the preferences
414  * dialog with the specified tab name. The tab name may not be
415  * duplicated. For example, the Business code might have a full page
416  * of its own preferences. */
417 void
418 gnc_preferences_add_page (const gchar *filename,
419  const gchar *widgetname,
420  const gchar *tabname)
421 {
422  gnc_preferences_add_page_internal (filename, widgetname, tabname, TRUE);
423 }
424 
425 
426 /* This function adds a partial page of preferences to the
427  * preferences dialog. When the dialog is created, the specified
428  * content will be pulled from the glade file and added to the
429  * preferences dialog with the specified tab name. The tab name
430  * may be duplicated. For example, the HBCI preferences may share a
431  * "Data Import" page with QIF and other methods. */
432 void
433 gnc_preferences_add_to_page (const gchar *filename,
434  const gchar *widgetname,
435  const gchar *tabname)
436 {
437  gnc_preferences_add_page_internal (filename, widgetname, tabname, FALSE);
438 }
439 
440 
441 /*******************************************************************/
442 
456 static void
457 gnc_prefs_build_widget_table (GtkBuilder *builder,
458  GtkWidget *dialog)
459 {
460  GHashTable *prefs_table;
461  GSList *interesting, *runner;
462  const gchar *name;
463  const gchar *wname;
464  GtkWidget *widget;
465 
466  prefs_table = g_object_get_data (G_OBJECT(dialog), PREFS_WIDGET_HASH);
467 
468  interesting = gtk_builder_get_objects (builder);
469 
470  for (runner = interesting; runner; runner = g_slist_next(runner))
471  {
472  widget = runner->data;
473  if (GTK_IS_WIDGET(widget))
474  {
475  wname = gtk_widget_get_name (widget);
476  name = gtk_buildable_get_name (GTK_BUILDABLE(widget));
477  DEBUG("Widget type is %s and buildable get name is %s", wname, name);
478  if (g_str_has_prefix (name, "pref"))
479  g_hash_table_insert (prefs_table, (gchar *)name, widget);
480  }
481  }
482  g_slist_free (interesting);
483 
484 }
485 
486 
492 struct copy_data
493 {
495  GtkGrid *grid_from;
497  GtkGrid *grid_to;
499  gint cols, rows;
500 };
501 
502 
503 static GtkWidget *
504 gnc_prefs_find_page (GtkNotebook *notebook, const gchar *name)
505 {
506  int n_pages, i;
507  GtkWidget *child;
508  const gchar *child_name;
509 
510  g_return_val_if_fail (GTK_IS_NOTEBOOK(notebook), NULL);
511  g_return_val_if_fail (name, NULL);
512 
513  ENTER("");
514 
515  n_pages = gtk_notebook_get_n_pages (notebook);
516 
517  for (i = 0; i < n_pages; i++)
518  {
519  child = gtk_notebook_get_nth_page (notebook, i);
520  g_return_val_if_fail (child, NULL);
521 
522  child_name = gtk_notebook_get_tab_label_text (notebook, child);
523  g_return_val_if_fail (child_name, NULL);
524 
525  if (g_utf8_collate (name, child_name) == 0)
526  {
527  LEAVE("found at index: %d", i);
528  return child;
529  }
530  }
531 
532  LEAVE("not found");
533  return NULL;
534 }
535 
536 
548 static void
549 gnc_prefs_get_grid_size (GtkWidget *child, gpointer data)
550 {
551  struct copy_data *copydata = data;
552  gint top, left, height, width;
553 
554  gtk_container_child_get (GTK_CONTAINER(copydata->grid_to), child,
555  "left-attach", &left,
556  "top-attach", &top,
557  "height", &height,
558  "width", &width,
559  NULL);
560 
561  if (left + width >= copydata->cols)
562  copydata->cols = left + width;
563 
564  if (top + height >= copydata->rows)
565  copydata->rows = top + height;
566 }
567 
568 
581 static void
582 gnc_prefs_move_grid_entry (GtkWidget *child,
583  gpointer data)
584 {
585  struct copy_data *copydata = data;
586  gint top, left, height, width;
587  gboolean hexpand, vexpand;
588  GtkAlign halign, valign;
589  gint topm, bottomm, leftm, rightm;
590 
591  ENTER("child %p, copy data %p", child, data);
592  gtk_container_child_get (GTK_CONTAINER(copydata->grid_from), child,
593  "left-attach", &left,
594  "top-attach", &top,
595  "height", &height,
596  "width", &width,
597  NULL);
598  hexpand = gtk_widget_get_hexpand (child);
599  vexpand = gtk_widget_get_vexpand (child);
600  halign = gtk_widget_get_halign (child);
601  valign = gtk_widget_get_valign (child);
602 
603  g_object_get (child, "margin-top", &topm, "margin-bottom", &bottomm, NULL);
604  g_object_get (child, "margin-left", &leftm, "margin-right", &rightm, NULL);
605 
606  g_object_ref (child);
607  gtk_container_remove (GTK_CONTAINER(copydata->grid_from), child);
608 
609  gtk_grid_attach (copydata->grid_to, child, left, copydata->rows + top , width, height);
610 
611  gtk_widget_set_hexpand (child, hexpand);
612  gtk_widget_set_vexpand (child, vexpand);
613  gtk_widget_set_halign (child, halign);
614  gtk_widget_set_valign (child, valign);
615 
616  g_object_set (child, "margin-left", leftm, "margin-right", rightm, NULL);
617  g_object_set (child, "margin-top", topm, "margin-bottom", bottomm, NULL);
618 
619  g_object_unref (child);
620  LEAVE(" ");
621 }
622 
623 
635 static void
636 gnc_preferences_build_page (gpointer data,
637  gpointer user_data)
638 {
639  GtkBuilder *builder;
640  GtkWidget *dialog, *existing_content, *new_content, *label;
641  GtkNotebook *notebook;
642  addition *add_in;
643  struct copy_data copydata = {NULL, NULL, 0, 0};
644  gchar **widgetname;
645  gint i;
646 
647  ENTER("add_in %p, dialog %p", data, user_data);
648  add_in = (addition *)data;
649  dialog = user_data;
650 
651  DEBUG("Opening %s to get %s", add_in->filename, add_in->widgetname);
652  builder = gtk_builder_new ();
653 
654  /* Adjustments etc... must come before dialog information */
655  widgetname = g_strsplit (add_in->widgetname, ",", -1);
656 
657  for (i = 0; widgetname[i]; i++)
658  {
659  DEBUG("Opening %s to get content %s", add_in->filename, widgetname[i]);
660  gnc_builder_add_from_file (builder, add_in->filename, widgetname[i]);
661  }
662 
663  DEBUG("Widget Content is %s", widgetname[i - 1]);
664  new_content = GTK_WIDGET(gtk_builder_get_object (builder, widgetname[i - 1]));
665 
666  g_strfreev (widgetname);
667  DEBUG("done");
668 
669  /* Add to the list of interesting widgets */
670  gnc_prefs_build_widget_table (builder, dialog);
671 
672  /* Connect the signals in this glade file. The dialog is passed in
673  * so the callback can find "interesting" widgets from other
674  * glade files if necessary (via the GPREFS_WIDGET_HASH hash table). */
675  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, dialog);
676 
677  /* Prepare for recursion */
678  notebook = g_object_get_data (G_OBJECT(dialog), NOTEBOOK);
679 
680  if (add_in->full_page)
681  {
682  label = gtk_label_new (add_in->tabname);
683  gnc_label_set_alignment (label, 0.0, 0.5);
684  gtk_notebook_append_page (notebook, new_content, label);
685  g_object_unref (G_OBJECT(builder));
686  LEAVE("appended page");
687  return;
688  }
689 
690  /* Copied grids must be grids */
691  if (!GTK_IS_GRID(new_content))
692  {
693  g_critical ("The object name %s in file %s is not a GtkGrid. It cannot "
694  "be added to the preferences dialog.",
695  add_in->widgetname, add_in->filename);
696  g_object_unref (G_OBJECT(builder));
697  LEAVE("");
698  return;
699  }
700 
701  /* Does the page exist or must we create it */
702  existing_content = gnc_prefs_find_page (notebook, add_in->tabname);
703 
704  if (!existing_content)
705  {
706  /* No existing content with this name. Create a blank page */
707  existing_content = gtk_grid_new ();
708  gtk_container_set_border_width (GTK_CONTAINER(existing_content), 6);
709  label = gtk_label_new (add_in->tabname);
710  gnc_label_set_alignment (label, 0.0, 0.5);
711  gtk_notebook_append_page (notebook, existing_content, label);
712  gtk_widget_show_all (existing_content);
713  DEBUG("created new page %s, appended it", add_in->tabname);
714  }
715  else
716  {
717  /* Lets get the size of the existing grid */
718  copydata.grid_to = GTK_GRID(existing_content);
719  gtk_container_foreach (GTK_CONTAINER(existing_content), gnc_prefs_get_grid_size, &copydata);
720 
721  DEBUG("found existing page %s, grid size is %d x %d", add_in->tabname, copydata.rows, copydata.cols);
722  }
723 
724  /* Maybe add a spacer row */
725  if (copydata.rows > 0)
726  {
727  label = gtk_label_new ("");
728  gtk_widget_show (label);
729  gtk_grid_attach (GTK_GRID(existing_content), label, 0, copydata.rows, 1, 1);
730  copydata.rows = copydata.rows + 1;
731 
732  DEBUG("add spacer row");
733  }
734 
735  /* Now copy all the entries in the grid */
736  copydata.grid_from = GTK_GRID(new_content);
737  copydata.grid_to = GTK_GRID(existing_content);
738  gtk_container_foreach (GTK_CONTAINER(new_content), gnc_prefs_move_grid_entry, &copydata);
739 
740  g_object_ref_sink (new_content);
741  g_object_unref (G_OBJECT(builder));
742 
743  LEAVE("added content to page");
744 }
745 
746 
747 static gint
748 tab_cmp (GtkWidget *page_a, GtkWidget *page_b, GtkNotebook *notebook)
749 {
750  return g_utf8_collate (gtk_notebook_get_tab_label_text (notebook, page_a),
751  gtk_notebook_get_tab_label_text (notebook, page_b));
752 }
753 
754 
755 static void
756 gnc_prefs_sort_pages (GtkNotebook *notebook)
757 {
758  gint n_pages, i;
759  GList *tabs = NULL, *iter = NULL;
760 
761  g_return_if_fail (GTK_IS_NOTEBOOK(notebook));
762 
763  /* gather tabs */
764  n_pages = gtk_notebook_get_n_pages (notebook);
765  for (i = n_pages - 1; i >= 0; i--)
766  tabs = g_list_prepend (tabs, gtk_notebook_get_nth_page (notebook, i));
767 
768  /* sort in local copy */
769  tabs = g_list_sort_with_data (tabs, (GCompareDataFunc) tab_cmp, notebook);
770 
771  /* reorder tabs */
772  for (i = 0, iter = tabs; iter; i++, iter = iter->next)
773  gtk_notebook_reorder_child (notebook, GTK_WIDGET(iter->data), i);
774 
775  g_list_free (tabs);
776 }
777 
778 
779 /*******************************/
780 /* Dynamically added Callbacks */
781 /*******************************/
782 
783 static void
784 gnc_prefs_split_widget_name (const gchar *name, gchar **group, gchar **pref, gchar **value)
785 {
786  const gchar *group_with_pref = name + PREF_PREFIX_LEN;
787  gchar **splits = g_strsplit (group_with_pref, "/", 0);
788  gchar **value_splits = g_strsplit (splits[1], "=", 0);
789 
790  *group = g_strdup (splits[0]);
791  *pref = g_strdup (value_splits[0]);
792  if (value)
793  *value = g_strdup (value_splits[1]); /* may be NULL */
794  g_strfreev (splits);
795  g_strfreev (value_splits);
796 }
797 
798 /****************************************************************************/
799 
806 static void
807 gnc_prefs_connect_font_button (GtkFontButton *fb)
808 {
809  gchar *group, *pref;
810 
811  g_return_if_fail (GTK_IS_FONT_BUTTON(fb));
812 
813  gnc_prefs_split_widget_name (gtk_buildable_get_name (GTK_BUILDABLE(fb)), &group, &pref, NULL);
814  gnc_prefs_bind (group, pref, NULL, G_OBJECT (fb), "font-name");
815 
816  g_free (group);
817  g_free (pref);
818 
819  gtk_widget_show_all (GTK_WIDGET(fb));
820 }
821 
822 /****************************************************************************/
823 
830 static void
831 file_chooser_selected_cb (GtkFileChooser *fc, gpointer user_data)
832 {
833  GtkImage *image = g_object_get_data (G_OBJECT(fc), "path_head_error");
834  const gchar *group = g_object_get_data (G_OBJECT(fc), "group");
835  const gchar *pref = g_object_get_data (G_OBJECT(fc), "pref");
836  gchar *folder_uri = gtk_file_chooser_get_uri (fc);
837  gchar *old_path_head_uri = gnc_doclink_get_path_head ();
838 
839  // make sure path_head ends with a trailing '/', 3.5 onwards
840  if (!g_str_has_suffix (folder_uri, "/"))
841  {
842  gchar *folder_with_slash = g_strconcat (folder_uri, "/", NULL);
843  g_free (folder_uri);
844  folder_uri = g_strdup (folder_with_slash);
845  g_free (folder_with_slash);
846  }
847 
848  gtk_widget_hide (GTK_WIDGET(image));
849 
850  if (!gnc_prefs_set_string (group, pref, folder_uri))
851  PINFO("Failed to save preference at %s, %s with %s", group, pref, folder_uri);
852  else
853  gnc_doclink_pref_path_head_changed (
854  GTK_WINDOW(gtk_widget_get_toplevel (GTK_WIDGET(fc))),
855  old_path_head_uri);
856 
857  g_free (old_path_head_uri);
858  g_free (folder_uri);
859 }
860 
869 static void
870 gnc_prefs_connect_file_chooser_button (GtkFileChooserButton *fcb, const gchar *boxname)
871 {
872  GtkImage *image;
873  gchar *group, *pref;
874  gchar *uri;
875  gboolean folder_set = TRUE;
876 
877  g_return_if_fail (GTK_FILE_CHOOSER_BUTTON(fcb));
878 
879  if (boxname == NULL)
880  gnc_prefs_split_widget_name (gtk_buildable_get_name (GTK_BUILDABLE(fcb)), &group, &pref, NULL);
881  else
882  gnc_prefs_split_widget_name (boxname, &group, &pref, NULL);
883 
884  uri = gnc_prefs_get_string (group, pref);
885 
886  PINFO("Uri is %s", uri);
887 
888  if (uri && *uri) // default entry
889  {
890  gchar *path_head = g_filename_from_uri (uri, NULL, NULL);
891 
892  // test for current folder present and set chooser to it
893  if (g_file_test (path_head, G_FILE_TEST_IS_DIR))
894  gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER(fcb), uri);
895  else
896  folder_set = FALSE;
897 
898  g_free (path_head);
899  }
900 
901  image = g_object_get_data (G_OBJECT(fcb), "path_head_error");
902 
903  if (folder_set) // If current folder missing, display error and tt message
904  gtk_widget_hide (GTK_WIDGET(image));
905  else
906  {
907  gchar *path_head = gnc_doclink_get_unescape_uri (NULL, uri, "file");
908  gchar *ttip = g_strconcat (_("Path does not exist, "), path_head, NULL);
909 
910  gtk_widget_set_tooltip_text (GTK_WIDGET(image), ttip);
911  gtk_widget_show (GTK_WIDGET(image));
912 
913  g_free (ttip);
914  g_free (path_head);
915  }
916 
917  g_signal_connect (GTK_FILE_CHOOSER(fcb), "selection-changed",
918  G_CALLBACK(file_chooser_selected_cb), NULL);
919 
920  g_object_set_data_full (G_OBJECT(fcb),"group", g_strdup (group), (GDestroyNotify) g_free);
921  g_object_set_data_full (G_OBJECT(fcb),"pref", g_strdup (pref), (GDestroyNotify) g_free);
922 
923  g_free (group);
924  g_free (pref);
925  g_free (uri);
926 
927  gtk_widget_show_all (GTK_WIDGET(fcb));
928 }
929 
938 static void
939 file_chooser_clear_cb (GtkButton *button, gpointer user_data)
940 {
941  GtkFileChooserButton *fcb = GTK_FILE_CHOOSER_BUTTON(user_data);
942  const gchar *group = g_object_get_data (G_OBJECT(fcb), "group");
943  const gchar *pref = g_object_get_data (G_OBJECT(fcb), "pref");
944  GtkImage *image = g_object_get_data (G_OBJECT(fcb), "path_head_error");
945  GtkWidget *box;
946  GtkWidget *fcb_new;
947  gchar *boxname;
948  gchar *old_path_head_uri = gnc_doclink_get_path_head ();
949 
950  /* We need to destroy the GtkFileChooserButton and recreate as there
951  does not seem to be away of resetting the folder path to NONE */
952  box = gtk_widget_get_parent (GTK_WIDGET(fcb));
953  g_signal_handlers_disconnect_by_func (button, file_chooser_clear_cb, fcb);
954 
955  if (!gnc_prefs_set_string (group, pref, ""))
956  PINFO("Failed to Clear preference at %s, %s", group, pref);
957  else
958  gnc_doclink_pref_path_head_changed (
959  GTK_WINDOW(gtk_widget_get_toplevel (GTK_WIDGET(fcb))),
960  old_path_head_uri);
961 
962  gtk_widget_destroy (GTK_WIDGET(fcb));
963 
964  fcb_new = gtk_file_chooser_button_new (_("Select a folder"),
965  GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
966 
967  g_object_set_data (G_OBJECT(fcb_new), "path_head_error", image);
968  g_object_set_data_full (G_OBJECT(fcb_new),"group", g_strdup (group), (GDestroyNotify) g_free);
969  g_object_set_data_full (G_OBJECT(fcb_new),"pref", g_strdup (pref), (GDestroyNotify) g_free);
970 
971  gtk_box_pack_start (GTK_BOX(box), fcb_new, TRUE, TRUE, 0);
972  gtk_box_reorder_child (GTK_BOX(box), fcb_new, 0);
973  gtk_widget_show (fcb_new);
974 
975  g_signal_connect (GTK_BUTTON(button), "clicked",
976  G_CALLBACK(file_chooser_clear_cb), fcb_new);
977 
978  boxname = g_strconcat ("pref/", group, "/", pref, NULL);
979 
980  gnc_prefs_connect_file_chooser_button (GTK_FILE_CHOOSER_BUTTON(fcb_new), boxname);
981  g_free (boxname);
982  g_free (old_path_head_uri);
983 }
984 
985 /****************************************************************************/
986 
994 static void
995 gnc_prefs_connect_radio_button (GtkRadioButton *button)
996 {
997  gchar *group, *pref, *value;
998 
999  g_return_if_fail (GTK_IS_RADIO_BUTTON(button));
1000 
1001  gnc_prefs_split_widget_name (gtk_buildable_get_name (GTK_BUILDABLE(button)), &group, &pref, &value);
1002 
1003  gnc_prefs_bind (group, pref, value, G_OBJECT(button), "active");
1004 
1005  g_free (group);
1006  g_free (pref);
1007  g_free (value);
1008 }
1009 
1010 /****************************************************************************/
1011 
1019 static void
1020 gnc_prefs_connect_check_button (GtkCheckButton *button)
1021 {
1022  gchar *group, *pref, *value;
1023 
1024  g_return_if_fail (GTK_IS_CHECK_BUTTON(button));
1025 
1026  gnc_prefs_split_widget_name (gtk_buildable_get_name (GTK_BUILDABLE(button)), &group, &pref, &value);
1027 
1028  gnc_prefs_bind (group, pref, NULL, G_OBJECT(button), "active");
1029 
1030  g_free (group);
1031  g_free (pref);
1032  g_free (value);
1033 }
1034 
1035 /****************************************************************************/
1036 
1044 static void
1045 gnc_prefs_connect_spin_button (GtkSpinButton *spin)
1046 {
1047  gchar *group, *pref;
1048 
1049  g_return_if_fail (GTK_IS_SPIN_BUTTON(spin));
1050 
1051  gnc_prefs_split_widget_name (gtk_buildable_get_name (GTK_BUILDABLE(spin)), &group, &pref, NULL);
1052 
1053  gnc_prefs_bind (group, pref, NULL, G_OBJECT(spin), "value");
1054 
1055  g_free (group);
1056  g_free (pref);
1057 }
1058 
1059 /****************************************************************************/
1060 
1067 static void
1068 gnc_prefs_connect_combo_box (GtkComboBox *box)
1069 {
1070  gchar *group, *pref;
1071 
1072  g_return_if_fail (GTK_IS_COMBO_BOX(box));
1073 
1074  gnc_prefs_split_widget_name (gtk_buildable_get_name (GTK_BUILDABLE(box)), &group, &pref, NULL);
1075 
1076  gnc_prefs_bind (group, pref, NULL, G_OBJECT(box), "active");
1077 
1078  g_free (group);
1079  g_free (pref);
1080 }
1081 
1082 /****************************************************************************/
1083 
1090 static void
1091 gnc_prefs_connect_currency_edit (GNCCurrencyEdit *gce, const gchar *boxname )
1092 {
1093  gchar *group, *pref;
1094 
1095  g_return_if_fail (GNC_IS_CURRENCY_EDIT(gce));
1096 
1097  gnc_prefs_split_widget_name (boxname, &group, &pref, NULL);
1098 
1099  gnc_prefs_bind (group, pref, NULL, G_OBJECT(gce), "mnemonic");
1100 
1101  g_free (group);
1102  g_free (pref);
1103 
1104  gtk_widget_show_all (GTK_WIDGET(gce));
1105 }
1106 
1107 /****************************************************************************/
1108 
1115 static void
1116 gnc_prefs_connect_entry (GtkEntry *entry)
1117 {
1118  gchar *group, *pref;
1119 
1120  g_return_if_fail (GTK_IS_ENTRY(entry));
1121 
1122  gnc_prefs_split_widget_name (gtk_buildable_get_name (GTK_BUILDABLE(entry)), &group, &pref, NULL);
1123 
1124  gnc_prefs_bind (group, pref, NULL, G_OBJECT(entry), "text");
1125 
1126  g_free (group);
1127  g_free (pref);
1128 }
1129 
1130 /****************************************************************************/
1131 
1138 static void
1139 gnc_prefs_connect_period_select (GncPeriodSelect *period, const gchar *boxname )
1140 {
1141  gchar *group, *pref;
1142 
1143  g_return_if_fail (GNC_IS_PERIOD_SELECT(period));
1144 
1145  gnc_prefs_split_widget_name (boxname, &group, &pref, NULL);
1146 
1147  gnc_prefs_bind (group, pref, NULL, G_OBJECT(period), "active");
1148 
1149  g_free (group);
1150  g_free (pref);
1151 }
1152 
1153 /****************************************************************************/
1154 
1161 static void
1162 gnc_prefs_connect_date_edit (GNCDateEdit *gde , const gchar *boxname )
1163 {
1164  gchar *group, *pref;
1165 
1166  g_return_if_fail (GNC_IS_DATE_EDIT(gde));
1167 
1168  gnc_prefs_split_widget_name (boxname, &group, &pref, NULL);
1169 
1170  gnc_prefs_bind (group, pref, NULL, G_OBJECT(gde), "time");
1171 
1172  g_free (group);
1173  g_free (pref);
1174 }
1175 
1176 
1177 /****************************************************************************/
1178 
1179 /********************/
1180 /* Callbacks */
1181 /********************/
1182 
1183 gboolean
1184 gnc_preferences_delete_event_cb (GtkWidget *widget,
1185  GdkEvent *event,
1186  gpointer user_data)
1187 {
1188  /* need to block this for the account separator test */
1189  return TRUE;
1190 }
1191 
1205 void
1206 gnc_preferences_response_cb (GtkDialog *dialog, gint response, GtkDialog *unused)
1207 {
1208  switch (response)
1209  {
1210  case GTK_RESPONSE_HELP:
1211  gnc_gnome_help (GTK_WINDOW(dialog), DF_MANUAL, DL_GLOBPREFS);
1212  break;
1213 
1214  case GTK_RESPONSE_DELETE_EVENT:
1215  default:
1216  if (gnc_account_separator_validate (GTK_WIDGET(dialog)))
1217  {
1218  gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(dialog));
1219  gnc_unregister_gui_component_by_data (DIALOG_PREFERENCES_CM_CLASS,
1220  dialog);
1221  gtk_widget_destroy (GTK_WIDGET(dialog));
1222  }
1223  else
1224  gnc_preferences_select_account_page (dialog);
1225  break;
1226  }
1227 }
1228 
1229 
1230 /********************/
1231 /* Creation */
1232 /********************/
1233 
1245 static void
1246 gnc_prefs_connect_one (const gchar *name,
1247  GtkWidget *widget,
1248  gpointer user_data)
1249 {
1250  /* These tests must be ordered from more specific widget to less
1251  * specific widget. */
1252 
1253  if (GTK_IS_FONT_BUTTON(widget))
1254  {
1255  DEBUG(" %s - font button", name);
1256  gnc_prefs_connect_font_button (GTK_FONT_BUTTON(widget));
1257  }
1258  else if (GTK_IS_FILE_CHOOSER_BUTTON(widget))
1259  {
1260  DEBUG(" %s - file chooser button", name);
1261  gnc_prefs_connect_file_chooser_button (GTK_FILE_CHOOSER_BUTTON(widget), NULL);
1262  }
1263  else if (GTK_IS_RADIO_BUTTON(widget))
1264  {
1265  DEBUG(" %s - radio button", name);
1266  gnc_prefs_connect_radio_button (GTK_RADIO_BUTTON(widget));
1267  }
1268  else if (GTK_IS_CHECK_BUTTON(widget))
1269  {
1270  DEBUG(" %s - check button", name);
1271  gnc_prefs_connect_check_button (GTK_CHECK_BUTTON(widget));
1272  }
1273  else if (GTK_IS_SPIN_BUTTON(widget))
1274  {
1275  DEBUG(" %s - spin button", name);
1276  gnc_prefs_connect_spin_button (GTK_SPIN_BUTTON(widget));
1277  }
1278  else if (GTK_IS_COMBO_BOX(widget))
1279  {
1280  DEBUG(" %s - combo box", name);
1281  gnc_prefs_connect_combo_box (GTK_COMBO_BOX(widget));
1282  }
1283  else if (GTK_IS_ENTRY(widget))
1284  {
1285  DEBUG(" %s - entry", name);
1286  gnc_prefs_connect_entry (GTK_ENTRY(widget));
1287  }
1288  else if (GTK_IS_BOX(widget))
1289  {
1290  /* Test custom widgets are all children of a hbox */
1291  GtkWidget *widget_child;
1292  GList* child = gtk_container_get_children (GTK_CONTAINER(widget));
1293  widget_child = child->data;
1294  g_list_free (child);
1295  DEBUG(" %s - box", name);
1296  DEBUG("Box widget type is %s and name is %s", gtk_widget_get_name (GTK_WIDGET(widget_child)), name);
1297  if (GNC_IS_CURRENCY_EDIT(widget_child))
1298  {
1299  DEBUG(" %s - currency_edit", name);
1300  gnc_prefs_connect_currency_edit (GNC_CURRENCY_EDIT(widget_child), name );
1301  }
1302  else if (GNC_IS_PERIOD_SELECT(widget_child))
1303  {
1304  DEBUG(" %s - period_select", name);
1305  gnc_prefs_connect_period_select (GNC_PERIOD_SELECT(widget_child), name );
1306  }
1307  else if (GNC_IS_DATE_EDIT(widget_child))
1308  {
1309  DEBUG(" %s - date_edit", name);
1310  gnc_prefs_connect_date_edit (GNC_DATE_EDIT(widget_child), name );
1311  }
1312  else if (GTK_FILE_CHOOSER_BUTTON(widget_child))
1313  {
1314  DEBUG(" %s - file chooser button", name);
1315  gnc_prefs_connect_file_chooser_button (GTK_FILE_CHOOSER_BUTTON(widget_child), name );
1316  }
1317  }
1318  else
1319  {
1320  DEBUG(" %s - unsupported %s", name,
1321  G_OBJECT_TYPE_NAME(G_OBJECT(widget)));
1322  }
1323 }
1324 
1325 
1337 static GtkWidget *
1338 gnc_preferences_dialog_create (GtkWindow *parent)
1339 {
1340  GtkBuilder *builder;
1341  GtkWidget *dialog, *notebook, *label, *image, *spinner, *entry;
1342  GtkWidget *box, *date, *period, *currency, *fcb, *button;
1343  GHashTable *prefs_table;
1344  GDate* gdate = NULL;
1345  gchar buf[128];
1346  GtkListStore *store;
1347  GtkTreePath *path;
1348  GtkTreeIter iter;
1349  gnc_commodity *locale_currency;
1350  const gchar *currency_name;
1351  GDate fy_end;
1352  gboolean date_is_valid = FALSE;
1353 
1354  ENTER("");
1355  DEBUG("Opening dialog-preferences.glade:");
1356  builder = gtk_builder_new ();
1357 
1358  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "auto_decimal_places_adj");
1359  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "autosave_interval_minutes_adj");
1360  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "save_on_close_adj");
1361  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "date_backmonth_adj");
1362  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "default_zoom_adj");
1363  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "max_transactions_adj");
1364  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "key_length_adj");
1365  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "new_search_limit_adj");
1366  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "retain_days_adj");
1367  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "tab_width_adj");
1368  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "date_formats");
1369  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "atm_fee_adj");
1370  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "auto_add_adj");
1371  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "auto_clear_adj");
1372  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "match_adj");
1373  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "likely_day_threshold");
1374  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "unlikely_day_threshold");
1375  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "gnucash_preferences_dialog");
1376 
1377  dialog = GTK_WIDGET(gtk_builder_get_object (builder, "gnucash_preferences_dialog"));
1378 
1379  // Set the name for this dialog so it can be easily manipulated with css
1380  gtk_widget_set_name (GTK_WIDGET(dialog), "gnc-id-preferences");
1381 
1382  /* parent */
1383  gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(parent));
1384 
1385  label = GTK_WIDGET(gtk_builder_get_object (builder, "sample_account"));
1386  g_object_set_data (G_OBJECT(dialog), "sample_account", label);
1387 
1388  image = GTK_WIDGET(gtk_builder_get_object (builder, "separator_error"));
1389  g_object_set_data (G_OBJECT(dialog), "separator_error", image);
1390 
1391  entry = GTK_WIDGET(gtk_builder_get_object (builder, "pref/general/account-separator"));
1392  g_object_set_data (G_OBJECT(dialog), "account-separator", entry);
1393 
1394  spinner = GTK_WIDGET(gtk_builder_get_object (builder, "pref/general/save-on-close-wait-time"));
1395  g_object_set_data (G_OBJECT(dialog), "save_on_close_wait_time", spinner);
1396 
1397  DEBUG("autoconnect");
1398  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, dialog);
1399 
1400  DEBUG("done");
1401 
1402  notebook = GTK_WIDGET(gtk_builder_get_object (builder, "notebook1"));
1403  prefs_table = g_hash_table_new (g_str_hash, g_str_equal);
1404  g_object_set_data (G_OBJECT(dialog), NOTEBOOK, notebook);
1405  g_object_set_data_full (G_OBJECT(dialog), PREFS_WIDGET_HASH,
1406  prefs_table, (GDestroyNotify)g_hash_table_destroy);
1407 
1408 
1409  if (gnc_current_session_exist())
1410  {
1411  QofBook *book = gnc_get_current_book ();
1412  g_date_clear (&fy_end, 1);
1413  qof_instance_get (QOF_INSTANCE(book),
1414  "fy-end", &fy_end,
1415  NULL);
1416  }
1417  box = GTK_WIDGET(gtk_builder_get_object (builder,
1418  "pref/" GNC_PREFS_GROUP_ACCT_SUMMARY "/" GNC_PREF_START_PERIOD));
1419  period = gnc_period_select_new (TRUE);
1420  gtk_widget_show (period);
1421  gtk_box_pack_start (GTK_BOX(box), period, TRUE, TRUE, 0);
1422  if (date_is_valid)
1423  gnc_period_select_set_fy_end (GNC_PERIOD_SELECT(period), &fy_end);
1424 
1425  box = GTK_WIDGET(gtk_builder_get_object (builder,
1426  "pref/" GNC_PREFS_GROUP_ACCT_SUMMARY "/" GNC_PREF_END_PERIOD));
1427  period = gnc_period_select_new (FALSE);
1428  gtk_widget_show (period);
1429  gtk_box_pack_start (GTK_BOX(box), period, TRUE, TRUE, 0);
1430  if (date_is_valid)
1431  gnc_period_select_set_fy_end (GNC_PERIOD_SELECT(period), &fy_end);
1432 
1433  box = GTK_WIDGET(gtk_builder_get_object (builder,
1434  "pref/" GNC_PREFS_GROUP_ACCT_SUMMARY "/" GNC_PREF_START_DATE));
1435  date = gnc_date_edit_new (gnc_time (NULL), FALSE, FALSE);
1436  gtk_widget_show (date);
1437  gtk_box_pack_start (GTK_BOX(box), date, TRUE, TRUE, 0);
1438 
1439  box = GTK_WIDGET(gtk_builder_get_object (builder,
1440  "pref/" GNC_PREFS_GROUP_ACCT_SUMMARY "/" GNC_PREF_END_DATE));
1441  date = gnc_date_edit_new (gnc_time (NULL), FALSE, FALSE);
1442  gtk_widget_show (date);
1443  gtk_box_pack_start (GTK_BOX(box), date, TRUE, TRUE, 0);
1444 
1445  box = GTK_WIDGET(gtk_builder_get_object (builder,
1446  "pref/" GNC_PREFS_GROUP_GENERAL "/" GNC_PREF_CURRENCY_OTHER));
1447  currency = gnc_currency_edit_new ();
1448  gnc_currency_edit_set_currency (GNC_CURRENCY_EDIT(currency), gnc_default_currency());
1449  gtk_widget_show (currency);
1450  gtk_box_pack_start (GTK_BOX(box), currency, TRUE, TRUE, 0);
1451 
1452  box = GTK_WIDGET(gtk_builder_get_object (builder,
1453  "pref/" GNC_PREFS_GROUP_GENERAL_REPORT "/" GNC_PREF_CURRENCY_OTHER));
1454  currency = gnc_currency_edit_new ();
1455  gnc_currency_edit_set_currency (GNC_CURRENCY_EDIT(currency), gnc_default_currency());
1456  gtk_widget_show (currency);
1457  gtk_box_pack_start (GTK_BOX(box), currency, TRUE, TRUE, 0);
1458 
1459  box = GTK_WIDGET(gtk_builder_get_object (builder,
1460  "pref/" GNC_PREFS_GROUP_GENERAL "/" GNC_DOC_LINK_PATH_HEAD));
1461  fcb = gtk_file_chooser_button_new (_("Select a folder"),
1462  GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
1463  gtk_box_pack_start (GTK_BOX(box), fcb, TRUE, TRUE, 0);
1464  button = gtk_button_new_with_label (_("Clear"));
1465  gtk_box_pack_start (GTK_BOX(box), button, TRUE, TRUE, 0);
1466  gtk_widget_show (button);
1467  g_signal_connect (GTK_BUTTON(button), "clicked",
1468  G_CALLBACK(file_chooser_clear_cb), fcb);
1469 
1470  image = GTK_WIDGET(gtk_builder_get_object (builder, "path_head_error"));
1471  g_object_set_data (G_OBJECT(fcb), "path_head_error", image);
1472 
1473  /* Add to the list of interesting widgets */
1474  gnc_prefs_build_widget_table (builder, dialog);
1475 
1476  g_slist_foreach (add_ins, gnc_preferences_build_page, dialog);
1477 
1478  /* Sort tabs alphabetically */
1479  gnc_prefs_sort_pages (GTK_NOTEBOOK(notebook));
1480  gtk_notebook_set_current_page (GTK_NOTEBOOK(notebook), 0);
1481 
1482  DEBUG("We have the following interesting widgets:");
1483  gnc_prefs_block_all (); // Block All Registered callbacks
1484  g_hash_table_foreach (prefs_table, (GHFunc)gnc_prefs_connect_one, dialog);
1485  gnc_prefs_unblock_all (); // UnBlock All Registered callbacks
1486  DEBUG("Done with interesting widgets.");
1487 
1488  /* Other stuff */
1489  gdate = g_date_new_dmy (31, G_DATE_JULY, 2013);
1490  g_date_strftime (buf, sizeof(buf), "%x", gdate);
1491  store = GTK_LIST_STORE(gtk_builder_get_object (builder, "date_formats"));
1492  path = gtk_tree_path_new_from_indices (QOF_DATE_FORMAT_LOCALE, -1);
1493  if (gtk_tree_model_get_iter (GTK_TREE_MODEL(store), &iter, path))
1494  gtk_list_store_set (store, &iter, 1, buf, -1);
1495  g_date_free (gdate);
1496  gtk_tree_path_free (path);
1497 
1498  locale_currency = gnc_locale_default_currency ();
1499  currency_name = gnc_commodity_get_printname (locale_currency);
1500  label = GTK_WIDGET(gtk_builder_get_object (builder, "locale_currency"));
1501  gtk_label_set_label (GTK_LABEL(label), currency_name);
1502  label = GTK_WIDGET(gtk_builder_get_object (builder, "locale_currency2"));
1503  gtk_label_set_label (GTK_LABEL(label), currency_name);
1504 
1505  button = GTK_WIDGET(gtk_builder_get_object (builder, "pref/general/save-on-close-expires"));
1506  gnc_save_on_close_expires_cb (GTK_TOGGLE_BUTTON(button), dialog);
1507 
1508  g_object_unref (G_OBJECT(builder));
1509 
1510  /* save the original account separator in case it changes */
1511  g_object_set_data_full (G_OBJECT(entry), "original_text",
1512  g_strdup (gtk_entry_get_text (GTK_ENTRY(entry))),
1513  g_free);
1514 
1515  LEAVE("dialog %p", dialog);
1516  return dialog;
1517 }
1518 
1519 
1520 /*************************************/
1521 /* Common callback code */
1522 /*************************************/
1523 
1524 
1525 
1540 static gboolean
1541 show_handler (const char *class_name, gint component_id,
1542  gpointer user_data, gpointer iter_data)
1543 {
1544  GtkWidget *dialog;
1545 
1546  ENTER(" ");
1547  dialog = GTK_WIDGET(user_data);
1548  gtk_window_present (GTK_WINDOW(dialog));
1549  LEAVE(" ");
1550  return(TRUE);
1551 }
1552 
1553 
1560 static void
1561 close_handler (gpointer user_data)
1562 {
1563  GtkWidget *dialog;
1564 
1565  ENTER(" ");
1566  dialog = GTK_WIDGET(user_data);
1567  gnc_unregister_gui_component_by_data (DIALOG_PREFERENCES_CM_CLASS, dialog);
1568  gtk_widget_destroy (dialog);
1569  LEAVE(" ");
1570 }
1571 
1572 
1573 /* This function creates the preferences dialog and presents it to
1574  * the user. The preferences dialog is a singleton, so if a
1575  * preferences dialog already exists it will be raised to the top of
1576  * the window stack instead of creating a new dialog. */
1577 void
1578 gnc_preferences_dialog (GtkWindow *parent)
1579 {
1580  GtkWidget *dialog;
1581 
1582  ENTER("");
1583  if (gnc_forall_gui_components (DIALOG_PREFERENCES_CM_CLASS,
1584  show_handler, NULL))
1585  {
1586  LEAVE("existing window");
1587  return;
1588  }
1589 
1590  dialog = gnc_preferences_dialog_create(parent);
1591 
1592  gnc_restore_window_size (GNC_PREFS_GROUP, GTK_WINDOW(dialog), parent);
1593  gtk_widget_show (dialog);
1594 
1595  gnc_register_gui_component (DIALOG_PREFERENCES_CM_CLASS,
1596  NULL, close_handler, dialog);
1597 
1598  LEAVE(" ");
1599 }
1600 
void gnc_preferences_dialog(GtkWindow *parent)
This function creates the preferences dialog and presents it to the user.
void gnc_save_on_close_expires_cb(GtkToggleButton *button, GtkWidget *dialog)
Called when the save-on-close checkbutton is toggled.
void gnc_preferences_add_page(const gchar *filename, const gchar *widgetname, const gchar *tabname)
This function adds a full page of preferences to the preferences dialog.
void qof_instance_get(const QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_get.
gchar * gnc_prefs_get_string(const gchar *group, const gchar *pref_name)
Get a string value from the preferences backend.
void gnc_currency_edit_set_currency(GNCCurrencyEdit *gce, const gnc_commodity *currency)
Set the widget to display a certain currency name.
GtkGrid * grid_from
The grid being copied from.
utility functions for the GnuCash UI
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
void gnc_preferences_add_to_page(const gchar *filename, const gchar *widgetname, const gchar *tabname)
This function adds a partial page of preferences to the preferences dialog.
GList * gnc_account_list_name_violations(QofBook *book, const gchar *separator)
Runs through all the accounts and returns a list of account names that contain the provided separator...
Definition: Account.cpp:273
gboolean full_page
TRUE if this addition represents a full page in the preferences dialog.
GSList * add_ins
A list of all additions that have been made to the preferences dialog.
gboolean gnc_prefs_set_string(const gchar *group, const gchar *pref_name, const gchar *value)
Store a string into the preferences backend.
Definition: gnc-prefs.c:320
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
gnc_commodity * gnc_default_currency(void)
Return the default currency set by the user.
Currency selection widget.
GtkGrid * grid_to
The grid being copied to.
Account handling public routines.
Gobject helper routines.
gchar * gnc_account_name_violations_errmsg(const gchar *separator, GList *invalid_account_names)
Composes a translatable error message showing which account names clash with the current account sepa...
Definition: Account.cpp:235
This data structure is used while building the preferences dialog to copy a grid from a glade file to...
gint cols
The number of columns and rows in the grid.
void gnc_gnome_help(GtkWindow *parent, const char *file_name, const char *anchor)
Launch the systems default help browser, gnome&#39;s yelp for linux, and open to a given link within a gi...
gchar * tabname
The name of the tab within the preferences dialog where these widgets should be placed.
void gnc_period_select_set_fy_end(GncPeriodSelect *period, const GDate *fy_end)
Set the fiscal year end on a GncPeriodSelect widget.
Dialog for handling user preferences.
void gnc_prefs_bind(const gchar *group, const gchar *pref_name, const gchar *pref_value, gpointer object, const gchar *property)
Bind a setting to a g_object property.
Definition: gnc-prefs.c:181
All type declarations for the whole Gnucash engine.
gchar * widgetname
The name of the widget within the glade data file that should be added to the preferences dialog...
Generic api to store and retrieve preferences.
void gnc_preferences_response_cb(GtkDialog *dialog, gint response, GtkDialog *unused)
Handle a user click on one of the buttons at the bottom of the preference dialog. ...
const char * gnc_commodity_get_printname(const gnc_commodity *cm)
Retrieve the &#39;print&#39; name for the specified commodity.
gchar * filename
The relative name of the file where the glade data for this addition can be found.
GtkWidget * gnc_currency_edit_new(void)
Create a new GNCCurrencyEdit widget which can be used to provide an easy way to enter ISO currency co...
This data structure holds the information for a single addition to the preferences dialog...
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
time64 gnc_time(time64 *tbuf)
get the current time
Definition: gnc-date.cpp:261
GtkWidget * gnc_period_select_new(gboolean starting_labels)
Create a new GncPeriodSelect widget which is used to select a accounting period like "previous month"...
void gnc_prefs_block_all(void)
Block all preference callbacks.
Definition: gnc-prefs.c:380
Take from locale information.
Definition: gnc-date.h:128
void gnc_prefs_unblock_all(void)
Unblock all preferences callbacks.
Definition: gnc-prefs.c:386
A custom widget for selecting accounting periods.
gnc_commodity * gnc_locale_default_currency(void)
Returns the default currency of the current locale.
void gnc_account_separator_pref_changed_cb(GtkEntry *entry, GtkWidget *dialog)
This function is called whenever the account separator is changed in the preferences dialog...