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