a8b52954d598faab9fa441ed16614287456d591b
[empathy.git] / libempathy-gtk / 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-conf.h>
34
35 #include "empathy-preferences.h"
36 #include "empathy-ui-utils.h"
37 #include "empathy-theme-manager.h"
38 #include "empathy-spell.h"
39 #include "empathy-contact-list-store.h"
40 #include "empathy-gtk-enum-types.h"
41
42 typedef struct {
43         GtkWidget *dialog;
44
45         GtkWidget *notebook;
46
47         GtkWidget *checkbutton_show_avatars;
48         GtkWidget *checkbutton_compact_contact_list;
49         GtkWidget *checkbutton_show_smileys;
50         GtkWidget *combobox_chat_theme;
51         GtkWidget *checkbutton_theme_chat_room;
52         GtkWidget *checkbutton_separate_chat_windows;
53         GtkWidget *radiobutton_contact_list_sort_by_name;
54         GtkWidget *radiobutton_contact_list_sort_by_state;
55
56         GtkWidget *checkbutton_sounds_for_messages;
57         GtkWidget *checkbutton_sounds_when_busy;
58         GtkWidget *checkbutton_sounds_when_away;
59         GtkWidget *checkbutton_popups_when_available;
60
61         GtkWidget *treeview_spell_checker;
62
63         GList     *notify_ids;
64 } EmpathyPreferences;
65
66 static void     preferences_setup_widgets                (EmpathyPreferences      *preferences);
67 static void     preferences_languages_setup              (EmpathyPreferences      *preferences);
68 static void     preferences_languages_add                (EmpathyPreferences      *preferences);
69 static void     preferences_languages_save               (EmpathyPreferences      *preferences);
70 static gboolean preferences_languages_save_foreach       (GtkTreeModel           *model,
71                                                           GtkTreePath            *path,
72                                                           GtkTreeIter            *iter,
73                                                           gchar                 **languages);
74 static void     preferences_languages_load               (EmpathyPreferences      *preferences);
75 static gboolean preferences_languages_load_foreach       (GtkTreeModel           *model,
76                                                           GtkTreePath            *path,
77                                                           GtkTreeIter            *iter,
78                                                           gchar                 **languages);
79 static void     preferences_languages_cell_toggled_cb    (GtkCellRendererToggle  *cell,
80                                                           gchar                  *path_string,
81                                                           EmpathyPreferences      *preferences);
82 static void     preferences_themes_setup                 (EmpathyPreferences      *preferences);
83 static void     preferences_widget_sync_bool             (const gchar            *key,
84                                                           GtkWidget              *widget);
85 static void     preferences_widget_sync_int              (const gchar            *key,
86                                                           GtkWidget              *widget);
87 static void     preferences_widget_sync_string           (const gchar            *key,
88                                                           GtkWidget              *widget);
89 static void     preferences_widget_sync_string_combo     (const gchar            *key,
90                                                           GtkWidget              *widget);
91 static void     preferences_notify_int_cb                (EmpathyConf             *conf,
92                                                           const gchar            *key,
93                                                           gpointer                user_data);
94 static void     preferences_notify_string_cb             (EmpathyConf             *conf,
95                                                           const gchar            *key,
96                                                           gpointer                user_data);
97 static void     preferences_notify_string_combo_cb       (EmpathyConf             *conf,
98                                                           const gchar            *key,
99                                                           gpointer                user_data);
100 static void     preferences_notify_bool_cb               (EmpathyConf             *conf,
101                                                           const gchar            *key,
102                                                           gpointer                user_data);
103 static void     preferences_notify_sensitivity_cb        (EmpathyConf             *conf,
104                                                           const gchar            *key,
105                                                           gpointer                user_data);
106 static void     preferences_hookup_spin_button           (EmpathyPreferences      *preferences,
107                                                           const gchar            *key,
108                                                           GtkWidget              *widget);
109 static void     preferences_hookup_entry                 (EmpathyPreferences      *preferences,
110                                                           const gchar            *key,
111                                                           GtkWidget              *widget);
112 static void     preferences_hookup_toggle_button         (EmpathyPreferences      *preferences,
113                                                           const gchar            *key,
114                                                           GtkWidget              *widget);
115 static void     preferences_hookup_radio_button          (EmpathyPreferences      *preferences,
116                                                           const gchar            *key,
117                                                           GtkWidget              *widget);
118 static void     preferences_hookup_string_combo          (EmpathyPreferences      *preferences,
119                                                           const gchar            *key,
120                                                           GtkWidget              *widget);
121 static void     preferences_hookup_sensitivity           (EmpathyPreferences      *preferences,
122                                                           const gchar            *key,
123                                                           GtkWidget              *widget);
124 static void     preferences_spin_button_value_changed_cb (GtkWidget              *button,
125                                                           gpointer                user_data);
126 static void     preferences_entry_value_changed_cb       (GtkWidget              *entry,
127                                                           gpointer                user_data);
128 static void     preferences_toggle_button_toggled_cb     (GtkWidget              *button,
129                                                           gpointer                user_data);
130 static void     preferences_radio_button_toggled_cb      (GtkWidget              *button,
131                                                           gpointer                user_data);
132 static void     preferences_string_combo_changed_cb      (GtkWidget *button,
133                                                           gpointer                user_data);
134 static void     preferences_destroy_cb                   (GtkWidget              *widget,
135                                                           EmpathyPreferences      *preferences);
136 static void     preferences_response_cb                  (GtkWidget              *widget,
137                                                           gint                    response,
138                                                           EmpathyPreferences      *preferences);
139
140 enum {
141         COL_LANG_ENABLED,
142         COL_LANG_CODE,
143         COL_LANG_NAME,
144         COL_LANG_COUNT
145 };
146
147 enum {
148         COL_COMBO_VISIBLE_NAME,
149         COL_COMBO_NAME,
150         COL_COMBO_COUNT
151 };
152
153 static void
154 preferences_setup_widgets (EmpathyPreferences *preferences)
155 {
156         preferences_hookup_toggle_button (preferences,
157                                           EMPATHY_PREFS_SOUNDS_FOR_MESSAGES,
158                                           preferences->checkbutton_sounds_for_messages);
159         preferences_hookup_toggle_button (preferences,
160                                           EMPATHY_PREFS_SOUNDS_WHEN_AWAY,
161                                           preferences->checkbutton_sounds_when_away);
162         preferences_hookup_toggle_button (preferences,
163                                           EMPATHY_PREFS_SOUNDS_WHEN_BUSY,
164                                           preferences->checkbutton_sounds_when_busy);
165         preferences_hookup_toggle_button (preferences,
166                                           EMPATHY_PREFS_POPUPS_WHEN_AVAILABLE,
167                                           preferences->checkbutton_popups_when_available);
168
169         preferences_hookup_sensitivity (preferences,
170                                         EMPATHY_PREFS_SOUNDS_FOR_MESSAGES,
171                                         preferences->checkbutton_sounds_when_away);
172         preferences_hookup_sensitivity (preferences,
173                                         EMPATHY_PREFS_SOUNDS_FOR_MESSAGES,
174                                         preferences->checkbutton_sounds_when_busy);
175
176         preferences_hookup_toggle_button (preferences,
177                                           EMPATHY_PREFS_UI_SEPARATE_CHAT_WINDOWS,
178                                           preferences->checkbutton_separate_chat_windows);
179
180         preferences_hookup_toggle_button (preferences,
181                                           EMPATHY_PREFS_UI_SHOW_AVATARS,
182                                           preferences->checkbutton_show_avatars);
183
184         preferences_hookup_toggle_button (preferences,
185                                           EMPATHY_PREFS_UI_COMPACT_CONTACT_LIST,
186                                           preferences->checkbutton_compact_contact_list);
187
188         preferences_hookup_toggle_button (preferences,
189                                           EMPATHY_PREFS_CHAT_SHOW_SMILEYS,
190                                           preferences->checkbutton_show_smileys);
191
192         preferences_hookup_string_combo (preferences,
193                                          EMPATHY_PREFS_CHAT_THEME,
194                                          preferences->combobox_chat_theme);
195
196         preferences_hookup_toggle_button (preferences,
197                                           EMPATHY_PREFS_CHAT_THEME_CHAT_ROOM,
198                                           preferences->checkbutton_theme_chat_room);
199
200         preferences_hookup_radio_button (preferences,
201                                          EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM,
202                                          preferences->radiobutton_contact_list_sort_by_name);
203 }
204
205 static void
206 preferences_languages_setup (EmpathyPreferences *preferences)
207 {
208         GtkTreeView       *view;
209         GtkListStore      *store;
210         GtkTreeSelection  *selection;
211         GtkTreeModel      *model;
212         GtkTreeViewColumn *column;
213         GtkCellRenderer   *renderer;
214         guint              col_offset;
215
216         view = GTK_TREE_VIEW (preferences->treeview_spell_checker);
217
218         store = gtk_list_store_new (COL_LANG_COUNT,
219                                     G_TYPE_BOOLEAN,  /* enabled */
220                                     G_TYPE_STRING,   /* code */
221                                     G_TYPE_STRING);  /* name */
222
223         gtk_tree_view_set_model (view, GTK_TREE_MODEL (store));
224
225         selection = gtk_tree_view_get_selection (view);
226         gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
227
228         model = GTK_TREE_MODEL (store);
229
230         renderer = gtk_cell_renderer_toggle_new ();
231         g_signal_connect (renderer, "toggled",
232                           G_CALLBACK (preferences_languages_cell_toggled_cb),
233                           preferences);
234
235         column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
236                                                            "active", COL_LANG_ENABLED,
237                                                            NULL);
238
239         gtk_tree_view_append_column (view, column);
240
241         renderer = gtk_cell_renderer_text_new ();
242         col_offset = gtk_tree_view_insert_column_with_attributes (view,
243                                                                   -1, _("Language"),
244                                                                   renderer,
245                                                                   "text", COL_LANG_NAME,
246                                                                   NULL);
247
248         g_object_set_data (G_OBJECT (renderer),
249                            "column", GINT_TO_POINTER (COL_LANG_NAME));
250
251         column = gtk_tree_view_get_column (view, col_offset - 1);
252         gtk_tree_view_column_set_sort_column_id (column, COL_LANG_NAME);
253         gtk_tree_view_column_set_resizable (column, FALSE);
254         gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
255
256         g_object_unref (store);
257 }
258
259 static void
260 preferences_languages_add (EmpathyPreferences *preferences)
261 {
262         GtkTreeView  *view;
263         GtkListStore *store;
264         GList        *codes, *l;
265
266         view = GTK_TREE_VIEW (preferences->treeview_spell_checker);
267         store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
268
269         codes = empathy_spell_get_language_codes ();
270
271         empathy_conf_set_bool (empathy_conf_get(),
272                                EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED,
273                                codes != NULL);
274         if (!codes) {
275                 gtk_widget_set_sensitive (preferences->treeview_spell_checker, FALSE);
276         }               
277
278         for (l = codes; l; l = l->next) {
279                 GtkTreeIter  iter;
280                 const gchar *code;
281                 const gchar *name;
282
283                 code = l->data;
284                 name = empathy_spell_get_language_name (code);
285                 if (!name) {
286                         continue;
287                 }
288
289                 gtk_list_store_append (store, &iter);
290                 gtk_list_store_set (store, &iter,
291                                     COL_LANG_CODE, code,
292                                     COL_LANG_NAME, name,
293                                     -1);
294         }
295
296         empathy_spell_free_language_codes (codes);
297 }
298
299 static void
300 preferences_languages_save (EmpathyPreferences *preferences)
301 {
302         GtkTreeView       *view;
303         GtkTreeModel      *model;
304
305         gchar             *languages = NULL;
306
307         view = GTK_TREE_VIEW (preferences->treeview_spell_checker);
308         model = gtk_tree_view_get_model (view);
309
310         gtk_tree_model_foreach (model,
311                                 (GtkTreeModelForeachFunc) preferences_languages_save_foreach,
312                                 &languages);
313
314         /* if user selects no languages, we don't want spell check */
315         empathy_conf_set_bool (empathy_conf_get (),
316                                EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED,
317                                languages != NULL);
318
319         empathy_conf_set_string (empathy_conf_get (),
320                                  EMPATHY_PREFS_CHAT_SPELL_CHECKER_LANGUAGES,
321                                  languages ? languages : "");
322
323         g_free (languages);
324 }
325
326 static gboolean
327 preferences_languages_save_foreach (GtkTreeModel  *model,
328                                     GtkTreePath   *path,
329                                     GtkTreeIter   *iter,
330                                     gchar        **languages)
331 {
332         gboolean  enabled;
333         gchar    *code;
334
335         if (!languages) {
336                 return TRUE;
337         }
338
339         gtk_tree_model_get (model, iter, COL_LANG_ENABLED, &enabled, -1);
340         if (!enabled) {
341                 return FALSE;
342         }
343
344         gtk_tree_model_get (model, iter, COL_LANG_CODE, &code, -1);
345         if (!code) {
346                 return FALSE;
347         }
348
349         if (!(*languages)) {
350                 *languages = g_strdup (code);
351         } else {
352                 gchar *str = *languages;
353                 *languages = g_strdup_printf ("%s,%s", str, code);
354                 g_free (str);
355         }
356
357         g_free (code);
358
359         return FALSE;
360 }
361
362 static void
363 preferences_languages_load (EmpathyPreferences *preferences)
364 {
365         GtkTreeView   *view;
366         GtkTreeModel  *model;
367         gchar         *value;
368         gchar        **vlanguages;
369
370         if (!empathy_conf_get_string (empathy_conf_get (),
371                                       EMPATHY_PREFS_CHAT_SPELL_CHECKER_LANGUAGES,
372                                       &value) || !value) {
373                 return;
374         }
375
376         vlanguages = g_strsplit (value, ",", -1);
377         g_free (value);
378
379         view = GTK_TREE_VIEW (preferences->treeview_spell_checker);
380         model = gtk_tree_view_get_model (view);
381
382         gtk_tree_model_foreach (model,
383                                 (GtkTreeModelForeachFunc) preferences_languages_load_foreach,
384                                 vlanguages);
385
386         g_strfreev (vlanguages);
387 }
388
389 static gboolean
390 preferences_languages_load_foreach (GtkTreeModel  *model,
391                                     GtkTreePath   *path,
392                                     GtkTreeIter   *iter,
393                                     gchar        **languages)
394 {
395         gchar    *code;
396         gchar    *lang;
397         gint      i;
398         gboolean  found = FALSE;
399
400         if (!languages) {
401                 return TRUE;
402         }
403
404         gtk_tree_model_get (model, iter, COL_LANG_CODE, &code, -1);
405         if (!code) {
406                 return FALSE;
407         }
408
409         for (i = 0, lang = languages[i]; lang; lang = languages[++i]) {
410                 if (strcmp (lang, code) == 0) {
411                         found = TRUE;
412                 }
413         }
414
415         gtk_list_store_set (GTK_LIST_STORE (model), iter, COL_LANG_ENABLED, found, -1);
416         return FALSE;
417 }
418
419 static void
420 preferences_languages_cell_toggled_cb (GtkCellRendererToggle *cell,
421                                        gchar                 *path_string,
422                                        EmpathyPreferences     *preferences)
423 {
424         GtkTreeView  *view;
425         GtkTreeModel *model;
426         GtkListStore *store;
427         GtkTreePath  *path;
428         GtkTreeIter   iter;
429         gboolean      enabled;
430
431         view = GTK_TREE_VIEW (preferences->treeview_spell_checker);
432         model = gtk_tree_view_get_model (view);
433         store = GTK_LIST_STORE (model);
434
435         path = gtk_tree_path_new_from_string (path_string);
436
437         gtk_tree_model_get_iter (model, &iter, path);
438         gtk_tree_model_get (model, &iter, COL_LANG_ENABLED, &enabled, -1);
439
440         enabled ^= 1;
441
442         gtk_list_store_set (store, &iter, COL_LANG_ENABLED, enabled, -1);
443         gtk_tree_path_free (path);
444
445         preferences_languages_save (preferences);
446 }
447
448 static void
449 preferences_themes_setup (EmpathyPreferences *preferences)
450 {
451         GtkComboBox   *combo;
452         GtkListStore  *model;
453         GtkTreeIter    iter;
454         const gchar  **themes;
455         gint           i;
456
457         combo = GTK_COMBO_BOX (preferences->combobox_chat_theme);
458
459         model = gtk_list_store_new (COL_COMBO_COUNT,
460                                     G_TYPE_STRING,
461                                     G_TYPE_STRING);
462
463         themes = empathy_theme_manager_get_themes ();
464         for (i = 0; themes[i]; i += 2) {
465                 gtk_list_store_append (model, &iter);
466                 gtk_list_store_set (model, &iter,
467                                     COL_COMBO_VISIBLE_NAME, _(themes[i + 1]),
468                                     COL_COMBO_NAME, themes[i],
469                                     -1);
470         }
471
472         gtk_combo_box_set_model (combo, GTK_TREE_MODEL (model));
473         g_object_unref (model);
474 }
475
476 static void
477 preferences_widget_sync_bool (const gchar *key, GtkWidget *widget)
478 {
479         gboolean value;
480
481         if (empathy_conf_get_bool (empathy_conf_get (), key, &value)) {
482                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), value);
483         }
484 }
485
486 static void
487 preferences_widget_sync_int (const gchar *key, GtkWidget *widget)
488 {
489         gint value;
490
491         if (empathy_conf_get_int (empathy_conf_get (), key, &value)) {
492                 if (GTK_IS_SPIN_BUTTON (widget)) {
493                         gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
494                 }
495         }
496 }
497
498 static void
499 preferences_widget_sync_string (const gchar *key, GtkWidget *widget)
500 {
501         gchar *value;
502
503         if (empathy_conf_get_string (empathy_conf_get (), key, &value) && value) {
504                 if (GTK_IS_ENTRY (widget)) {
505                         gtk_entry_set_text (GTK_ENTRY (widget), value);
506                 } else if (GTK_IS_RADIO_BUTTON (widget)) {
507                         if (strcmp (key, EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM) == 0) {
508                                 GType        type;
509                                 GEnumClass  *enum_class;
510                                 GEnumValue  *enum_value;
511                                 GSList      *list;
512                                 GtkWidget   *toggle_widget;
513                                 
514                                 /* Get index from new string */
515                                 type = empathy_contact_list_store_sort_get_type ();
516                                 enum_class = G_ENUM_CLASS (g_type_class_peek (type));
517                                 enum_value = g_enum_get_value_by_nick (enum_class, value);
518                                 
519                                 if (enum_value) { 
520                                         list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
521                                         toggle_widget = g_slist_nth_data (list, enum_value->value);
522                                         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle_widget), TRUE);
523                                 }
524                         } else {
525                                 g_warning ("Unhandled key:'%s' just had string change", key);
526                         }
527                 }
528
529                 g_free (value);
530         }
531 }
532
533 static void
534 preferences_widget_sync_string_combo (const gchar *key, GtkWidget *widget)
535 {
536         gchar        *value;
537         GtkTreeModel *model;
538         GtkTreeIter   iter;
539         gboolean      found;
540
541         if (!empathy_conf_get_string (empathy_conf_get (), key, &value)) {
542                 return;
543         }
544
545         model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
546
547         found = FALSE;
548         if (value && gtk_tree_model_get_iter_first (model, &iter)) {
549                 gchar *name;
550
551                 do {
552                         gtk_tree_model_get (model, &iter,
553                                             COL_COMBO_NAME, &name,
554                                             -1);
555
556                         if (strcmp (name, value) == 0) {
557                                 found = TRUE;
558                                 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter);
559                                 break;
560                         } else {
561                                 found = FALSE;
562                         }
563
564                         g_free (name);
565                 } while (gtk_tree_model_iter_next (model, &iter));
566         }
567
568         /* Fallback to the first one. */
569         if (!found) {
570                 if (gtk_tree_model_get_iter_first (model, &iter)) {
571                         gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter);
572                 }
573         }
574
575         g_free (value);
576 }
577
578 static void
579 preferences_notify_int_cb (EmpathyConf  *conf,
580                            const gchar *key,
581                            gpointer     user_data)
582 {
583         preferences_widget_sync_int (key, user_data);   
584 }
585
586 static void
587 preferences_notify_string_cb (EmpathyConf  *conf,
588                               const gchar *key,
589                               gpointer     user_data)
590 {
591         preferences_widget_sync_string (key, user_data);
592 }
593
594 static void
595 preferences_notify_string_combo_cb (EmpathyConf  *conf,
596                                     const gchar *key,
597                                     gpointer     user_data)
598 {
599         preferences_widget_sync_string_combo (key, user_data);
600 }
601
602 static void
603 preferences_notify_bool_cb (EmpathyConf  *conf,
604                             const gchar *key,
605                             gpointer     user_data)
606 {
607         preferences_widget_sync_bool (key, user_data);
608 }
609
610 static void
611 preferences_notify_sensitivity_cb (EmpathyConf  *conf,
612                                    const gchar *key,
613                                    gpointer     user_data)
614 {
615         gboolean value;
616
617         if (empathy_conf_get_bool (conf, key, &value)) {
618                 gtk_widget_set_sensitive (GTK_WIDGET (user_data), value);
619         }
620 }
621
622 static void
623 preferences_add_id (EmpathyPreferences *preferences, guint id)
624 {
625         preferences->notify_ids = g_list_prepend (preferences->notify_ids,
626                                                   GUINT_TO_POINTER (id));
627 }
628
629 static void
630 preferences_hookup_spin_button (EmpathyPreferences *preferences,
631                                 const gchar       *key,
632                                 GtkWidget         *widget)
633 {
634         guint id;
635
636         /* Silence warning. */
637         if (0) {
638                 preferences_hookup_spin_button (preferences, key, widget);
639         }
640
641         preferences_widget_sync_int (key, widget);
642
643         g_object_set_data_full (G_OBJECT (widget), "key",
644                                 g_strdup (key), g_free);
645
646         g_signal_connect (widget,
647                           "value_changed",
648                           G_CALLBACK (preferences_spin_button_value_changed_cb),
649                           NULL);
650
651         id = empathy_conf_notify_add (empathy_conf_get (),
652                                       key,
653                                       preferences_notify_int_cb,
654                                       widget);
655         if (id) {
656                 preferences_add_id (preferences, id);
657         }
658 }
659
660 static void
661 preferences_hookup_entry (EmpathyPreferences *preferences,
662                           const gchar       *key,
663                           GtkWidget         *widget)
664 {
665         guint id;
666
667         if (0) {  /* Silent warning before we use this function. */
668                 preferences_hookup_entry (preferences, key, widget);
669         }
670
671         preferences_widget_sync_string (key, widget);
672
673         g_object_set_data_full (G_OBJECT (widget), "key",
674                                 g_strdup (key), g_free);
675
676         g_signal_connect (widget,
677                           "changed",
678                           G_CALLBACK (preferences_entry_value_changed_cb),
679                           NULL);
680
681         id = empathy_conf_notify_add (empathy_conf_get (),
682                                       key,
683                                       preferences_notify_string_cb,
684                                       widget);
685         if (id) {
686                 preferences_add_id (preferences, id);
687         }
688 }
689
690 static void
691 preferences_hookup_toggle_button (EmpathyPreferences *preferences,
692                                   const gchar       *key,
693                                   GtkWidget         *widget)
694 {
695         guint id;
696
697         preferences_widget_sync_bool (key, widget);
698
699         g_object_set_data_full (G_OBJECT (widget), "key",
700                                 g_strdup (key), g_free);
701
702         g_signal_connect (widget,
703                           "toggled",
704                           G_CALLBACK (preferences_toggle_button_toggled_cb),
705                           NULL);
706
707         id = empathy_conf_notify_add (empathy_conf_get (),
708                                      key,
709                                      preferences_notify_bool_cb,
710                                      widget);
711         if (id) {
712                 preferences_add_id (preferences, id);
713         }
714 }
715
716 static void
717 preferences_hookup_radio_button (EmpathyPreferences *preferences,
718                                  const gchar       *key,
719                                  GtkWidget         *widget)
720 {
721         GSList *group, *l;
722         guint   id;
723
724         preferences_widget_sync_string (key, widget);
725
726         group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
727         for (l = group; l; l = l->next) {
728                 g_signal_connect (l->data,
729                                   "toggled",
730                                   G_CALLBACK (preferences_radio_button_toggled_cb),
731                                   NULL);
732
733                 g_object_set_data_full (G_OBJECT (l->data), "key",
734                                         g_strdup (key), g_free);
735         }
736
737         id = empathy_conf_notify_add (empathy_conf_get (),
738                                      key,
739                                      preferences_notify_string_cb,
740                                      widget);
741         if (id) {
742                 preferences_add_id (preferences, id);
743         }
744 }
745
746 static void
747 preferences_hookup_string_combo (EmpathyPreferences *preferences,
748                                  const gchar       *key,
749                                  GtkWidget         *widget)
750 {
751         guint id;
752
753         preferences_widget_sync_string_combo (key, widget);
754
755         g_object_set_data_full (G_OBJECT (widget), "key",
756                                 g_strdup (key), g_free);
757
758         g_signal_connect (widget,
759                           "changed",
760                           G_CALLBACK (preferences_string_combo_changed_cb),
761                           NULL);
762
763         id = empathy_conf_notify_add (empathy_conf_get (),
764                                       key,
765                                       preferences_notify_string_combo_cb,
766                                       widget);
767         if (id) {
768                 preferences_add_id (preferences, id);
769         }
770 }
771
772 static void
773 preferences_hookup_sensitivity (EmpathyPreferences *preferences,
774                                 const gchar       *key,
775                                 GtkWidget         *widget)
776 {
777         gboolean value;
778         guint    id;
779
780         if (empathy_conf_get_bool (empathy_conf_get (), key, &value)) {
781                 gtk_widget_set_sensitive (widget, value);
782         }
783
784         id = empathy_conf_notify_add (empathy_conf_get (),
785                                       key,
786                                       preferences_notify_sensitivity_cb,
787                                       widget);
788         if (id) {
789                 preferences_add_id (preferences, id);
790         }
791 }
792
793 static void
794 preferences_spin_button_value_changed_cb (GtkWidget *button,
795                                           gpointer   user_data)
796 {
797         const gchar *key;
798
799         key = g_object_get_data (G_OBJECT (button), "key");
800
801         empathy_conf_set_int (empathy_conf_get (),
802                               key,
803                               gtk_spin_button_get_value (GTK_SPIN_BUTTON (button)));
804 }
805
806 static void
807 preferences_entry_value_changed_cb (GtkWidget *entry,
808                                     gpointer   user_data)
809 {
810         const gchar *key;
811
812         key = g_object_get_data (G_OBJECT (entry), "key");
813
814         empathy_conf_set_string (empathy_conf_get (),
815                                  key,
816                                  gtk_entry_get_text (GTK_ENTRY (entry)));
817 }
818
819 static void
820 preferences_toggle_button_toggled_cb (GtkWidget *button,
821                                       gpointer   user_data)
822 {
823         const gchar *key;
824
825         key = g_object_get_data (G_OBJECT (button), "key");
826
827         empathy_conf_set_bool (empathy_conf_get (),
828                                key,
829                                gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)));
830 }
831
832 static void
833 preferences_radio_button_toggled_cb (GtkWidget *button,
834                                      gpointer   user_data)
835 {
836         const gchar *key;
837         const gchar *value = NULL;
838
839         if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
840                 return;
841         }
842
843         key = g_object_get_data (G_OBJECT (button), "key");
844
845         if (key && strcmp (key, EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM) == 0) {
846                 GSList      *group;
847                 GType        type;
848                 GEnumClass  *enum_class;
849                 GEnumValue  *enum_value;
850                 
851                 group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
852                 
853                 /* Get string from index */
854                 type = empathy_contact_list_store_sort_get_type ();
855                 enum_class = G_ENUM_CLASS (g_type_class_peek (type));
856                 enum_value = g_enum_get_value (enum_class, g_slist_index (group, button));
857                 
858                 if (!enum_value) {
859                         g_warning ("No GEnumValue for EmpathyContactListSort with GtkRadioButton index:%d", 
860                                    g_slist_index (group, button));
861                         return;
862                 }
863
864                 value = enum_value->value_nick;
865         }
866
867         empathy_conf_set_string (empathy_conf_get (), key, value);
868 }
869
870 static void
871 preferences_string_combo_changed_cb (GtkWidget *combo,
872                                      gpointer   user_data)
873 {
874         const gchar  *key;
875         GtkTreeModel *model;
876         GtkTreeIter   iter;
877         gchar        *name;
878
879         key = g_object_get_data (G_OBJECT (combo), "key");
880
881         if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter)) {
882                 model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
883
884                 gtk_tree_model_get (model, &iter,
885                                     COL_COMBO_NAME, &name,
886                                     -1);
887                 empathy_conf_set_string (empathy_conf_get (), key, name);
888                 g_free (name);
889         }
890 }
891
892 static void
893 preferences_response_cb (GtkWidget         *widget,
894                          gint               response,
895                          EmpathyPreferences *preferences)
896 {
897         gtk_widget_destroy (widget);
898 }
899
900 static void
901 preferences_destroy_cb (GtkWidget         *widget,
902                         EmpathyPreferences *preferences)
903 {
904         GList *l;
905
906         for (l = preferences->notify_ids; l; l = l->next) {
907                 guint id;
908
909                 id = GPOINTER_TO_UINT (l->data);
910                 empathy_conf_notify_remove (empathy_conf_get (), id);
911         }
912
913         g_list_free (preferences->notify_ids);
914         g_free (preferences);
915 }
916
917 GtkWidget *
918 empathy_preferences_show (GtkWindow *parent)
919 {
920         static EmpathyPreferences *preferences;
921         GladeXML                 *glade;
922
923         if (preferences) {
924                 gtk_window_present (GTK_WINDOW (preferences->dialog));
925                 return preferences->dialog;
926         }
927
928         preferences = g_new0 (EmpathyPreferences, 1);
929
930         glade = empathy_glade_get_file (
931                 "empathy-preferences.glade",
932                 "preferences_dialog",
933                 NULL,
934                 "preferences_dialog", &preferences->dialog,
935                 "notebook", &preferences->notebook,
936                 "checkbutton_show_avatars", &preferences->checkbutton_show_avatars,
937                 "checkbutton_compact_contact_list", &preferences->checkbutton_compact_contact_list,
938                 "checkbutton_show_smileys", &preferences->checkbutton_show_smileys,
939                 "combobox_chat_theme", &preferences->combobox_chat_theme,
940                 "checkbutton_theme_chat_room", &preferences->checkbutton_theme_chat_room,
941                 "checkbutton_separate_chat_windows", &preferences->checkbutton_separate_chat_windows,
942                 "radiobutton_contact_list_sort_by_name", &preferences->radiobutton_contact_list_sort_by_name,
943                 "radiobutton_contact_list_sort_by_state", &preferences->radiobutton_contact_list_sort_by_state,
944                 "checkbutton_sounds_for_messages", &preferences->checkbutton_sounds_for_messages,
945                 "checkbutton_sounds_when_busy", &preferences->checkbutton_sounds_when_busy,
946                 "checkbutton_sounds_when_away", &preferences->checkbutton_sounds_when_away,
947                 "checkbutton_popups_when_available", &preferences->checkbutton_popups_when_available,
948                 "treeview_spell_checker", &preferences->treeview_spell_checker,
949                 NULL);
950
951         empathy_glade_connect (glade,
952                               preferences,
953                               "preferences_dialog", "destroy", preferences_destroy_cb,
954                               "preferences_dialog", "response", preferences_response_cb,
955                               NULL);
956
957         g_object_unref (glade);
958
959         g_object_add_weak_pointer (G_OBJECT (preferences->dialog), (gpointer) &preferences);
960
961         preferences_themes_setup (preferences);
962
963         preferences_setup_widgets (preferences);
964
965         preferences_languages_setup (preferences);
966         preferences_languages_add (preferences);
967         preferences_languages_load (preferences);
968
969         if (empathy_spell_supported ()) {
970                 GtkWidget *page;
971
972                 page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (preferences->notebook), 2);
973                 gtk_widget_show (page);
974         }
975
976         if (parent) {
977                 gtk_window_set_transient_for (GTK_WINDOW (preferences->dialog),
978                                               GTK_WINDOW (parent));
979         }
980
981         gtk_widget_show (preferences->dialog);
982
983         return preferences->dialog;
984 }
985