1 /*
2 ** 2009-12-28 - Implementation of the nagging configuration. This mainly gives the user an option to forget
3 ** which dialogs have been suppressed, and hooks into the save/load of configure data.
4 */
5
6 #include "gentoo.h"
7
8 #include "configure.h"
9 #include "xmlutil.h"
10
11 #include "cfg_nag.h"
12
13 #define NODE "Nagging"
14
15 /* ----------------------------------------------------------------------------------------- */
16
17 typedef struct {
18 GtkWidget *vbox;
19 GtkWidget *label;
20 GtkWidget *reset;
21 gboolean do_reset;
22
23 MainInfo *min;
24 gboolean modified;
25 } P_Nag;
26
27 static P_Nag the_page;
28
29 /* ----------------------------------------------------------------------------------------- */
30
cng_initialize(NagInfo * ni)31 void cng_initialize(NagInfo *ni)
32 {
33 ni->ignored = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
34 }
35
cng_num_ignored(const NagInfo * ni)36 gsize cng_num_ignored(const NagInfo *ni)
37 {
38 return ni != NULL ? g_hash_table_size(ni->ignored) : 0u;
39 }
40
cng_is_ignored(const NagInfo * ni,const gchar * tag)41 gboolean cng_is_ignored(const NagInfo *ni, const gchar *tag)
42 {
43 if(ni == NULL || tag == NULL)
44 return FALSE;
45 if(g_hash_table_lookup_extended(ni->ignored, tag, NULL, NULL))
46 return TRUE;
47 return FALSE;
48 }
49
50 /* 2009-12-29 - Adds the given tag to the set of ignored tags. The tag is copied. */
cng_ignore(NagInfo * ni,const gchar * tag)51 void cng_ignore(NagInfo *ni, const gchar *tag)
52 {
53 gpointer key;
54
55 if(ni == NULL || tag == NULL)
56 return;
57 /* Protect against multiple insertions, since that would leak memory. */
58 if(g_hash_table_lookup_extended(ni->ignored, (gpointer) tag, NULL, NULL))
59 return;
60 if((key = g_strdup(tag)) != NULL)
61 {
62 g_hash_table_insert(ni->ignored, key, NULL);
63 }
64 }
65
cng_reset(NagInfo * ni)66 void cng_reset(NagInfo *ni)
67 {
68 if(ni != NULL)
69 g_hash_table_remove_all(ni->ignored);
70 }
71
72 /* ----------------------------------------------------------------------------------------- */
73
set_label(GtkWidget * label,gsize num)74 static void set_label(GtkWidget *label, gsize num)
75 {
76 gchar buf[256];
77
78 g_snprintf(buf, sizeof buf, _("Click the button below to reset the %zu stored 'Don't show this dialog again' responses."), num);
79 gtk_label_set_markup(GTK_LABEL(label), buf);
80 }
81
evt_reset_clicked(GtkWidget * wid,gpointer user)82 static void evt_reset_clicked(GtkWidget *wid, gpointer user)
83 {
84 P_Nag *page = user;
85
86 page->do_reset = TRUE;
87 page->modified = TRUE;
88 set_label(page->label, 0);
89 gtk_widget_set_sensitive(page->reset, FALSE);
90 }
91
cng_init(MainInfo * min,gchar ** name)92 static GtkWidget * cng_init(MainInfo *min, gchar **name)
93 {
94 P_Nag *page = &the_page;
95 gsize num;
96
97 if(name == NULL)
98 return NULL;
99
100 *name = _("Nagging");
101
102 page->min = min;
103 page->modified = FALSE;
104
105 page->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
106 page->label = gtk_label_new(NULL);
107 num = cng_num_ignored(&min->cfg.nag);
108 set_label(page->label, num);
109 gtk_box_pack_start(GTK_BOX(page->vbox), page->label, FALSE, FALSE, 5);
110 page->reset = gtk_button_new_with_label(_("Reset All"));
111 gtk_widget_set_sensitive(page->reset, num > 0);
112 g_signal_connect(G_OBJECT(page->reset), "clicked", G_CALLBACK(evt_reset_clicked), page);
113 gtk_box_pack_start(GTK_BOX(page->vbox), page->reset, FALSE, FALSE, 0);
114
115 gtk_widget_show_all(page->vbox);
116
117 return page->vbox;
118 }
119
120 /* ----------------------------------------------------------------------------------------- */
121
cng_update(MainInfo * min)122 static void cng_update(MainInfo *min)
123 {
124 P_Nag *page = &the_page;
125
126 page->do_reset = FALSE;
127 page->modified = FALSE;
128 }
129
130 /* ----------------------------------------------------------------------------------------- */
131
cng_accept(MainInfo * min)132 static void cng_accept(MainInfo *min)
133 {
134 P_Nag *page = &the_page;
135
136 if(!page->modified)
137 return;
138 if(page->do_reset)
139 cng_reset(&min->cfg.nag);
140 page->modified = FALSE;
141 }
142
143 /* ----------------------------------------------------------------------------------------- */
144
cng_save(MainInfo * min,FILE * out)145 static gint cng_save(MainInfo *min, FILE *out)
146 {
147 GHashTableIter iter;
148 gpointer key;
149
150 xml_put_node_open(out, NODE);
151 g_hash_table_iter_init(&iter, min->cfg.nag.ignored);
152 while(g_hash_table_iter_next(&iter, &key, NULL))
153 {
154 xml_put_text(out, "ignore", key);
155 }
156 xml_put_node_close(out, NODE);
157
158 return TRUE;
159 }
160
visit_ignore(const XmlNode * child,gpointer user)161 static void visit_ignore(const XmlNode *child, gpointer user)
162 {
163 const gchar *text;
164
165 if(xml_get_text(child, "ignore", &text))
166 cng_ignore(&((MainInfo *) user)->cfg.nag, text);
167 }
168
cng_load(MainInfo * min,const XmlNode * node)169 static void cng_load(MainInfo *min, const XmlNode *node)
170 {
171 const XmlNode *root;
172
173 if((root = xml_tree_search(node, NODE)) != NULL)
174 xml_node_visit_children(root, visit_ignore, min);
175 }
176
177 /* ----------------------------------------------------------------------------------------- */
178
cng_describe(MainInfo * min)179 const CfgModule * cng_describe(MainInfo *min)
180 {
181 static const CfgModule desc = { NODE, cng_init, cng_update, cng_accept, cng_save, cng_load, NULL };
182
183 return &desc;
184 }
185