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