]> git.0d.be Git - empathy.git/blob - src/empathy-preferences.c
Improve wording.
[empathy.git] / src / empathy-preferences.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2003-2007 Imendio AB
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Authors: Mikael Hallendal <micke@imendio.com>
21  *          Richard Hult <richard@imendio.com>
22  *          Martyn Russell <martyn@imendio.com>
23  */
24
25 #include <config.h>
26
27 #include <string.h>
28
29 #include <gtk/gtk.h>
30 #include <glade/glade.h>
31 #include <glib/gi18n.h>
32
33 #include <libempathy/empathy-utils.h>
34
35 #include <libempathy-gtk/empathy-conf.h>
36 #include <libempathy-gtk/empathy-ui-utils.h>
37 #include <libempathy-gtk/empathy-theme-manager.h>
38 #include <libempathy-gtk/empathy-spell.h>
39 #include <libempathy-gtk/empathy-contact-list-store.h>
40 #include <libempathy-gtk/empathy-gtk-enum-types.h>
41
42 #include "empathy-preferences.h"
43
44 typedef struct {
45         GtkWidget *dialog;
46
47         GtkWidget *notebook;
48
49         GtkWidget *checkbutton_show_avatars;
50         GtkWidget *checkbutton_compact_contact_list;
51         GtkWidget *checkbutton_show_smileys;
52         GtkWidget *combobox_chat_theme;
53         GtkWidget *checkbutton_separate_chat_windows;
54         GtkWidget *checkbutton_autoconnect;
55         GtkWidget *radiobutton_contact_list_sort_by_name;
56         GtkWidget *radiobutton_contact_list_sort_by_state;
57
58         GtkWidget *checkbutton_sounds_enabled;
59         GtkWidget *checkbutton_sounds_disabled_away;
60         GtkWidget *treeview_sounds;
61
62         GtkWidget *treeview_spell_checker;
63
64         GList     *notify_ids;
65 } EmpathyPreferences;
66
67 static void     preferences_setup_widgets                (EmpathyPreferences      *preferences);
68 static void     preferences_languages_setup              (EmpathyPreferences      *preferences);
69 static void     preferences_languages_add                (EmpathyPreferences      *preferences);
70 static void     preferences_languages_save               (EmpathyPreferences      *preferences);
71 static gboolean preferences_languages_save_foreach       (GtkTreeModel           *model,
72                                                           GtkTreePath            *path,
73                                                           GtkTreeIter            *iter,
74                                                           gchar                 **languages);
75 static void     preferences_languages_load               (EmpathyPreferences      *preferences);
76 static gboolean preferences_languages_load_foreach       (GtkTreeModel           *model,
77                                                           GtkTreePath            *path,
78                                                           GtkTreeIter            *iter,
79                                                           gchar                 **languages);
80 static void     preferences_languages_cell_toggled_cb    (GtkCellRendererToggle  *cell,
81                                                           gchar                  *path_string,
82                                                           EmpathyPreferences      *preferences);
83 static void     preferences_themes_setup                 (EmpathyPreferences      *preferences);
84 static void     preferences_widget_sync_bool             (const gchar            *key,
85                                                           GtkWidget              *widget);
86 static void     preferences_widget_sync_string           (const gchar            *key,
87                                                           GtkWidget              *widget);
88 static void     preferences_widget_sync_string_combo     (const gchar            *key,
89                                                           GtkWidget              *widget);
90 static void     preferences_notify_string_cb             (EmpathyConf             *conf,
91                                                           const gchar            *key,
92                                                           gpointer                user_data);
93 static void     preferences_notify_string_combo_cb       (EmpathyConf             *conf,
94                                                           const gchar            *key,
95                                                           gpointer                user_data);
96 static void     preferences_notify_bool_cb               (EmpathyConf             *conf,
97                                                           const gchar            *key,
98                                                           gpointer                user_data);
99 static void     preferences_notify_sensitivity_cb        (EmpathyConf             *conf,
100                                                           const gchar            *key,
101                                                           gpointer                user_data);
102 static void     preferences_hookup_toggle_button         (EmpathyPreferences      *preferences,
103                                                           const gchar            *key,
104                                                           GtkWidget              *widget);
105 static void     preferences_hookup_radio_button          (EmpathyPreferences      *preferences,
106                                                           const gchar            *key,
107                                                           GtkWidget              *widget);
108 static void     preferences_hookup_string_combo          (EmpathyPreferences      *preferences,
109                                                           const gchar            *key,
110                                                           GtkWidget              *widget);
111 static void     preferences_hookup_sensitivity           (EmpathyPreferences      *preferences,
112                                                           const gchar            *key,
113                                                           GtkWidget              *widget);
114 static void     preferences_toggle_button_toggled_cb     (GtkWidget              *button,
115                                                           gpointer                user_data);
116 static void     preferences_radio_button_toggled_cb      (GtkWidget              *button,
117                                                           gpointer                user_data);
118 static void     preferences_string_combo_changed_cb      (GtkWidget *button,
119                                                           gpointer                user_data);
120 static void     preferences_destroy_cb                   (GtkWidget              *widget,
121                                                           EmpathyPreferences      *preferences);
122 static void     preferences_response_cb                  (GtkWidget              *widget,
123                                                           gint                    response,
124                                                           EmpathyPreferences      *preferences);
125
126 enum {
127         COL_LANG_ENABLED,
128         COL_LANG_CODE,
129         COL_LANG_NAME,
130         COL_LANG_COUNT
131 };
132
133 enum {
134         COL_COMBO_VISIBLE_NAME,
135         COL_COMBO_NAME,
136         COL_COMBO_COUNT
137 };
138
139 enum {
140         COL_SOUND_ENABLED,
141         COL_SOUND_NAME,
142         COL_SOUND_KEY,
143         COL_SOUND_COUNT
144 };
145
146 typedef struct {
147         const char *name;
148         const char *key;
149 } SoundEventEntry;
150
151 /* TODO: add phone related sounds also? */
152 static SoundEventEntry sound_entries [] = {
153         { N_("Message received"), EMPATHY_PREFS_SOUNDS_INCOMING_MESSAGE },
154         { N_("Message sent"), EMPATHY_PREFS_SOUNDS_OUTGOING_MESSAGE },
155         { N_("New conversation"), EMPATHY_PREFS_SOUNDS_NEW_CONVERSATION },
156         { N_("Contact goes online"), EMPATHY_PREFS_SOUNDS_CONTACT_LOGIN },
157         { N_("Contact goes offline"), EMPATHY_PREFS_SOUNDS_CONTACT_LOGOUT },
158         { N_("Account connected"), EMPATHY_PREFS_SOUNDS_SERVICE_LOGIN },
159         { N_("Account disconnected"), EMPATHY_PREFS_SOUNDS_SERVICE_LOGOUT }
160 };
161
162 static void
163 preferences_add_id (EmpathyPreferences *preferences, guint id)
164 {
165         preferences->notify_ids = g_list_prepend (preferences->notify_ids,
166                                                   GUINT_TO_POINTER (id));
167 }
168
169 static void
170 preferences_compact_contact_list_changed_cb (EmpathyConf *conf,
171                                              const gchar *key,
172                                              gpointer     user_data)
173 {
174         EmpathyPreferences *preferences = user_data;
175         gboolean            value;
176
177         if (empathy_conf_get_bool (empathy_conf_get (), key, &value)) {
178                 gtk_widget_set_sensitive (preferences->checkbutton_show_avatars,
179                                           !value);
180         }
181 }
182
183 static void
184 preferences_setup_widgets (EmpathyPreferences *preferences)
185 {
186         guint id;
187
188         preferences_hookup_toggle_button (preferences,
189                                           EMPATHY_PREFS_SOUNDS_ENABLED,
190                                           preferences->checkbutton_sounds_enabled);
191         preferences_hookup_toggle_button (preferences,
192                                           EMPATHY_PREFS_SOUNDS_DISABLED_AWAY,
193                                           preferences->checkbutton_sounds_disabled_away);
194
195         preferences_hookup_sensitivity (preferences,
196                                         EMPATHY_PREFS_SOUNDS_ENABLED,
197                                         preferences->checkbutton_sounds_disabled_away);
198         preferences_hookup_sensitivity (preferences,
199                                         EMPATHY_PREFS_SOUNDS_ENABLED,
200                                         preferences->treeview_sounds);
201
202         preferences_hookup_toggle_button (preferences,
203                                           EMPATHY_PREFS_UI_SEPARATE_CHAT_WINDOWS,
204                                           preferences->checkbutton_separate_chat_windows);
205
206         preferences_hookup_toggle_button (preferences,
207                                           EMPATHY_PREFS_UI_SHOW_AVATARS,
208                                           preferences->checkbutton_show_avatars);
209
210         preferences_hookup_toggle_button (preferences,
211                                           EMPATHY_PREFS_UI_COMPACT_CONTACT_LIST,
212                                           preferences->checkbutton_compact_contact_list);
213
214         preferences_hookup_toggle_button (preferences,
215                                           EMPATHY_PREFS_CHAT_SHOW_SMILEYS,
216                                           preferences->checkbutton_show_smileys);
217
218         preferences_hookup_string_combo (preferences,
219                                          EMPATHY_PREFS_CHAT_THEME,
220                                          preferences->combobox_chat_theme);
221
222         preferences_hookup_radio_button (preferences,
223                                          EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM,
224                                          preferences->radiobutton_contact_list_sort_by_name);
225
226         preferences_hookup_toggle_button (preferences,
227                                           EMPATHY_PREFS_AUTOCONNECT,
228                                           preferences->checkbutton_autoconnect);
229
230         id = empathy_conf_notify_add (empathy_conf_get (),
231                                       EMPATHY_PREFS_UI_COMPACT_CONTACT_LIST,
232                                       preferences_compact_contact_list_changed_cb,
233                                       preferences);
234         if (id) {
235                 preferences_add_id (preferences, id);
236         }
237         preferences_compact_contact_list_changed_cb (empathy_conf_get (),
238                                                      EMPATHY_PREFS_UI_COMPACT_CONTACT_LIST,
239                                                      preferences);
240 }
241
242 static void
243 preferences_sound_cell_toggled_cb (GtkCellRendererToggle *toggle,
244                                    char *path_string,
245                                    EmpathyPreferences *preferences)
246 {
247         GtkTreePath *path;
248         gboolean toggled, instore;
249         GtkTreeIter iter;
250         GtkTreeView *view;
251         GtkTreeModel *model;
252         char *key;
253
254         view = GTK_TREE_VIEW (preferences->treeview_sounds);
255         model = gtk_tree_view_get_model (view);
256
257         path = gtk_tree_path_new_from_string (path_string);
258         toggled = gtk_cell_renderer_toggle_get_active (toggle);
259
260         gtk_tree_model_get_iter (model, &iter, path);
261         gtk_tree_model_get (model, &iter, COL_SOUND_KEY, &key,
262                             COL_SOUND_ENABLED, &instore, -1);
263
264         instore ^= 1;
265
266         gtk_list_store_set (GTK_LIST_STORE (model), &iter,
267                             COL_SOUND_ENABLED, instore, -1);
268
269         empathy_conf_set_bool (empathy_conf_get (), key, instore);
270
271         gtk_tree_path_free (path);
272 }
273
274 static void
275 preferences_sound_load (EmpathyPreferences *preferences)
276 {
277         int i;
278         GtkTreeView *view;
279         GtkListStore *store;
280         GtkTreeIter iter;
281         gboolean set;
282         EmpathyConf *conf;
283
284         view = GTK_TREE_VIEW (preferences->treeview_sounds);
285         store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
286         conf = empathy_conf_get ();
287
288         for (i = 0; i < G_N_ELEMENTS (sound_entries); i++) {
289                 empathy_conf_get_bool (conf, sound_entries[i].key, &set);
290
291                 gtk_list_store_append (store, &iter);
292                 gtk_list_store_set (store, &iter, COL_SOUND_ENABLED, set,
293                                     COL_SOUND_NAME, sound_entries[i].name,
294                                     COL_SOUND_KEY, sound_entries[i].key, -1);
295         }
296 }
297
298 static void
299 preferences_sound_setup (EmpathyPreferences *preferences)
300 {
301         GtkTreeView *view;
302         GtkListStore *store;
303         GtkCellRenderer *renderer;
304         GtkTreeViewColumn *column;
305
306         view = GTK_TREE_VIEW (preferences->treeview_sounds);
307
308         store = gtk_list_store_new (COL_SOUND_COUNT,
309                                     G_TYPE_BOOLEAN, /* enabled */
310                                     G_TYPE_STRING,  /* name */
311                                     G_TYPE_STRING); /* key */
312
313         gtk_tree_view_set_model (view, GTK_TREE_MODEL (store));
314
315         renderer = gtk_cell_renderer_toggle_new ();
316         g_signal_connect (renderer, "toggled",
317                           G_CALLBACK (preferences_sound_cell_toggled_cb),
318                           preferences);
319
320         column = gtk_tree_view_column_new ();
321         gtk_tree_view_column_pack_start (column, renderer, FALSE);
322         gtk_tree_view_column_add_attribute (column, renderer,
323                                             "active", COL_SOUND_ENABLED);
324
325         renderer = gtk_cell_renderer_text_new ();
326         gtk_tree_view_column_pack_start (column, renderer, FALSE);
327         gtk_tree_view_column_add_attribute (column, renderer,
328                                             "text", COL_SOUND_NAME);
329
330         gtk_tree_view_append_column (view, column);
331
332         gtk_tree_view_column_set_resizable (column, FALSE);
333         gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
334
335         g_object_unref (store);
336 }
337
338 static void
339 preferences_languages_setup (EmpathyPreferences *preferences)
340 {
341         GtkTreeView       *view;
342         GtkListStore      *store;
343         GtkTreeSelection  *selection;
344         GtkTreeModel      *model;
345         GtkTreeViewColumn *column;
346         GtkCellRenderer   *renderer;
347         guint              col_offset;
348
349         view = GTK_TREE_VIEW (preferences->treeview_spell_checker);
350
351         store = gtk_list_store_new (COL_LANG_COUNT,
352                                     G_TYPE_BOOLEAN,  /* enabled */
353                                     G_TYPE_STRING,   /* code */
354                                     G_TYPE_STRING);  /* name */
355
356         gtk_tree_view_set_model (view, GTK_TREE_MODEL (store));
357
358         selection = gtk_tree_view_get_selection (view);
359         gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
360
361         model = GTK_TREE_MODEL (store);
362
363         renderer = gtk_cell_renderer_toggle_new ();
364         g_signal_connect (renderer, "toggled",
365                           G_CALLBACK (preferences_languages_cell_toggled_cb),
366                           preferences);
367
368         column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
369                                                            "active", COL_LANG_ENABLED,
370                                                            NULL);
371
372         gtk_tree_view_append_column (view, column);
373
374         renderer = gtk_cell_renderer_text_new ();
375         col_offset = gtk_tree_view_insert_column_with_attributes (view,
376                                                                   -1, _("Language"),
377                                                                   renderer,
378                                                                   "text", COL_LANG_NAME,
379                                                                   NULL);
380
381         g_object_set_data (G_OBJECT (renderer),
382                            "column", GINT_TO_POINTER (COL_LANG_NAME));
383
384         column = gtk_tree_view_get_column (view, col_offset - 1);
385         gtk_tree_view_column_set_sort_column_id (column, COL_LANG_NAME);
386         gtk_tree_view_column_set_resizable (column, FALSE);
387         gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
388
389         g_object_unref (store);
390 }
391
392 static void
393 preferences_languages_add (EmpathyPreferences *preferences)
394 {
395         GtkTreeView  *view;
396         GtkListStore *store;
397         GList        *codes, *l;
398
399         view = GTK_TREE_VIEW (preferences->treeview_spell_checker);
400         store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
401
402         codes = empathy_spell_get_language_codes ();
403
404         empathy_conf_set_bool (empathy_conf_get(),
405                                EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED,
406                                codes != NULL);
407         if (!codes) {
408                 gtk_widget_set_sensitive (preferences->treeview_spell_checker, FALSE);
409         }               
410
411         for (l = codes; l; l = l->next) {
412                 GtkTreeIter  iter;
413                 const gchar *code;
414                 const gchar *name;
415
416                 code = l->data;
417                 name = empathy_spell_get_language_name (code);
418                 if (!name) {
419                         continue;
420                 }
421
422                 gtk_list_store_append (store, &iter);
423                 gtk_list_store_set (store, &iter,
424                                     COL_LANG_CODE, code,
425                                     COL_LANG_NAME, name,
426                                     -1);
427         }
428
429         empathy_spell_free_language_codes (codes);
430 }
431
432 static void
433 preferences_languages_save (EmpathyPreferences *preferences)
434 {
435         GtkTreeView       *view;
436         GtkTreeModel      *model;
437
438         gchar             *languages = NULL;
439
440         view = GTK_TREE_VIEW (preferences->treeview_spell_checker);
441         model = gtk_tree_view_get_model (view);
442
443         gtk_tree_model_foreach (model,
444                                 (GtkTreeModelForeachFunc) preferences_languages_save_foreach,
445                                 &languages);
446
447         /* if user selects no languages, we don't want spell check */
448         empathy_conf_set_bool (empathy_conf_get (),
449                                EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED,
450                                languages != NULL);
451
452         empathy_conf_set_string (empathy_conf_get (),
453                                  EMPATHY_PREFS_CHAT_SPELL_CHECKER_LANGUAGES,
454                                  languages ? languages : "");
455
456         g_free (languages);
457 }
458
459 static gboolean
460 preferences_languages_save_foreach (GtkTreeModel  *model,
461                                     GtkTreePath   *path,
462                                     GtkTreeIter   *iter,
463                                     gchar        **languages)
464 {
465         gboolean  enabled;
466         gchar    *code;
467
468         if (!languages) {
469                 return TRUE;
470         }
471
472         gtk_tree_model_get (model, iter, COL_LANG_ENABLED, &enabled, -1);
473         if (!enabled) {
474                 return FALSE;
475         }
476
477         gtk_tree_model_get (model, iter, COL_LANG_CODE, &code, -1);
478         if (!code) {
479                 return FALSE;
480         }
481
482         if (!(*languages)) {
483                 *languages = g_strdup (code);
484         } else {
485                 gchar *str = *languages;
486                 *languages = g_strdup_printf ("%s,%s", str, code);
487                 g_free (str);
488         }
489
490         g_free (code);
491
492         return FALSE;
493 }
494
495 static void
496 preferences_languages_load (EmpathyPreferences *preferences)
497 {
498         GtkTreeView   *view;
499         GtkTreeModel  *model;
500         gchar         *value;
501         gchar        **vlanguages;
502
503         if (!empathy_conf_get_string (empathy_conf_get (),
504                                       EMPATHY_PREFS_CHAT_SPELL_CHECKER_LANGUAGES,
505                                       &value) || !value) {
506                 return;
507         }
508
509         vlanguages = g_strsplit (value, ",", -1);
510         g_free (value);
511
512         view = GTK_TREE_VIEW (preferences->treeview_spell_checker);
513         model = gtk_tree_view_get_model (view);
514
515         gtk_tree_model_foreach (model,
516                                 (GtkTreeModelForeachFunc) preferences_languages_load_foreach,
517                                 vlanguages);
518
519         g_strfreev (vlanguages);
520 }
521
522 static gboolean
523 preferences_languages_load_foreach (GtkTreeModel  *model,
524                                     GtkTreePath   *path,
525                                     GtkTreeIter   *iter,
526                                     gchar        **languages)
527 {
528         gchar    *code;
529         gchar    *lang;
530         gint      i;
531         gboolean  found = FALSE;
532
533         if (!languages) {
534                 return TRUE;
535         }
536
537         gtk_tree_model_get (model, iter, COL_LANG_CODE, &code, -1);
538         if (!code) {
539                 return FALSE;
540         }
541
542         for (i = 0, lang = languages[i]; lang; lang = languages[++i]) {
543                 if (strcmp (lang, code) == 0) {
544                         found = TRUE;
545                 }
546         }
547
548         gtk_list_store_set (GTK_LIST_STORE (model), iter, COL_LANG_ENABLED, found, -1);
549         return FALSE;
550 }
551
552 static void
553 preferences_languages_cell_toggled_cb (GtkCellRendererToggle *cell,
554                                        gchar                 *path_string,
555                                        EmpathyPreferences     *preferences)
556 {
557         GtkTreeView  *view;
558         GtkTreeModel *model;
559         GtkListStore *store;
560         GtkTreePath  *path;
561         GtkTreeIter   iter;
562         gboolean      enabled;
563
564         view = GTK_TREE_VIEW (preferences->treeview_spell_checker);
565         model = gtk_tree_view_get_model (view);
566         store = GTK_LIST_STORE (model);
567
568         path = gtk_tree_path_new_from_string (path_string);
569
570         gtk_tree_model_get_iter (model, &iter, path);
571         gtk_tree_model_get (model, &iter, COL_LANG_ENABLED, &enabled, -1);
572
573         enabled ^= 1;
574
575         gtk_list_store_set (store, &iter, COL_LANG_ENABLED, enabled, -1);
576         gtk_tree_path_free (path);
577
578         preferences_languages_save (preferences);
579 }
580
581 static void
582 preferences_themes_setup (EmpathyPreferences *preferences)
583 {
584         GtkComboBox   *combo;
585         GtkListStore  *model;
586         GtkTreeIter    iter;
587         const gchar  **themes;
588         gint           i;
589
590         combo = GTK_COMBO_BOX (preferences->combobox_chat_theme);
591
592         model = gtk_list_store_new (COL_COMBO_COUNT,
593                                     G_TYPE_STRING,
594                                     G_TYPE_STRING);
595
596         themes = empathy_theme_manager_get_themes ();
597         for (i = 0; themes[i]; i += 2) {
598                 gtk_list_store_append (model, &iter);
599                 gtk_list_store_set (model, &iter,
600                                     COL_COMBO_VISIBLE_NAME, _(themes[i + 1]),
601                                     COL_COMBO_NAME, themes[i],
602                                     -1);
603         }
604
605         gtk_combo_box_set_model (combo, GTK_TREE_MODEL (model));
606         g_object_unref (model);
607 }
608
609 static void
610 preferences_widget_sync_bool (const gchar *key, GtkWidget *widget)
611 {
612         gboolean value;
613
614         if (empathy_conf_get_bool (empathy_conf_get (), key, &value)) {
615                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), value);
616         }
617 }
618
619 static void
620 preferences_widget_sync_string (const gchar *key, GtkWidget *widget)
621 {
622         gchar *value;
623
624         if (empathy_conf_get_string (empathy_conf_get (), key, &value) && value) {
625                 if (GTK_IS_ENTRY (widget)) {
626                         gtk_entry_set_text (GTK_ENTRY (widget), value);
627                 } else if (GTK_IS_RADIO_BUTTON (widget)) {
628                         if (strcmp (key, EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM) == 0) {
629                                 GType        type;
630                                 GEnumClass  *enum_class;
631                                 GEnumValue  *enum_value;
632                                 GSList      *list;
633                                 GtkWidget   *toggle_widget;
634                                 
635                                 /* Get index from new string */
636                                 type = empathy_contact_list_store_sort_get_type ();
637                                 enum_class = G_ENUM_CLASS (g_type_class_peek (type));
638                                 enum_value = g_enum_get_value_by_nick (enum_class, value);
639                                 
640                                 if (enum_value) { 
641                                         list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
642                                         toggle_widget = g_slist_nth_data (list, enum_value->value);
643                                         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle_widget), TRUE);
644                                 }
645                         } else {
646                                 g_warning ("Unhandled key:'%s' just had string change", key);
647                         }
648                 }
649
650                 g_free (value);
651         }
652 }
653
654 static void
655 preferences_widget_sync_string_combo (const gchar *key, GtkWidget *widget)
656 {
657         gchar        *value;
658         GtkTreeModel *model;
659         GtkTreeIter   iter;
660         gboolean      found;
661
662         if (!empathy_conf_get_string (empathy_conf_get (), key, &value)) {
663                 return;
664         }
665
666         model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
667
668         found = FALSE;
669         if (value && gtk_tree_model_get_iter_first (model, &iter)) {
670                 gchar *name;
671
672                 do {
673                         gtk_tree_model_get (model, &iter,
674                                             COL_COMBO_NAME, &name,
675                                             -1);
676
677                         if (strcmp (name, value) == 0) {
678                                 found = TRUE;
679                                 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter);
680                                 break;
681                         } else {
682                                 found = FALSE;
683                         }
684
685                         g_free (name);
686                 } while (gtk_tree_model_iter_next (model, &iter));
687         }
688
689         /* Fallback to the first one. */
690         if (!found) {
691                 if (gtk_tree_model_get_iter_first (model, &iter)) {
692                         gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter);
693                 }
694         }
695
696         g_free (value);
697 }
698
699 static void
700 preferences_notify_string_cb (EmpathyConf  *conf,
701                               const gchar *key,
702                               gpointer     user_data)
703 {
704         preferences_widget_sync_string (key, user_data);
705 }
706
707 static void
708 preferences_notify_string_combo_cb (EmpathyConf  *conf,
709                                     const gchar *key,
710                                     gpointer     user_data)
711 {
712         preferences_widget_sync_string_combo (key, user_data);
713 }
714
715 static void
716 preferences_notify_bool_cb (EmpathyConf  *conf,
717                             const gchar *key,
718                             gpointer     user_data)
719 {
720         preferences_widget_sync_bool (key, user_data);
721 }
722
723 static void
724 preferences_notify_sensitivity_cb (EmpathyConf  *conf,
725                                    const gchar *key,
726                                    gpointer     user_data)
727 {
728         gboolean value;
729
730         if (empathy_conf_get_bool (conf, key, &value)) {
731                 gtk_widget_set_sensitive (GTK_WIDGET (user_data), value);
732         }
733 }
734
735 #if 0
736 static void
737 preferences_widget_sync_int (const gchar *key, GtkWidget *widget)
738 {
739         gint value;
740
741         if (empathy_conf_get_int (empathy_conf_get (), key, &value)) {
742                 if (GTK_IS_SPIN_BUTTON (widget)) {
743                         gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
744                 }
745         }
746 }
747
748 static void
749 preferences_notify_int_cb (EmpathyConf  *conf,
750                            const gchar *key,
751                            gpointer     user_data)
752 {
753         preferences_widget_sync_int (key, user_data);   
754 }
755
756 static void
757 preferences_hookup_spin_button (EmpathyPreferences *preferences,
758                                 const gchar       *key,
759                                 GtkWidget         *widget)
760 {
761         guint id;
762
763         preferences_widget_sync_int (key, widget);
764
765         g_object_set_data_full (G_OBJECT (widget), "key",
766                                 g_strdup (key), g_free);
767
768         g_signal_connect (widget,
769                           "value_changed",
770                           G_CALLBACK (preferences_spin_button_value_changed_cb),
771                           NULL);
772
773         id = empathy_conf_notify_add (empathy_conf_get (),
774                                       key,
775                                       preferences_notify_int_cb,
776                                       widget);
777         if (id) {
778                 preferences_add_id (preferences, id);
779         }
780 }
781
782 static void
783 preferences_hookup_entry (EmpathyPreferences *preferences,
784                           const gchar       *key,
785                           GtkWidget         *widget)
786 {
787         guint id;
788
789         preferences_widget_sync_string (key, widget);
790
791         g_object_set_data_full (G_OBJECT (widget), "key",
792                                 g_strdup (key), g_free);
793
794         g_signal_connect (widget,
795                           "changed",
796                           G_CALLBACK (preferences_entry_value_changed_cb),
797                           NULL);
798
799         id = empathy_conf_notify_add (empathy_conf_get (),
800                                       key,
801                                       preferences_notify_string_cb,
802                                       widget);
803         if (id) {
804                 preferences_add_id (preferences, id);
805         }
806 }
807
808 static void
809 preferences_spin_button_value_changed_cb (GtkWidget *button,
810                                           gpointer   user_data)
811 {
812         const gchar *key;
813
814         key = g_object_get_data (G_OBJECT (button), "key");
815
816         empathy_conf_set_int (empathy_conf_get (),
817                               key,
818                               gtk_spin_button_get_value (GTK_SPIN_BUTTON (button)));
819 }
820
821 static void
822 preferences_entry_value_changed_cb (GtkWidget *entry,
823                                     gpointer   user_data)
824 {
825         const gchar *key;
826
827         key = g_object_get_data (G_OBJECT (entry), "key");
828
829         empathy_conf_set_string (empathy_conf_get (),
830                                  key,
831                                  gtk_entry_get_text (GTK_ENTRY (entry)));
832 }
833 #endif
834
835 static void
836 preferences_hookup_toggle_button (EmpathyPreferences *preferences,
837                                   const gchar       *key,
838                                   GtkWidget         *widget)
839 {
840         guint id;
841
842         preferences_widget_sync_bool (key, widget);
843
844         g_object_set_data_full (G_OBJECT (widget), "key",
845                                 g_strdup (key), g_free);
846
847         g_signal_connect (widget,
848                           "toggled",
849                           G_CALLBACK (preferences_toggle_button_toggled_cb),
850                           NULL);
851
852         id = empathy_conf_notify_add (empathy_conf_get (),
853                                      key,
854                                      preferences_notify_bool_cb,
855                                      widget);
856         if (id) {
857                 preferences_add_id (preferences, id);
858         }
859 }
860
861 static void
862 preferences_hookup_radio_button (EmpathyPreferences *preferences,
863                                  const gchar       *key,
864                                  GtkWidget         *widget)
865 {
866         GSList *group, *l;
867         guint   id;
868
869         preferences_widget_sync_string (key, widget);
870
871         group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
872         for (l = group; l; l = l->next) {
873                 g_signal_connect (l->data,
874                                   "toggled",
875                                   G_CALLBACK (preferences_radio_button_toggled_cb),
876                                   NULL);
877
878                 g_object_set_data_full (G_OBJECT (l->data), "key",
879                                         g_strdup (key), g_free);
880         }
881
882         id = empathy_conf_notify_add (empathy_conf_get (),
883                                      key,
884                                      preferences_notify_string_cb,
885                                      widget);
886         if (id) {
887                 preferences_add_id (preferences, id);
888         }
889 }
890
891 static void
892 preferences_hookup_string_combo (EmpathyPreferences *preferences,
893                                  const gchar       *key,
894                                  GtkWidget         *widget)
895 {
896         guint id;
897
898         preferences_widget_sync_string_combo (key, widget);
899
900         g_object_set_data_full (G_OBJECT (widget), "key",
901                                 g_strdup (key), g_free);
902
903         g_signal_connect (widget,
904                           "changed",
905                           G_CALLBACK (preferences_string_combo_changed_cb),
906                           NULL);
907
908         id = empathy_conf_notify_add (empathy_conf_get (),
909                                       key,
910                                       preferences_notify_string_combo_cb,
911                                       widget);
912         if (id) {
913                 preferences_add_id (preferences, id);
914         }
915 }
916
917 static void
918 preferences_hookup_sensitivity (EmpathyPreferences *preferences,
919                                 const gchar       *key,
920                                 GtkWidget         *widget)
921 {
922         gboolean value;
923         guint    id;
924
925         if (empathy_conf_get_bool (empathy_conf_get (), key, &value)) {
926                 gtk_widget_set_sensitive (widget, value);
927         }
928
929         id = empathy_conf_notify_add (empathy_conf_get (),
930                                       key,
931                                       preferences_notify_sensitivity_cb,
932                                       widget);
933         if (id) {
934                 preferences_add_id (preferences, id);
935         }
936 }
937
938 static void
939 preferences_toggle_button_toggled_cb (GtkWidget *button,
940                                       gpointer   user_data)
941 {
942         const gchar *key;
943
944         key = g_object_get_data (G_OBJECT (button), "key");
945
946         empathy_conf_set_bool (empathy_conf_get (),
947                                key,
948                                gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)));
949 }
950
951 static void
952 preferences_radio_button_toggled_cb (GtkWidget *button,
953                                      gpointer   user_data)
954 {
955         const gchar *key;
956         const gchar *value = NULL;
957
958         if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
959                 return;
960         }
961
962         key = g_object_get_data (G_OBJECT (button), "key");
963
964         if (key && strcmp (key, EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM) == 0) {
965                 GSList      *group;
966                 GType        type;
967                 GEnumClass  *enum_class;
968                 GEnumValue  *enum_value;
969                 
970                 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
971                 
972                 /* Get string from index */
973                 type = empathy_contact_list_store_sort_get_type ();
974                 enum_class = G_ENUM_CLASS (g_type_class_peek (type));
975                 enum_value = g_enum_get_value (enum_class, g_slist_index (group, button));
976                 
977                 if (!enum_value) {
978                         g_warning ("No GEnumValue for EmpathyContactListSort with GtkRadioButton index:%d", 
979                                    g_slist_index (group, button));
980                         return;
981                 }
982
983                 value = enum_value->value_nick;
984         }
985
986         empathy_conf_set_string (empathy_conf_get (), key, value);
987 }
988
989 static void
990 preferences_string_combo_changed_cb (GtkWidget *combo,
991                                      gpointer   user_data)
992 {
993         const gchar  *key;
994         GtkTreeModel *model;
995         GtkTreeIter   iter;
996         gchar        *name;
997
998         key = g_object_get_data (G_OBJECT (combo), "key");
999
1000         if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter)) {
1001                 model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
1002
1003                 gtk_tree_model_get (model, &iter,
1004                                     COL_COMBO_NAME, &name,
1005                                     -1);
1006                 empathy_conf_set_string (empathy_conf_get (), key, name);
1007                 g_free (name);
1008         }
1009 }
1010
1011 static void
1012 preferences_response_cb (GtkWidget         *widget,
1013                          gint               response,
1014                          EmpathyPreferences *preferences)
1015 {
1016         gtk_widget_destroy (widget);
1017 }
1018
1019 static void
1020 preferences_destroy_cb (GtkWidget         *widget,
1021                         EmpathyPreferences *preferences)
1022 {
1023         GList *l;
1024
1025         for (l = preferences->notify_ids; l; l = l->next) {
1026                 guint id;
1027
1028                 id = GPOINTER_TO_UINT (l->data);
1029                 empathy_conf_notify_remove (empathy_conf_get (), id);
1030         }
1031
1032         g_list_free (preferences->notify_ids);
1033         g_free (preferences);
1034 }
1035
1036 GtkWidget *
1037 empathy_preferences_show (GtkWindow *parent)
1038 {
1039         static EmpathyPreferences *preferences;
1040         GladeXML                 *glade;
1041         gchar                    *filename;
1042
1043         if (preferences) {
1044                 gtk_window_present (GTK_WINDOW (preferences->dialog));
1045                 return preferences->dialog;
1046         }
1047
1048         preferences = g_new0 (EmpathyPreferences, 1);
1049
1050         filename = empathy_file_lookup ("empathy-preferences.glade", "src");
1051         glade = empathy_glade_get_file (filename,
1052                 "preferences_dialog",
1053                 NULL,
1054                 "preferences_dialog", &preferences->dialog,
1055                 "notebook", &preferences->notebook,
1056                 "checkbutton_show_avatars", &preferences->checkbutton_show_avatars,
1057                 "checkbutton_compact_contact_list", &preferences->checkbutton_compact_contact_list,
1058                 "checkbutton_show_smileys", &preferences->checkbutton_show_smileys,
1059                 "combobox_chat_theme", &preferences->combobox_chat_theme,
1060                 "checkbutton_separate_chat_windows", &preferences->checkbutton_separate_chat_windows,
1061                 "checkbutton_autoconnect", &preferences->checkbutton_autoconnect,
1062                 "radiobutton_contact_list_sort_by_name", &preferences->radiobutton_contact_list_sort_by_name,
1063                 "radiobutton_contact_list_sort_by_state", &preferences->radiobutton_contact_list_sort_by_state,
1064                 "checkbutton_sounds_enabled", &preferences->checkbutton_sounds_enabled,
1065                 "checkbutton_sounds_disabled_away", &preferences->checkbutton_sounds_disabled_away,
1066                 "treeview_sounds", &preferences->treeview_sounds,
1067                 "treeview_spell_checker", &preferences->treeview_spell_checker,
1068                 NULL);
1069         g_free (filename);
1070
1071         empathy_glade_connect (glade,
1072                               preferences,
1073                               "preferences_dialog", "destroy", preferences_destroy_cb,
1074                               "preferences_dialog", "response", preferences_response_cb,
1075                               NULL);
1076
1077         g_object_unref (glade);
1078
1079         g_object_add_weak_pointer (G_OBJECT (preferences->dialog), (gpointer) &preferences);
1080
1081         preferences_themes_setup (preferences);
1082
1083         preferences_setup_widgets (preferences);
1084
1085         preferences_languages_setup (preferences);
1086         preferences_languages_add (preferences);
1087         preferences_languages_load (preferences);
1088
1089         preferences_sound_setup (preferences);
1090         preferences_sound_load (preferences);
1091
1092         if (empathy_spell_supported ()) {
1093                 GtkWidget *page;
1094
1095                 page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (preferences->notebook), 2);
1096                 gtk_widget_show (page);
1097         }
1098
1099         if (parent) {
1100                 gtk_window_set_transient_for (GTK_WINDOW (preferences->dialog),
1101                                               GTK_WINDOW (parent));
1102         }
1103
1104         gtk_widget_show (preferences->dialog);
1105
1106         return preferences->dialog;
1107 }
1108