GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 [email protected] *
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-component-manager.h"
79 #include "dialog-preferences.h"
80 
81 #define DIALOG_PREFERENCES_CM_CLASS "dialog-newpreferences"
82 #define GNC_PREFS_GROUP "dialogs.preferences"
83 #define PREF_PREFIX_LEN sizeof("pref/") - 1
84 #define PREFS_WIDGET_HASH "prefs_widget_hash"
85 #define NOTEBOOK "notebook"
86 
88 static QofLogModule log_module = GNC_MOD_PREFS;
89 
90 void gnc_preferences_response_cb(GtkDialog *dialog, gint response, GtkDialog *unused);
91 void gnc_account_separator_pref_changed_cb (GtkEntry *entry, GtkWidget *dialog);
92 gboolean gnc_account_separator_validate_cb (GtkEntry *entry, GdkEvent *event, GtkWidget *dialog);
93 
96 typedef struct addition_t
97 {
100  gchar *filename;
104  gchar *widgetname;
107  gchar *tabname;
110  gboolean full_page;
111 } addition;
112 
116 GSList *add_ins = NULL;
117 
118 static gchar *gnc_account_separator_is_valid (const gchar *separator,
119  gchar **normalized_separator)
120 {
121  QofBook *book = gnc_get_current_book();
122  GList *conflict_accts = NULL;
123  gchar *message = NULL;
124 
125  *normalized_separator = gnc_normalize_account_separator (separator);
126  conflict_accts = gnc_account_list_name_violations (book, *normalized_separator);
127  if (conflict_accts)
128  message = gnc_account_name_violations_errmsg (*normalized_separator,
129  conflict_accts);
130 
131  g_list_free (conflict_accts);
132 
133  return message;
134 }
135 
146 void
147 gnc_account_separator_pref_changed_cb (GtkEntry *entry, GtkWidget *dialog)
148 {
149  GtkWidget *label, *image;
150  gchar *sample;
151  gchar *separator;
152 
153  gchar *conflict_msg = gnc_account_separator_is_valid (gtk_entry_get_text (entry), &separator);
154 
155  label = g_object_get_data(G_OBJECT(dialog), "sample_account");
156  DEBUG("Sample Account pointer is %p", label );
157  /* Translators: Both %s will be the account separator character; the
158  resulting string is a demonstration how the account separator
159  character will look like. You can replace these three account
160  names with other account names that are more suitable for your
161  language - just keep in mind to have exactly two %s in your
162  translation. */
163  sample = g_strdup_printf(_("Income%sSalary%sTaxable"),
164  separator, separator);
165  PINFO(" Label set to '%s'", sample);
166  gtk_label_set_text(GTK_LABEL(label), sample);
167  g_free(sample);
168 
169  /* Check if the new separator clashes with existing account names */
170  image = g_object_get_data(G_OBJECT(dialog), "separator_error");
171  DEBUG("Separator Error Image pointer is %p", image );
172 
173  if (conflict_msg)
174  {
175  gtk_widget_set_tooltip_text(GTK_WIDGET(image), conflict_msg);
176  gtk_widget_show (GTK_WIDGET(image));
177  g_free ( conflict_msg );
178  }
179  else
180  gtk_widget_hide (GTK_WIDGET(image));
181 
182  g_free (separator);
183 }
184 
185 
186 gboolean
187 gnc_account_separator_validate_cb (GtkEntry *entry, GdkEvent *event, GtkWidget *dialog)
188 {
189  gchar *separator;
190  gchar *conflict_msg = gnc_account_separator_is_valid (gtk_entry_get_text (entry), &separator);
191 
192  /* Check if the new separator clashes with existing account names */
193 
194  if (conflict_msg)
195  {
196  gnc_warning_dialog(dialog, "%s", conflict_msg);
197  g_free ( conflict_msg );
198  }
199  g_free (separator);
200  return FALSE;
201 }
202 
203 
215 static gint
216 gnc_prefs_compare_addins (addition *a,
217  addition *b)
218 {
219  return g_utf8_collate(a->tabname, b->tabname);
220 }
221 
222 
242 static void
243 gnc_preferences_add_page_internal (const gchar *filename,
244  const gchar *widgetname,
245  const gchar *tabname,
246  gboolean full_page)
247 {
248  addition *add_in, *preexisting;
249  gboolean error = FALSE;
250  GSList *ptr;
251 
252  ENTER("file %s, widget %s, tab %s full page %d",
253  filename, widgetname, tabname, full_page);
254 
255  add_in = g_malloc(sizeof(addition));
256  if (add_in == NULL)
257  {
258  g_critical("Unable to allocate memory.\n");
259  LEAVE("no memory");
260  return;
261  }
262 
263  add_in->filename = g_strdup(filename);
264  add_in->widgetname = g_strdup(widgetname);
265  add_in->tabname = g_strdup(tabname);
266  add_in->full_page = full_page;
267  if (!add_in->filename || !add_in->widgetname || !add_in->tabname)
268  {
269  g_critical("Unable to allocate memory.\n");
270  g_free(add_in->filename);
271  g_free(add_in->widgetname);
272  g_free(add_in->tabname);
273  g_free(add_in);
274  LEAVE("no memory");
275  return;
276  }
277 
278  ptr = g_slist_find_custom(add_ins, add_in, (GCompareFunc)gnc_prefs_compare_addins);
279  if (ptr)
280  {
281  /* problem? */
282  preexisting = ptr->data;
283 
284  if (preexisting->full_page)
285  {
286  g_warning("New tab %s(%s/%s/%s) conflicts with existing tab %s(%s/%s/full)",
287  add_in->tabname, add_in->filename, add_in->widgetname,
288  add_in->full_page ? "full" : "partial",
289  preexisting->tabname, preexisting->filename, preexisting->widgetname);
290  error = TRUE;
291  }
292  else if (add_in->full_page)
293  {
294  g_warning("New tab %s(%s/%s/%s) conflicts with existing tab %s(%s/%s/partial)",
295  add_in->tabname, add_in->filename, add_in->widgetname,
296  add_in->full_page ? "full" : "partial",
297  preexisting->tabname, preexisting->filename, preexisting->widgetname);
298  error = TRUE;
299  }
300  }
301 
302  if (error)
303  {
304  g_free(add_in->filename);
305  g_free(add_in->widgetname);
306  g_free(add_in->tabname);
307  g_free(add_in);
308  LEAVE("err");
309  return;
310  }
311  else
312  {
313  add_ins = g_slist_append(add_ins, add_in);
314  }
315  LEAVE("");
316 }
317 
318 
319 /* This function adds a full page of preferences to the preferences
320  * dialog. When the dialog is created, the specified content will be
321  * pulled from the specified glade file and added to the preferences
322  * dialog with the specified tab name. The tab name may not be
323  * duplicated. For example, the Business code might have a full page
324  * of its own preferences. */
325 void
326 gnc_preferences_add_page (const gchar *filename,
327  const gchar *widgetname,
328  const gchar *tabname)
329 {
330  gnc_preferences_add_page_internal(filename, widgetname, tabname, TRUE);
331 }
332 
333 
334 /* This function adds a partial page of preferences to the
335  * preferences dialog. When the dialog is created, the specified
336  * content will be pulled from the glade file and added to the
337  * preferences dialog with the specified tab name. The tab name
338  * may be duplicated. For example, the HBCI preferences may share a
339  * "Data Import" page with QIF and other methods. */
340 void
341 gnc_preferences_add_to_page (const gchar *filename,
342  const gchar *widgetname,
343  const gchar *tabname)
344 {
345  gnc_preferences_add_page_internal(filename, widgetname, tabname, FALSE);
346 }
347 
348 
349 /*******************************************************************/
350 
364 static void
365 gnc_prefs_build_widget_table (GtkBuilder *builder,
366  GtkWidget *dialog)
367 {
368  GHashTable *prefs_table;
369  GSList *interesting, *runner;
370  const gchar *name;
371  const gchar *wname;
372  GtkWidget *widget;
373 
374  prefs_table = g_object_get_data(G_OBJECT(dialog), PREFS_WIDGET_HASH);
375 
376  interesting = gtk_builder_get_objects(builder);
377 
378  for (runner = interesting; runner; runner = g_slist_next(runner))
379  {
380  widget = runner->data;
381  if (GTK_IS_WIDGET(widget))
382  {
383  wname = gtk_widget_get_name(widget);
384  name = gtk_buildable_get_name(GTK_BUILDABLE(widget));
385  DEBUG("Widget type is %s and buildable get name is %s", wname, name);
386  if (g_str_has_prefix (name, "pref"))
387  g_hash_table_insert(prefs_table, (gchar *)name, widget);
388  }
389  }
390  g_slist_free(interesting);
391 
392 }
393 
394 
400 struct copy_data
401 {
403  GtkTable *table_from;
405  GtkTable *table_to;
409 };
410 
411 
412 static GtkWidget *
413 gnc_prefs_find_page (GtkNotebook *notebook, const gchar *name)
414 {
415  int n_pages, i;
416  GtkWidget *child;
417  const gchar *child_name;
418 
419  g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
420  g_return_val_if_fail (name, NULL);
421 
422  ENTER("");
423 
424  n_pages = gtk_notebook_get_n_pages (notebook);
425 
426  for (i = 0; i < n_pages; i++)
427  {
428  child = gtk_notebook_get_nth_page (notebook, i);
429  g_return_val_if_fail (child, NULL);
430 
431  child_name = gtk_notebook_get_tab_label_text (notebook, child);
432  g_return_val_if_fail (child_name, NULL);
433 
434  if (g_utf8_collate (name, child_name) == 0)
435  {
436  LEAVE("found at index: %d", i);
437  return child;
438  }
439  }
440 
441  LEAVE("not found");
442  return NULL;
443 }
444 
445 
458 static void
459 gnc_prefs_move_table_entry (GtkWidget *child,
460  gpointer data)
461 {
462  struct copy_data *copydata = data;
463  GtkAttachOptions x_opts, y_opts;
464  gint bottom, top, left, right, x_pad, y_pad;
465 
466  ENTER("child %p, copy data %p", child, data);
467  gtk_container_child_get(GTK_CONTAINER(copydata->table_from), child,
468  "bottom-attach", &bottom,
469  "left-attach", &left,
470  "right-attach", &right,
471  "top-attach", &top,
472  "x-options", &x_opts,
473  "x-padding", &x_pad,
474  "y-options", &y_opts,
475  "y-padding", &y_pad,
476  NULL);
477 
478  g_object_ref(child);
479  gtk_container_remove(GTK_CONTAINER(copydata->table_from), child);
480  gtk_table_attach(copydata->table_to, child, left, right,
481  top + copydata->row_offset, bottom + copydata->row_offset,
482  x_opts, y_opts, x_pad, y_pad);
483  g_object_unref(child);
484  LEAVE(" ");
485 }
486 
487 
499 static void
500 gnc_preferences_build_page (gpointer data,
501  gpointer user_data)
502 {
503  GtkBuilder *builder;
504  GtkWidget *dialog, *existing_content, *new_content, *label;
505  GtkNotebook *notebook;
506  addition *add_in;
507  struct copy_data copydata;
508  gint rows, cols;
509  gchar **widgetname;
510  gint i;
511 
512  ENTER("add_in %p, dialog %p", data, user_data);
513  add_in = (addition *)data;
514  dialog = user_data;
515 
516  DEBUG("Opening %s to get %s", add_in->filename, add_in->widgetname);
517  builder = gtk_builder_new();
518 
519  /* Adjustments etc... must come before dialog information */
520  widgetname = g_strsplit(add_in->widgetname, ",", -1);
521 
522  for (i = 0; widgetname[i]; i++)
523  {
524  DEBUG("Opening %s to get content %s", add_in->filename, widgetname[i]);
525  gnc_builder_add_from_file (builder, add_in->filename, widgetname[i]);
526  }
527 
528  DEBUG("Widget Content is %s", widgetname[i - 1]);
529  new_content = GTK_WIDGET(gtk_builder_get_object (builder, widgetname[i - 1]));
530 
531  g_strfreev(widgetname);
532  DEBUG("done");
533 
534  /* Add to the list of interesting widgets */
535  gnc_prefs_build_widget_table(builder, dialog);
536 
537  /* Connect the signals in this glade file. The dialog is passed in
538  * so the the callback can find "interesting" widgets from other
539  * glade files if necessary (via the GPREFS_WIDGET_HASH hash table). */
540  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, dialog);
541 
542  /* Prepare for recursion */
543  notebook = g_object_get_data(G_OBJECT(dialog), NOTEBOOK);
544 
545  if (add_in->full_page)
546  {
547  label = gtk_label_new(add_in->tabname);
548  gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
549  gtk_notebook_append_page(notebook, new_content, label);
550  g_object_unref(G_OBJECT(builder));
551  LEAVE("appended page");
552  return;
553  }
554 
555  /* Copied tables must match the size of the main table */
556  if (!GTK_IS_TABLE(new_content))
557  {
558  g_critical("The object name %s in file %s is not a GtkTable. It cannot "
559  "be added to the preferences dialog.",
560  add_in->widgetname, add_in->filename);
561  g_object_unref(G_OBJECT(builder));
562  LEAVE("");
563  return;
564  }
565  g_object_get(G_OBJECT(new_content), "n-columns", &cols, NULL);
566  if (cols != 4)
567  {
568  g_critical("The table %s in file %s does not have four columns. It cannot "
569  "be added to the preferences dialog.",
570  add_in->widgetname, add_in->filename);
571  g_object_unref(G_OBJECT(builder));
572  LEAVE("");
573  return;
574  }
575 
576  /* Does the page exist or must we create it */
577  existing_content = gnc_prefs_find_page(notebook, add_in->tabname);
578 
579  if (!existing_content)
580  {
581  /* No existing content with this name. Create a blank page */
582  rows = 0;
583  existing_content = gtk_table_new(0, 4, FALSE);
584  gtk_container_set_border_width(GTK_CONTAINER(existing_content), 6);
585  label = gtk_label_new(add_in->tabname);
586  gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
587  gtk_notebook_append_page(notebook, existing_content, label);
588  gtk_widget_show_all(existing_content);
589  DEBUG("created new page %s, appended it", add_in->tabname);
590  }
591  else
592  {
593  g_object_get(G_OBJECT(existing_content), "n-rows", &rows, NULL);
594  DEBUG("found existing page %s", add_in->tabname);
595  }
596 
597  /* Maybe add a spacer row */
598  DEBUG("rows is %d", rows);
599  if (rows > 0)
600  {
601  label = gtk_label_new("");
602  gtk_widget_show(label);
603  gtk_table_attach(GTK_TABLE(existing_content), label, 0, 1, rows, rows + 1,
604  GTK_FILL, GTK_FILL, 0, 0);
605  rows++;
606  }
607 
608  /* Now copy all the entries in the table */
609  copydata.table_from = GTK_TABLE(new_content);
610  copydata.table_to = GTK_TABLE(existing_content);
611  copydata.row_offset = rows;
612  gtk_container_foreach(GTK_CONTAINER(new_content), gnc_prefs_move_table_entry,
613  &copydata);
614 
615  g_object_ref_sink(new_content);
616  g_object_unref(G_OBJECT(builder));
617 
618  LEAVE("added content to page");
619 }
620 
621 
622 static gint
623 tab_cmp (GtkWidget *page_a, GtkWidget *page_b, GtkNotebook *notebook)
624 {
625  return g_utf8_collate (gtk_notebook_get_tab_label_text (notebook, page_a),
626  gtk_notebook_get_tab_label_text (notebook, page_b));
627 }
628 
629 
630 static void
631 gnc_prefs_sort_pages (GtkNotebook *notebook)
632 {
633  gint n_pages, i;
634  GList *tabs = NULL, *iter = NULL;
635 
636  g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
637 
638  /* gather tabs */
639  n_pages = gtk_notebook_get_n_pages (notebook);
640  for (i = n_pages - 1; i >= 0; i--)
641  tabs = g_list_prepend (tabs, gtk_notebook_get_nth_page (notebook, i));
642 
643  /* sort in local copy */
644  tabs = g_list_sort_with_data (tabs, (GCompareDataFunc) tab_cmp, notebook);
645 
646  /* reorder tabs */
647  for (i = 0, iter = tabs; iter; i++, iter = iter->next)
648  gtk_notebook_reorder_child (notebook, GTK_WIDGET (iter->data), i);
649 
650  g_list_free (tabs);
651 }
652 
653 
654 /*******************************/
655 /* Dynamically added Callbacks */
656 /*******************************/
657 
658 static void
659 gnc_prefs_split_widget_name (const gchar *name, gchar **group, gchar **pref)
660 {
661  const gchar *group_with_pref = name + PREF_PREFIX_LEN;
662  gchar **splits = g_strsplit (group_with_pref, "/", 0);
663 
664  *group = g_strdup (splits[0]);
665  *pref = g_strdup (splits[1]);
666  g_strfreev (splits);
667 }
668 
669 /****************************************************************************/
670 
677 static void
678 gnc_prefs_connect_font_button (GtkFontButton *fb)
679 {
680  gchar *group, *pref;
681  gchar *font;
682 
683  g_return_if_fail(GTK_IS_FONT_BUTTON(fb));
684 
685  gnc_prefs_split_widget_name (gtk_buildable_get_name(GTK_BUILDABLE(fb)), &group, &pref);
686  gnc_prefs_bind (group, pref, G_OBJECT (fb), "font-name");
687 
688  g_free (group);
689  g_free (pref);
690 
691  gtk_widget_show_all(GTK_WIDGET(fb));
692 }
693 
694 /****************************************************************************/
695 
703 static void
704 gnc_prefs_connect_radio_button (GtkRadioButton *button)
705 {
706  gchar *group, *pref;
707  gboolean active;
708 
709  g_return_if_fail(GTK_IS_RADIO_BUTTON(button));
710 
711  gnc_prefs_split_widget_name (gtk_buildable_get_name(GTK_BUILDABLE(button)), &group, &pref);
712 
713 // active = gnc_prefs_get_bool (group, pref);
714 // DEBUG(" Checkbox %s/%s initially %sactive", group, pref, active ? "" : "in");
715 // gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), active);
716 
717  gnc_prefs_bind (group, pref, G_OBJECT (button), "active");
718 
719  g_free(group);
720  g_free(pref);
721 }
722 
723 /****************************************************************************/
724 
732 static void
733 gnc_prefs_connect_check_button (GtkCheckButton *button)
734 {
735  gchar *group, *pref;
736  gboolean active;
737 
738  g_return_if_fail(GTK_IS_CHECK_BUTTON(button));
739 
740  gnc_prefs_split_widget_name (gtk_buildable_get_name(GTK_BUILDABLE(button)), &group, &pref);
741 
742 // active = gnc_prefs_get_bool (group, pref);
743 // DEBUG(" Checkbox %s/%s initially %sactive", group, pref, active ? "" : "in");
744 // gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), active);
745 
746  gnc_prefs_bind (group, pref, G_OBJECT (button), "active");
747 
748  g_free (group);
749  g_free (pref);
750 }
751 
752 /****************************************************************************/
753 
761 static void
762 gnc_prefs_connect_spin_button (GtkSpinButton *spin)
763 {
764  gchar *group, *pref;
765  gdouble value;
766 
767  g_return_if_fail(GTK_IS_SPIN_BUTTON(spin));
768 
769  gnc_prefs_split_widget_name (gtk_buildable_get_name(GTK_BUILDABLE(spin)), &group, &pref);
770 
771 // value = gnc_prefs_get_float (group, pref);
772 // gtk_spin_button_set_value(spin, value);
773 // DEBUG(" Spin button %s/%s has initial value %f", group, pref, value);
774 
775  gnc_prefs_bind (group, pref, G_OBJECT (spin), "value");
776 
777  g_free (group);
778  g_free (pref);
779 }
780 
781 /****************************************************************************/
782 
789 static void
790 gnc_prefs_connect_combo_box (GtkComboBox *box)
791 {
792  gchar *group, *pref;
793  gint active;
794 
795  g_return_if_fail(GTK_IS_COMBO_BOX(box));
796 
797  gnc_prefs_split_widget_name (gtk_buildable_get_name(GTK_BUILDABLE(box)), &group, &pref);
798 
799 // active = gnc_prefs_get_int(group, pref);
800 // gtk_combo_box_set_active(GTK_COMBO_BOX(box), active);
801 // DEBUG(" Combo box %s/%s set to item %d", group, pref, active);
802 
803  gnc_prefs_bind (group, pref, G_OBJECT (box), "active");
804 
805  g_free (group);
806  g_free (pref);
807 }
808 
809 /****************************************************************************/
810 
817 static void
818 gnc_prefs_connect_currency_edit (GNCCurrencyEdit *gce, const gchar *boxname )
819 {
820  gnc_commodity *currency;
821  gchar *group, *pref;
822  gchar *mnemonic;
823 
824  g_return_if_fail(GNC_IS_CURRENCY_EDIT(gce));
825 
826  gnc_prefs_split_widget_name (boxname, &group, &pref);
827 
828  gnc_prefs_bind (group, pref, G_OBJECT (gce), "mnemonic");
829 
830  g_free (group);
831  g_free (pref);
832 
833  gtk_widget_show_all(GTK_WIDGET(gce));
834 }
835 
836 /****************************************************************************/
837 
844 static void
845 gnc_prefs_connect_entry (GtkEntry *entry)
846 {
847  gchar *group, *pref;
848  gchar *text;
849 
850  g_return_if_fail(GTK_IS_ENTRY(entry));
851 
852  gnc_prefs_split_widget_name (gtk_buildable_get_name(GTK_BUILDABLE(entry)), &group, &pref);
853 
854 // text = gnc_prefs_get_string(group, pref);
855 // gtk_entry_set_text(GTK_ENTRY(entry), text ? text : "");
856 // DEBUG(" Entry %s/%s set to '%s'", group, pref, text ? text : "(null)");
857 // g_free(text);
858 
859  gnc_prefs_bind (group, pref, G_OBJECT (entry), "text");
860 
861  g_free (group);
862  g_free (pref);
863 }
864 
865 /****************************************************************************/
866 
873 static void
874 gnc_prefs_connect_period_select (GncPeriodSelect *period, const gchar *boxname )
875 {
876  gchar *group, *pref;
877  gchar *mnemonic;
878 
879  g_return_if_fail(GNC_IS_PERIOD_SELECT(period));
880 
881  gnc_prefs_split_widget_name (boxname, &group, &pref);
882 
883  gnc_prefs_bind (group, pref, G_OBJECT (period), "active");
884 
885  g_free (group);
886  g_free (pref);
887 }
888 
889 /****************************************************************************/
890 
897 static void
898 gnc_prefs_connect_date_edit (GNCDateEdit *gde , const gchar *boxname )
899 {
900  gchar *group, *pref;
901  gchar *mnemonic;
902 
903  g_return_if_fail(GNC_IS_DATE_EDIT(gde));
904 
905  gnc_prefs_split_widget_name (boxname, &group, &pref);
906 
907  gnc_prefs_bind (group, pref, G_OBJECT (gde), "time");
908 
909  g_free (group);
910  g_free (pref);
911 }
912 
913 
914 /****************************************************************************/
915 
916 /********************/
917 /* Callbacks */
918 /********************/
919 
933 void
934 gnc_preferences_response_cb(GtkDialog *dialog, gint response, GtkDialog *unused)
935 {
936  switch (response)
937  {
938  case GTK_RESPONSE_HELP:
939  gnc_gnome_help(HF_HELP, HL_GLOBPREFS);
940  break;
941 
942  default:
943  gnc_save_window_size(GNC_PREFS_GROUP, GTK_WINDOW(dialog));
944  gnc_unregister_gui_component_by_data(DIALOG_PREFERENCES_CM_CLASS,
945  dialog);
946  gtk_widget_destroy(GTK_WIDGET(dialog));
947  break;
948  }
949 }
950 
951 
952 /********************/
953 /* Creation */
954 /********************/
955 
967 static void
968 gnc_prefs_connect_one (const gchar *name,
969  GtkWidget *widget,
970  gpointer user_data)
971 {
972  /* These tests must be ordered from more specific widget to less
973  * specific widget. */
974 
975  if (GTK_IS_FONT_BUTTON(widget))
976  {
977  DEBUG(" %s - entry", name);
978  gnc_prefs_connect_font_button(GTK_FONT_BUTTON(widget));
979  }
980  else if (GTK_IS_RADIO_BUTTON(widget))
981  {
982  DEBUG(" %s - radio button", name);
983  gnc_prefs_connect_radio_button(GTK_RADIO_BUTTON(widget));
984  }
985  else if (GTK_IS_CHECK_BUTTON(widget))
986  {
987  DEBUG(" %s - check button", name);
988  gnc_prefs_connect_check_button(GTK_CHECK_BUTTON(widget));
989  }
990  else if (GTK_IS_SPIN_BUTTON(widget))
991  {
992  DEBUG(" %s - spin button", name);
993  gnc_prefs_connect_spin_button(GTK_SPIN_BUTTON(widget));
994  }
995  else if (GTK_IS_COMBO_BOX(widget))
996  {
997  DEBUG(" %s - combo box", name);
998  gnc_prefs_connect_combo_box(GTK_COMBO_BOX(widget));
999  }
1000  else if (GTK_IS_ENTRY(widget))
1001  {
1002  DEBUG(" %s - entry", name);
1003  gnc_prefs_connect_entry(GTK_ENTRY(widget));
1004  }
1005  else if (GTK_IS_HBOX(widget))
1006  {
1007  /* Test custom widgets are all children of a hbox */
1008  GtkWidget *widget_child;
1009  GList* child = gtk_container_get_children(GTK_CONTAINER(widget));
1010  widget_child = child->data;
1011  g_list_free(child);
1012  DEBUG(" %s - hbox", name);
1013  DEBUG("Hbox widget type is %s and name is %s", gtk_widget_get_name(GTK_WIDGET(widget_child)), name);
1014 
1015  if (GNC_IS_CURRENCY_EDIT(widget_child))
1016  {
1017  DEBUG(" %s - currency_edit", name);
1018  gnc_prefs_connect_currency_edit(GNC_CURRENCY_EDIT(widget_child), name );
1019  }
1020  else if (GNC_IS_PERIOD_SELECT(widget_child))
1021  {
1022  DEBUG(" %s - period_Select", name);
1023  gnc_prefs_connect_period_select(GNC_PERIOD_SELECT(widget_child), name );
1024  }
1025  else if (GNC_IS_DATE_EDIT(widget_child))
1026  {
1027  DEBUG(" %s - date_edit", name);
1028  gnc_prefs_connect_date_edit(GNC_DATE_EDIT(widget_child), name );
1029  }
1030  }
1031  else
1032  {
1033  DEBUG(" %s - unsupported %s", name,
1034  G_OBJECT_TYPE_NAME(G_OBJECT(widget)));
1035  }
1036 }
1037 
1038 
1050 static GtkWidget *
1051 gnc_preferences_dialog_create(void)
1052 {
1053  GtkBuilder *builder;
1054  GtkWidget *dialog, *notebook, *label, *image;
1055  GtkWidget *box, *date, *period, *currency;
1056  GHashTable *prefs_table;
1057  GDate* gdate = NULL;
1058  gchar buf[128];
1059  GtkListStore *store;
1060  GtkTreePath *path;
1061  GtkTreeIter iter;
1062  gnc_commodity *locale_currency;
1063  const gchar *currency_name;
1064  QofBook *book;
1065  KvpFrame *book_frame;
1066  gint64 month, day;
1067  GDate fy_end;
1068  gboolean date_is_valid = FALSE;
1069 
1070  ENTER("");
1071  DEBUG("Opening dialog-preferences.glade:");
1072  builder = gtk_builder_new();
1073 
1074  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "auto_decimal_places_adj");
1075  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "autosave_interval_minutes_adj");
1076  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "save_on_close_adj");
1077  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "date_backmonth_adj");
1078  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "max_transactions_adj");
1079  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "key_length_adj");
1080  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "new_search_limit_adj");
1081  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "retain_days_adj");
1082  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "tab_width_adj");
1083  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "date_formats");
1084  gnc_builder_add_from_file (builder, "dialog-preferences.glade", "GnuCash Preferences");
1085 
1086  dialog = GTK_WIDGET(gtk_builder_get_object (builder, "GnuCash Preferences"));
1087 
1088 #ifndef REGISTER2_ENABLED
1089  /* Hide preferences that are related to register2 */
1090  box = GTK_WIDGET (gtk_builder_get_object (builder, "label14"));
1091  gtk_widget_hide (box);
1092  box = GTK_WIDGET (gtk_builder_get_object (builder, "pref/general.register/key-length"));
1093  gtk_widget_hide (box);
1094  box = GTK_WIDGET (gtk_builder_get_object (builder, "pref/general.register/show-extra-dates"));
1095  gtk_widget_hide (box);
1096  box = GTK_WIDGET (gtk_builder_get_object (builder, "pref/general.register/show-calendar-buttons"));
1097  gtk_widget_hide (box);
1098  box = GTK_WIDGET (gtk_builder_get_object (builder, "pref/general.register/selection-to-blank-on-expand"));
1099  gtk_widget_hide (box);
1100  box = GTK_WIDGET (gtk_builder_get_object (builder, "pref/general.register/show-extra-dates-on-selection"));
1101  gtk_widget_hide (box);
1102 #endif
1103 
1104  label = GTK_WIDGET(gtk_builder_get_object (builder, "sample_account"));
1105  g_object_set_data(G_OBJECT(dialog), "sample_account", label);
1106 
1107  image = GTK_WIDGET(gtk_builder_get_object (builder, "separator_error"));
1108  g_object_set_data(G_OBJECT(dialog), "separator_error", image);
1109 
1110  DEBUG("autoconnect");
1111  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, dialog);
1112 
1113  DEBUG("done");
1114 
1115  notebook = GTK_WIDGET(gtk_builder_get_object (builder, "notebook1"));
1116  prefs_table = g_hash_table_new(g_str_hash, g_str_equal);
1117  g_object_set_data(G_OBJECT(dialog), NOTEBOOK, notebook);
1118  g_object_set_data_full(G_OBJECT(dialog), PREFS_WIDGET_HASH,
1119  prefs_table, (GDestroyNotify)g_hash_table_destroy);
1120 
1121 
1122  book = gnc_get_current_book();
1123  g_date_clear (&fy_end, 1);
1124  qof_instance_get (QOF_INSTANCE (book),
1125  "fy-end", &fy_end,
1126  NULL);
1127  box = GTK_WIDGET(gtk_builder_get_object (builder,
1128  "pref/" GNC_PREFS_GROUP_ACCT_SUMMARY "/" GNC_PREF_START_PERIOD));
1129  period = gnc_period_select_new(TRUE);
1130  gtk_widget_show (period);
1131  gtk_box_pack_start (GTK_BOX (box), period, TRUE, TRUE, 0);
1132  if (date_is_valid)
1133  gnc_period_select_set_fy_end(GNC_PERIOD_SELECT (period), &fy_end);
1134 
1135  box = GTK_WIDGET(gtk_builder_get_object (builder,
1136  "pref/" GNC_PREFS_GROUP_ACCT_SUMMARY "/" GNC_PREF_END_PERIOD));
1137  period = gnc_period_select_new(FALSE);
1138  gtk_widget_show (period);
1139  gtk_box_pack_start (GTK_BOX (box), period, TRUE, TRUE, 0);
1140  if (date_is_valid)
1141  gnc_period_select_set_fy_end(GNC_PERIOD_SELECT (period), &fy_end);
1142 
1143  box = GTK_WIDGET(gtk_builder_get_object (builder,
1144  "pref/" GNC_PREFS_GROUP_ACCT_SUMMARY "/" GNC_PREF_START_DATE));
1145  date = gnc_date_edit_new(gnc_time (NULL), FALSE, FALSE);
1146  gtk_widget_show (date);
1147  gtk_box_pack_start (GTK_BOX (box), date, TRUE, TRUE, 0);
1148 
1149  box = GTK_WIDGET(gtk_builder_get_object (builder,
1150  "pref/" GNC_PREFS_GROUP_ACCT_SUMMARY "/" GNC_PREF_END_DATE));
1151  date = gnc_date_edit_new(gnc_time (NULL), FALSE, FALSE);
1152  gtk_widget_show (date);
1153  gtk_box_pack_start (GTK_BOX (box), date, TRUE, TRUE, 0);
1154 
1155  box = GTK_WIDGET(gtk_builder_get_object (builder,
1156  "pref/" GNC_PREFS_GROUP_GENERAL "/" GNC_PREF_CURRENCY_OTHER));
1157  currency = gnc_currency_edit_new();
1158  gnc_currency_edit_set_currency (GNC_CURRENCY_EDIT(currency), gnc_default_currency());
1159  gtk_widget_show (currency);
1160  gtk_box_pack_start(GTK_BOX (box), currency, TRUE, TRUE, 0);
1161 
1162  box = GTK_WIDGET(gtk_builder_get_object (builder,
1163  "pref/" GNC_PREFS_GROUP_GENERAL_REPORT "/" GNC_PREF_CURRENCY_OTHER));
1164  currency = gnc_currency_edit_new();
1165  gnc_currency_edit_set_currency (GNC_CURRENCY_EDIT(currency), gnc_default_currency());
1166  gtk_widget_show (currency);
1167  gtk_box_pack_start(GTK_BOX (box), currency, TRUE, TRUE, 0);
1168 
1169 
1170  /* Add to the list of interesting widgets */
1171  gnc_prefs_build_widget_table(builder, dialog);
1172 
1173  g_slist_foreach(add_ins, gnc_preferences_build_page, dialog);
1174 
1175  /* Sort tabs alphabetically */
1176  gnc_prefs_sort_pages(GTK_NOTEBOOK(notebook));
1177  gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 0);
1178 
1179  DEBUG("We have the following interesting widgets:");
1180  g_hash_table_foreach(prefs_table, (GHFunc)gnc_prefs_connect_one, dialog);
1181  DEBUG("Done with interesting widgets.");
1182 
1183  /* Other stuff */
1184  gdate = g_date_new_dmy(31, G_DATE_JULY, 2013);
1185  g_date_strftime(buf, sizeof(buf), "%x", gdate);
1186  store = GTK_LIST_STORE(gtk_builder_get_object (builder, "date_formats"));
1187  path = gtk_tree_path_new_from_indices (QOF_DATE_FORMAT_LOCALE, -1);
1188  if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path))
1189  gtk_list_store_set (store, &iter, 1, buf, -1);
1190  g_date_free(gdate);
1191 
1192  locale_currency = gnc_locale_default_currency ();
1193  currency_name = gnc_commodity_get_printname(locale_currency);
1194  label = GTK_WIDGET(gtk_builder_get_object (builder, "locale_currency"));
1195  gtk_label_set_label(GTK_LABEL(label), currency_name);
1196  label = GTK_WIDGET(gtk_builder_get_object (builder, "locale_currency2"));
1197  gtk_label_set_label(GTK_LABEL(label), currency_name);
1198 
1199  g_object_unref(G_OBJECT(builder));
1200 
1201  LEAVE("dialog %p", dialog);
1202  return dialog;
1203 }
1204 
1205 
1206 /*************************************/
1207 /* Common callback code */
1208 /*************************************/
1209 
1210 
1211 
1226 static gboolean
1227 show_handler (const char *class_name, gint component_id,
1228  gpointer user_data, gpointer iter_data)
1229 {
1230  GtkWidget *dialog;
1231 
1232  ENTER(" ");
1233  dialog = GTK_WIDGET(user_data);
1234  gtk_window_present(GTK_WINDOW(dialog));
1235  LEAVE(" ");
1236  return(TRUE);
1237 }
1238 
1239 
1246 static void
1247 close_handler (gpointer user_data)
1248 {
1249  GtkWidget *dialog;
1250 
1251  ENTER(" ");
1252  dialog = GTK_WIDGET(user_data);
1253  gnc_unregister_gui_component_by_data(DIALOG_PREFERENCES_CM_CLASS, dialog);
1254  gtk_widget_destroy(dialog);
1255  LEAVE(" ");
1256 }
1257 
1258 
1259 /* This function creates the preferences dialog and presents it to
1260  * the user. The preferences dialog is a singleton, so if a
1261  * preferences dialog already exists it will be raised to the top of
1262  * the window stack instead of creating a new dialog. */
1263 void
1265 {
1266  GtkWidget *dialog;
1267 
1268  ENTER("");
1269  if (gnc_forall_gui_components(DIALOG_PREFERENCES_CM_CLASS,
1270  show_handler, NULL))
1271  {
1272  LEAVE("existing window");
1273  return;
1274  }
1275 
1276  dialog = gnc_preferences_dialog_create();
1277 
1278  gnc_restore_window_size(GNC_PREFS_GROUP, GTK_WINDOW(dialog));
1279  gtk_widget_show(dialog);
1280 
1281  gnc_register_gui_component(DIALOG_PREFERENCES_CM_CLASS,
1282  NULL, close_handler, dialog);
1283 
1284  LEAVE(" ");
1285 }
1286 
void gnc_preferences_add_page(const gchar *filename, const gchar *widgetname, const gchar *tabname)
void qof_instance_get(const QofInstance *inst, const gchar *first_param,...)
Wrapper for g_object_get.
void gnc_currency_edit_set_currency(GNCCurrencyEdit *gce, const gnc_commodity *currency)
utility functions for the GnuCash UI
#define PINFO(format, args...)
Definition: qoflog.h:249
#define DEBUG(format, args...)
Definition: qoflog.h:255
GtkTable * table_to
GtkTable * table_from
void gnc_preferences_add_to_page(const gchar *filename, const gchar *widgetname, const gchar *tabname)
GList * gnc_account_list_name_violations(QofBook *book, const gchar *separator)
Definition: Account.c:196
GSList * add_ins
#define ENTER(format, args...)
Definition: qoflog.h:261
gnc_commodity * gnc_default_currency(void)
Definition: gnc-ui-util.c:939
gboolean full_page
Currency selection widget.
Account handling public routines.
Gobject helper routines.
gchar * gnc_account_name_violations_errmsg(const gchar *separator, GList *invalid_account_names)
Definition: Account.c:159
void gnc_prefs_bind(const gchar *group, const gchar *pref_name, gpointer object, const gchar *property)
Definition: gnc-prefs.c:186
struct addition_t addition
void gnc_period_select_set_fy_end(GncPeriodSelect *period, const GDate *fy_end)
Dialog for handling user preferences.
void gnc_gnome_help(const char *file_name, const char *anchor)
All type declarations for the whole Gnucash engine.
Generic api to store and retrieve preferences.
void gnc_preferences_dialog(void)
void gnc_preferences_response_cb(GtkDialog *dialog, gint response, GtkDialog *unused)
const char * gnc_commodity_get_printname(const gnc_commodity *cm)
GtkWidget * gnc_currency_edit_new(void)
struct KvpFrameImpl KvpFrame
Definition: kvp_frame.h:76
#define LEAVE(format, args...)
Definition: qoflog.h:271
time64 gnc_time(time64 *tbuf)
get the current local time
GtkWidget * gnc_period_select_new(gboolean starting_labels)
A custom widget for selecting accounting periods.
const gchar * QofLogModule
Definition: qofid.h:89
void gnc_account_separator_pref_changed_cb(GtkEntry *entry, GtkWidget *dialog)