]> git.0d.be Git - empathy.git/blob - src/empathy-preferences.c
Use gtk_list_store_insert_with_values ().
[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_insert_with_values (store, &iter, i,
292                                                    COL_SOUND_NAME, gettext (sound_entries[i].name),
293                                                    COL_SOUND_KEY, sound_entries[i].key, -1);
294         }
295 }
296
297 static void
298 preferences_sound_setup (EmpathyPreferences *preferences)
299 {
300         GtkTreeView *view;
301         GtkListStore *store;
302         GtkCellRenderer *renderer;
303         GtkTreeViewColumn *column;
304
305         view = GTK_TREE_VIEW (preferences->treeview_sounds);
306
307         store = gtk_list_store_new (COL_SOUND_COUNT,
308                                     G_TYPE_BOOLEAN, /* enabled */
309                                     G_TYPE_STRING,  /* name */
310                                     G_TYPE_STRING); /* key */
311
312         gtk_tree_view_set_model (view, GTK_TREE_MODEL (store));
313
314         renderer = gtk_cell_renderer_toggle_new ();
315         g_signal_connect (renderer, "toggled",
316                           G_CALLBACK (preferences_sound_cell_toggled_cb),
317                           preferences);
318
319         column = gtk_tree_view_column_new ();
320         gtk_tree_view_column_pack_start (column, renderer, FALSE);
321         gtk_tree_view_column_add_attribute (column, renderer,
322                                             "active", COL_SOUND_ENABLED);
323
324         renderer = gtk_cell_renderer_text_new ();
325         gtk_tree_view_column_pack_start (column, renderer, FALSE);
326         gtk_tree_view_column_add_attribute (column, renderer,
327                                             "text", COL_SOUND_NAME);
328
329         gtk_tree_view_append_column (view, column);
330
331         gtk_tree_view_column_set_resizable (column, FALSE);
332         gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
333
334         g_object_unref (store);
335 }
336
337 static void
338 preferences_languages_setup (EmpathyPreferences *preferences)
339 {
340         GtkTreeView       *view;
341         GtkListStore      *store;
342         GtkTreeSelection  *selection;
343         GtkTreeModel      *model;
344         GtkTreeViewColumn *column;
345         GtkCellRenderer   *renderer;
346         guint              col_offset;
347
348         view = GTK_TREE_VIEW (preferences->treeview_spell_checker);
349
350         store = gtk_list_store_new (COL_LANG_COUNT,
351                                     G_TYPE_BOOLEAN,  /* enabled */
352                                     G_TYPE_STRING,   /* code */
353                                     G_TYPE_STRING);  /* name */
354
355         gtk_tree_view_set_model (view, GTK_TREE_MODEL (store));
356
357         selection = gtk_tree_view_get_selection (view);
358         gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
359
360         model = GTK_TREE_MODEL (store);
361
362         renderer = gtk_cell_renderer_toggle_new ();
363         g_signal_connect (renderer, "toggled",
364                           G_CALLBACK (preferences_languages_cell_toggled_cb),
365                           preferences);
366
367         column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
368                                                            "active", COL_LANG_ENABLED,
369                                                            NULL);
370
371         gtk_tree_view_append_column (view, column);
372
373         renderer = gtk_cell_renderer_text_new ();
374         col_offset = gtk_tree_view_insert_column_with_attributes (view,
375                                                                   -1, _("Language"),
376                                                                   renderer,
377                                                                   "text", COL_LANG_NAME,
378                                                                   NULL);
379
380         g_object_set_data (G_OBJECT (renderer),
381                            "column", GINT_TO_POINTER (COL_LANG_NAME));
382
383         column = gtk_tree_view_get_column (view, col_offset - 1);
384         gtk_tree_view_column_set_sort_column_id (column, COL_LANG_NAME);
385         gtk_tree_view_column_set_resizable (column, FALSE);
386         gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
387
388         g_object_unref (store);
389 }
390
391 static void
392 preferences_languages_add (EmpathyPreferences *preferences)
393 {
394         GtkTreeView  *view;
395         GtkListStore *store;
396         GList        *codes, *l;
397
398         view = GTK_TREE_VIEW (preferences->treeview_spell_checker);
399         store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
400
401         codes = empathy_spell_get_language_codes ();
402
403         empathy_conf_set_bool (empathy_conf_get(),
404                                EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED,
405                                codes != NULL);
406         if (!codes) {
407                 gtk_widget_set_sensitive (preferences->treeview_spell_checker, FALSE);
408         }               
409
410         for (l = codes; l; l = l->next) {
411                 GtkTreeIter  iter;
412                 const gchar *code;
413                 const gchar *name;
414
415                 code = l->data;
416                 name = empathy_spell_get_language_name (code);
417                 if (!name) {
418                         continue;
419                 }
420
421                 gtk_list_store_append (store, &iter);
422                 gtk_list_store_set (store, &iter,
423                                     COL_LANG_CODE, code,
424                                     COL_LANG_NAME, name,
425                                     -1);
426         }
427
428         empathy_spell_free_language_codes (codes);
429 }
430
431 static void
432 preferences_languages_save (EmpathyPreferences *preferences)
433 {
434         GtkTreeView       *view;
435         GtkTreeModel      *model;
436
437         gchar             *languages = NULL;
438
439         view = GTK_TREE_VIEW (preferences->treeview_spell_checker);
440         model = gtk_tree_view_get_model (view);
441
442         gtk_tree_model_foreach (model,
443                                 (GtkTreeModelForeachFunc) preferences_languages_save_foreach,
444                                 &languages);
445
446         /* if user selects no languages, we don't want spell check */
447         empathy_conf_set_bool (empathy_conf_get (),
448                                EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED,
449                                languages != NULL);
450
451         empathy_conf_set_string (empathy_conf_get (),
452                                  EMPATHY_PREFS_CHAT_SPELL_CHECKER_LANGUAGES,
453                                  languages ? languages : "");
454
455         g_free (languages);
456 }
457
458 static gboolean
459 preferences_languages_save_foreach (GtkTreeModel  *model,
460                                     GtkTreePath   *path,
461                                     GtkTreeIter   *iter,
462                                     gchar        **languages)
463 {
464         gboolean  enabled;
465         gchar    *code;
466
467         if (!languages) {
468                 return TRUE;
469         }
470
471         gtk_tree_model_get (model, iter, COL_LANG_ENABLED, &enabled, -1);
472         if (!enabled) {
473                 return FALSE;
474         }
475
476         gtk_tree_model_get (model, iter, COL_LANG_CODE, &code, -1);
477         if (!code) {
478                 return FALSE;
479         }
480
481         if (!(*languages)) {
482                 *languages = g_strdup (code);
483         } else {
484                 gchar *str = *languages;
485                 *languages = g_strdup_printf ("%s,%s", str, code);
486                 g_free (str);
487         }
488
489         g_free (code);
490
491         return FALSE;
492 }
493
494 static void
495 preferences_languages_load (EmpathyPreferences *preferences)
496 {
497         GtkTreeView   *view;
498         GtkTreeModel  *model;
499         gchar         *value;
500         gchar        **vlanguages;
501
502         if (!empathy_conf_get_string (empathy_conf_get (),
503                                       EMPATHY_PREFS_CHAT_SPELL_CHECKER_LANGUAGES,
504                                       &value) || !value) {
505                 return;
506         }
507
508         vlanguages = g_strsplit (value, ",", -1);
509         g_free (value);
510
511         view = GTK_TREE_VIEW (preferences->treeview_spell_checker);
512         model = gtk_tree_view_get_model (view);
513
514         gtk_tree_model_foreach (model,
515                                 (GtkTreeModelForeachFunc) preferences_languages_load_foreach,
516                                 vlanguages);
517
518         g_strfreev (vlanguages);
519 }
520
521 static gboolean
522 preferences_languages_load_foreach (GtkTreeModel  *model,
523                                     GtkTreePath   *path,
524                                     GtkTreeIter   *iter,
525                                     gchar        **languages)
526 {
527         gchar    *code;
528         gchar    *lang;
529         gint      i;
530         gboolean  found = FALSE;
531
532         if (!languages) {
533                 return TRUE;
534         }
535
536         gtk_tree_model_get (model, iter, COL_LANG_CODE, &code, -1);
537         if (!code) {
538                 return FALSE;
539         }
540
541         for (i = 0, lang = languages[i]; lang; lang = languages[++i]) {
542                 if (strcmp (lang, code) == 0) {
543                         found = TRUE;
544                 }
545         }
546
547         gtk_list_store_set (GTK_LIST_STORE (model), iter, COL_LANG_ENABLED, found, -1);
548         return FALSE;
549 }
550
551 static void
552 preferences_languages_cell_toggled_cb (GtkCellRendererToggle *cell,
553                                        gchar                 *path_string,
554                                        EmpathyPreferences     *preferences)
555 {
556         GtkTreeView  *view;
557         GtkTreeModel *model;
558         GtkListStore *store;
559         GtkTreePath  *path;
560         GtkTreeIter   iter;
561         gboolean      enabled;
562
563         view = GTK_TREE_VIEW (preferences->treeview_spell_checker);
564         model = gtk_tree_view_get_model (view);
565         store = GTK_LIST_STORE (model);
566
567         path = gtk_tree_path_new_from_string (path_string);
568
569         gtk_tree_model_get_iter (model, &iter, path);
570         gtk_tree_model_get (model, &iter, COL_LANG_ENABLED, &enabled, -1);
571
572         enabled ^= 1;
573
574         gtk_list_store_set (store, &iter, COL_LANG_ENABLED, enabled, -1);
575         gtk_tree_path_free (path);
576
577         preferences_languages_save (preferences);
578 }
579
580 static void
581 preferences_themes_setup (EmpathyPreferences *preferences)
582 {
583         GtkComboBox   *combo;
584         GtkListStore  *model;
585         GtkTreeIter    iter;
586         const gchar  **themes;
587         gint           i;
588
589         combo = GTK_COMBO_BOX (preferences->combobox_chat_theme);
590
591         model = gtk_list_store_new (COL_COMBO_COUNT,
592                                     G_TYPE_STRING,
593                                     G_TYPE_STRING);
594
595         themes = empathy_theme_manager_get_themes ();
596         for (i = 0; themes[i]; i += 2) {
597                 gtk_list_store_append (model, &iter);
598                 gtk_list_store_set (model, &iter,
599                                     COL_COMBO_VISIBLE_NAME, _(themes[i + 1]),
600                                     COL_COMBO_NAME, themes[i],
601                                     -1);
602         }
603
604         gtk_combo_box_set_model (combo, GTK_TREE_MODEL (model));
605         g_object_unref (model);
606 }
607
608 static void
609 preferences_widget_sync_bool (const gchar *key, GtkWidget *widget)
610 {
611         gboolean value;
612
613         if (empathy_conf_get_bool (empathy_conf_get (), key, &value)) {
614                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), value);
615         }
616 }
617
618 static void
619 preferences_widget_sync_string (const gchar *key, GtkWidget *widget)
620 {
621         gchar *value;
622
623         if (empathy_conf_get_string (empathy_conf_get (), key, &value) && value) {
624                 if (GTK_IS_ENTRY (widget)) {
625                         gtk_entry_set_text (GTK_ENTRY (widget), value);
626                 } else if (GTK_IS_RADIO_BUTTON (widget)) {
627                         if (strcmp (key, EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM) == 0) {
628                                 GType        type;
629                                 GEnumClass  *enum_class;
630                                 GEnumValue  *enum_value;
631                                 GSList      *list;
632                                 GtkWidget   *toggle_widget;
633                                 
634                                 /* Get index from new string */
635                                 type = empathy_contact_list_store_sort_get_type ();
636                                 enum_class = G_ENUM_CLASS (g_type_class_peek (type));
637                                 enum_value = g_enum_get_value_by_nick (enum_class, value);
638                                 
639                                 if (enum_value) { 
640                                         list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
641                                         toggle_widget = g_slist_nth_data (list, enum_value->value);
642                                         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle_widget), TRUE);
643                                 }
644                         } else {
645                                 g_warning ("Unhandled key:'%s' just had string change", key);
646                         }
647                 }
648
649                 g_free (value);
650         }
651 }
652
653 static void
654 preferences_widget_sync_string_combo (const gchar *key, GtkWidget *widget)
655 {
656         gchar        *value;
657         GtkTreeModel *model;
658         GtkTreeIter   iter;
659         gboolean      found;
660
661         if (!empathy_conf_get_string (empathy_conf_get (), key, &value)) {
662                 return;
663         }
664
665         model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
666
667         found = FALSE;
668         if (value && gtk_tree_model_get_iter_first (model, &iter)) {
669                 gchar *name;
670
671                 do {
672                         gtk_tree_model_get (model, &iter,
673                                             COL_COMBO_NAME, &name,
674                                             -1);
675
676                         if (strcmp (name, value) == 0) {
677                                 found = TRUE;
678                                 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter);
679                                 break;
680                         } else {
681                                 found = FALSE;
682                         }
683
684                         g_free (name);
685                 } while (gtk_tree_model_iter_next (model, &iter));
686         }
687
688         /* Fallback to the first one. */
689         if (!found) {
690                 if (gtk_tree_model_get_iter_first (model, &iter)) {
691                         gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter);
692                 }
693         }
694
695         g_free (value);
696 }
697
698 static void
699 preferences_notify_string_cb (EmpathyConf  *conf,
700                               const gchar *key,
701                               gpointer     user_data)
702 {
703         preferences_widget_sync_string (key, user_data);
704 }
705
706 static void
707 preferences_notify_string_combo_cb (EmpathyConf  *conf,
708                                     const gchar *key,
709                                     gpointer     user_data)
710 {
711         preferences_widget_sync_string_combo (key, user_data);
712 }
713
714 static void
715 preferences_notify_bool_cb (EmpathyConf  *conf,
716                             const gchar *key,
717                             gpointer     user_data)
718 {
719         preferences_widget_sync_bool (key, user_data);
720 }
721
722 static void
723 preferences_notify_sensitivity_cb (EmpathyConf  *conf,
724                                    const gchar *key,
725                                    gpointer     user_data)
726 {
727         gboolean value;
728
729         if (empathy_conf_get_bool (conf, key, &value)) {
730                 gtk_widget_set_sensitive (GTK_WIDGET (user_data), value);
731         }
732 }
733
734 #if 0
735 static void
736 preferences_widget_sync_int (const gchar *key, GtkWidget *widget)
737 {
738         gint value;
739
740         if (empathy_conf_get_int (empathy_conf_get (), key, &value)) {
741                 if (GTK_IS_SPIN_BUTTON (widget)) {
742                         gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
743                 }
744         }
745 }
746
747 static void
748 preferences_notify_int_cb (EmpathyConf  *conf,
749                            const gchar *key,
750                            gpointer     user_data)
751 {
752         preferences_widget_sync_int (key, user_data);   
753 }
754
755 static void
756 preferences_hookup_spin_button (EmpathyPreferences *preferences,
757                                 const gchar       *key,
758                                 GtkWidget         *widget)
759 {
760         guint id;
761
762         preferences_widget_sync_int (key, widget);
763
764         g_object_set_data_full (G_OBJECT (widget), "key",
765                                 g_strdup (key), g_free);
766
767         g_signal_connect (widget,
768                           "value_changed",
769                           G_CALLBACK (preferences_spin_button_value_changed_cb),
770                           NULL);
771
772         id = empathy_conf_notify_add (empathy_conf_get (),
773                                       key,
774                                       preferences_notify_int_cb,
775                                       widget);
776         if (id) {
777                 preferences_add_id (preferences, id);
778         }
779 }
780
781 static void
782 preferences_hookup_entry (EmpathyPreferences *preferences,
783                           const gchar       *key,
784                           GtkWidget         *widget)
785 {
786         guint id;
787
788         preferences_widget_sync_string (key, widget);
789
790         g_object_set_data_full (G_OBJECT (widget), "key",
791                                 g_strdup (key), g_free);
792
793         g_signal_connect (widget,
794                           "changed",
795                           G_CALLBACK (preferences_entry_value_changed_cb),
796                           NULL);
797
798         id = empathy_conf_notify_add (empathy_conf_get (),
799                                       key,
800                                       preferences_notify_string_cb,
801                                       widget);
802         if (id) {
803                 preferences_add_id (preferences, id);
804         }
805 }
806
807 static void
808 preferences_spin_button_value_changed_cb (GtkWidget *button,
809                                           gpointer   user_data)
810 {
811         const gchar *key;
812
813         key = g_object_get_data (G_OBJECT (button), "key");
814
815         empathy_conf_set_int (empathy_conf_get (),
816                               key,
817                               gtk_spin_button_get_value (GTK_SPIN_BUTTON (button)));
818 }
819
820 static void
821 preferences_entry_value_changed_cb (GtkWidget *entry,
822                                     gpointer   user_data)
823 {
824         const gchar *key;
825
826         key = g_object_get_data (G_OBJECT (entry), "key");
827
828         empathy_conf_set_string (empathy_conf_get (),
829                                  key,
830                                  gtk_entry_get_text (GTK_ENTRY (entry)));
831 }
832 #endif
833
834 static void
835 preferences_hookup_toggle_button (EmpathyPreferences *preferences,
836                                   const gchar       *key,
837                                   GtkWidget         *widget)
838 {
839         guint id;
840
841         preferences_widget_sync_bool (key, widget);
842
843         g_object_set_data_full (G_OBJECT (widget), "key",
844                                 g_strdup (key), g_free);
845
846         g_signal_connect (widget,
847                           "toggled",
848                           G_CALLBACK (preferences_toggle_button_toggled_cb),
849                           NULL);
850
851         id = empathy_conf_notify_add (empathy_conf_get (),
852                                      key,
853                                      preferences_notify_bool_cb,
854                                      widget);
855         if (id) {
856                 preferences_add_id (preferences, id);
857         }
858 }
859
860 static void
861 preferences_hookup_radio_button (EmpathyPreferences *preferences,
862                                  const gchar       *key,
863                                  GtkWidget         *widget)
864 {
865         GSList *group, *l;
866         guint   id;
867
868         preferences_widget_sync_string (key, widget);
869
870         group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
871         for (l = group; l; l = l->next) {
872                 g_signal_connect (l->data,
873                                   "toggled",
874                                   G_CALLBACK (preferences_radio_button_toggled_cb),
875                                   NULL);
876
877                 g_object_set_data_full (G_OBJECT (l->data), "key",
878                                         g_strdup (key), g_free);
879         }
880
881         id = empathy_conf_notify_add (empathy_conf_get (),
882                                      key,
883                                      preferences_notify_string_cb,
884                                      widget);
885         if (id) {
886                 preferences_add_id (preferences, id);
887         }
888 }
889
890 static void
891 preferences_hookup_string_combo (EmpathyPreferences *preferences,
892                                  const gchar       *key,
893                                  GtkWidget         *widget)
894 {
895         guint id;
896
897         preferences_widget_sync_string_combo (key, widget);
898
899         g_object_set_data_full (G_OBJECT (widget), "key",
900                                 g_strdup (key), g_free);
901
902         g_signal_connect (widget,
903                           "changed",
904                           G_CALLBACK (preferences_string_combo_changed_cb),
905                           NULL);
906
907         id = empathy_conf_notify_add (empathy_conf_get (),
908                                       key,
909                                       preferences_notify_string_combo_cb,
910                                       widget);
911         if (id) {
912                 preferences_add_id (preferences, id);
913         }
914 }
915
916 static void
917 preferences_hookup_sensitivity (EmpathyPreferences *preferences,
918                                 const gchar       *key,
919                                 GtkWidget         *widget)
920 {
921         gboolean value;
922         guint    id;
923
924         if (empathy_conf_get_bool (empathy_conf_get (), key, &value)) {
925                 gtk_widget_set_sensitive (widget, value);
926         }
927
928         id = empathy_conf_notify_add (empathy_conf_get (),
929                                       key,
930                                       preferences_notify_sensitivity_cb,
931                                       widget);
932         if (id) {
933                 preferences_add_id (preferences, id);
934         }
935 }
936
937 static void
938 preferences_toggle_button_toggled_cb (GtkWidget *button,
939                                       gpointer   user_data)
940 {
941         const gchar *key;
942
943         key = g_object_get_data (G_OBJECT (button), "key");
944
945         empathy_conf_set_bool (empathy_conf_get (),
946                                key,
947                                gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)));
948 }
949
950 static void
951 preferences_radio_button_toggled_cb (GtkWidget *button,
952                                      gpointer   user_data)
953 {
954         const gchar *key;
955         const gchar *value = NULL;
956
957         if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
958                 return;
959         }
960
961         key = g_object_get_data (G_OBJECT (button), "key");
962
963         if (key && strcmp (key, EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM) == 0) {
964                 GSList      *group;
965                 GType        type;
966                 GEnumClass  *enum_class;
967                 GEnumValue  *enum_value;
968                 
969                 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
970                 
971                 /* Get string from index */
972                 type = empathy_contact_list_store_sort_get_type ();
973                 enum_class = G_ENUM_CLASS (g_type_class_peek (type));
974                 enum_value = g_enum_get_value (enum_class, g_slist_index (group, button));
975                 
976                 if (!enum_value) {
977                         g_warning ("No GEnumValue for EmpathyContactListSort with GtkRadioButton index:%d", 
978                                    g_slist_index (group, button));
979                         return;
980                 }
981
982                 value = enum_value->value_nick;
983         }
984
985         empathy_conf_set_string (empathy_conf_get (), key, value);
986 }
987
988 static void
989 preferences_string_combo_changed_cb (GtkWidget *combo,
990                                      gpointer   user_data)
991 {
992         const gchar  *key;
993         GtkTreeModel *model;
994         GtkTreeIter   iter;
995         gchar        *name;
996
997         key = g_object_get_data (G_OBJECT (combo), "key");
998
999         if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter)) {
1000                 model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
1001
1002                 gtk_tree_model_get (model, &iter,
1003                                     COL_COMBO_NAME, &name,
1004                                     -1);
1005                 empathy_conf_set_string (empathy_conf_get (), key, name);
1006                 g_free (name);
1007         }
1008 }
1009
1010 static void
1011 preferences_response_cb (GtkWidget         *widget,
1012                          gint               response,
1013                          EmpathyPreferences *preferences)
1014 {
1015         gtk_widget_destroy (widget);
1016 }
1017
1018 static void
1019 preferences_destroy_cb (GtkWidget         *widget,
1020                         EmpathyPreferences *preferences)
1021 {
1022         GList *l;
1023
1024         for (l = preferences->notify_ids; l; l = l->next) {
1025                 guint id;
1026
1027                 id = GPOINTER_TO_UINT (l->data);
1028                 empathy_conf_notify_remove (empathy_conf_get (), id);
1029         }
1030
1031         g_list_free (preferences->notify_ids);
1032         g_free (preferences);
1033 }
1034
1035 GtkWidget *
1036 empathy_preferences_show (GtkWindow *parent)
1037 {
1038         static EmpathyPreferences *preferences;
1039         GladeXML                 *glade;
1040         gchar                    *filename;
1041
1042         if (preferences) {
1043                 gtk_window_present (GTK_WINDOW (preferences->dialog));
1044                 return preferences->dialog;
1045         }
1046
1047         preferences = g_new0 (EmpathyPreferences, 1);
1048
1049         filename = empathy_file_lookup ("empathy-preferences.glade", "src");
1050         glade = empathy_glade_get_file (filename,
1051                 "preferences_dialog",
1052                 NULL,
1053                 "preferences_dialog", &preferences->dialog,
1054                 "notebook", &preferences->notebook,
1055                 "checkbutton_show_avatars", &preferences->checkbutton_show_avatars,
1056                 "checkbutton_compact_contact_list", &preferences->checkbutton_compact_contact_list,
1057                 "checkbutton_show_smileys", &preferences->checkbutton_show_smileys,
1058                 "combobox_chat_theme", &preferences->combobox_chat_theme,
1059                 "checkbutton_separate_chat_windows", &preferences->checkbutton_separate_chat_windows,
1060                 "checkbutton_autoconnect", &preferences->checkbutton_autoconnect,
1061                 "radiobutton_contact_list_sort_by_name", &preferences->radiobutton_contact_list_sort_by_name,
1062                 "radiobutton_contact_list_sort_by_state", &preferences->radiobutton_contact_list_sort_by_state,
1063                 "checkbutton_sounds_enabled", &preferences->checkbutton_sounds_enabled,
1064                 "checkbutton_sounds_disabled_away", &preferences->checkbutton_sounds_disabled_away,
1065                 "treeview_sounds", &preferences->treeview_sounds,
1066                 "treeview_spell_checker", &preferences->treeview_spell_checker,
1067                 NULL);
1068         g_free (filename);
1069
1070         empathy_glade_connect (glade,
1071                               preferences,
1072                               "preferences_dialog", "destroy", preferences_destroy_cb,
1073                               "preferences_dialog", "response", preferences_response_cb,
1074                               NULL);
1075
1076         g_object_unref (glade);
1077
1078         g_object_add_weak_pointer (G_OBJECT (preferences->dialog), (gpointer) &preferences);
1079
1080         preferences_themes_setup (preferences);
1081
1082         preferences_setup_widgets (preferences);
1083
1084         preferences_languages_setup (preferences);
1085         preferences_languages_add (preferences);
1086         preferences_languages_load (preferences);
1087
1088         preferences_sound_setup (preferences);
1089         preferences_sound_load (preferences);
1090
1091         if (empathy_spell_supported ()) {
1092                 GtkWidget *page;
1093
1094                 page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (preferences->notebook), 2);
1095                 gtk_widget_show (page);
1096         }
1097
1098         if (parent) {
1099                 gtk_window_set_transient_for (GTK_WINDOW (preferences->dialog),
1100                                               GTK_WINDOW (parent));
1101         }
1102
1103         gtk_widget_show (preferences->dialog);
1104
1105         return preferences->dialog;
1106 }
1107