]> git.0d.be Git - empathy.git/blob - src/empathy-preferences.c
Merge branch 'vino-621998'
[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 #include <telepathy-glib/dbus.h>
32 #include <telepathy-glib/util.h>
33
34 #include <libempathy/empathy-gsettings.h>
35 #include <libempathy/empathy-utils.h>
36
37 #include <libempathy-gtk/empathy-ui-utils.h>
38 #include <libempathy-gtk/empathy-theme-manager.h>
39 #include <libempathy-gtk/empathy-spell.h>
40 #include <libempathy-gtk/empathy-contact-list-store.h>
41 #include <libempathy-gtk/empathy-gtk-enum-types.h>
42
43 #ifdef HAVE_WEBKIT
44 #include <libempathy-gtk/empathy-theme-adium.h>
45 #endif
46
47 #include "empathy-preferences.h"
48
49 typedef struct {
50         GtkWidget *dialog;
51
52         GtkWidget *notebook;
53
54         GtkWidget *checkbutton_show_smileys;
55         GtkWidget *checkbutton_show_contacts_in_rooms;
56         GtkWidget *combobox_chat_theme;
57         GtkWidget *checkbutton_separate_chat_windows;
58         GtkWidget *checkbutton_autoconnect;
59
60         GtkWidget *checkbutton_sounds_enabled;
61         GtkWidget *checkbutton_sounds_disabled_away;
62         GtkWidget *treeview_sounds;
63
64         GtkWidget *checkbutton_notifications_enabled;
65         GtkWidget *checkbutton_notifications_disabled_away;
66         GtkWidget *checkbutton_notifications_focus;
67         GtkWidget *checkbutton_notifications_contact_signin;
68         GtkWidget *checkbutton_notifications_contact_signout;
69
70         GtkWidget *treeview_spell_checker;
71
72         GtkWidget *checkbutton_location_publish;
73         GtkWidget *checkbutton_location_reduce_accuracy;
74         GtkWidget *checkbutton_location_resource_network;
75         GtkWidget *checkbutton_location_resource_cell;
76         GtkWidget *checkbutton_location_resource_gps;
77
78         GSettings *gsettings;
79         GSettings *gsettings_chat;
80         GSettings *gsettings_loc;
81         GSettings *gsettings_notify;
82         GSettings *gsettings_sound;
83         GSettings *gsettings_ui;
84 } EmpathyPreferences;
85
86 static void     preferences_setup_widgets                (EmpathyPreferences      *preferences);
87 static void     preferences_languages_setup              (EmpathyPreferences      *preferences);
88 static void     preferences_languages_add                (EmpathyPreferences      *preferences);
89 static void     preferences_languages_save               (EmpathyPreferences      *preferences);
90 static gboolean preferences_languages_save_foreach       (GtkTreeModel           *model,
91                                                           GtkTreePath            *path,
92                                                           GtkTreeIter            *iter,
93                                                           gchar                 **languages);
94 static void     preferences_languages_load               (EmpathyPreferences      *preferences);
95 static gboolean preferences_languages_load_foreach       (GtkTreeModel           *model,
96                                                           GtkTreePath            *path,
97                                                           GtkTreeIter            *iter,
98                                                           gchar                 **languages);
99 static void     preferences_languages_cell_toggled_cb    (GtkCellRendererToggle  *cell,
100                                                           gchar                  *path_string,
101                                                           EmpathyPreferences      *preferences);
102 static void     preferences_destroy_cb                   (GtkWidget              *widget,
103                                                           EmpathyPreferences      *preferences);
104 static void     preferences_response_cb                  (GtkWidget              *widget,
105                                                           gint                    response,
106                                                           EmpathyPreferences      *preferences);
107
108 enum {
109         COL_LANG_ENABLED,
110         COL_LANG_CODE,
111         COL_LANG_NAME,
112         COL_LANG_COUNT
113 };
114
115 enum {
116         COL_COMBO_IS_ADIUM,
117         COL_COMBO_VISIBLE_NAME,
118         COL_COMBO_NAME,
119         COL_COMBO_PATH,
120         COL_COMBO_COUNT
121 };
122
123 enum {
124         COL_SOUND_ENABLED,
125         COL_SOUND_NAME,
126         COL_SOUND_KEY,
127         COL_SOUND_COUNT
128 };
129
130 typedef struct {
131         const char *name;
132         const char *key;
133 } SoundEventEntry;
134
135 /* TODO: add phone related sounds also? */
136 static SoundEventEntry sound_entries [] = {
137         { N_("Message received"), EMPATHY_PREFS_SOUNDS_INCOMING_MESSAGE },
138         { N_("Message sent"), EMPATHY_PREFS_SOUNDS_OUTGOING_MESSAGE },
139         { N_("New conversation"), EMPATHY_PREFS_SOUNDS_NEW_CONVERSATION },
140         { N_("Contact goes online"), EMPATHY_PREFS_SOUNDS_CONTACT_LOGIN },
141         { N_("Contact goes offline"), EMPATHY_PREFS_SOUNDS_CONTACT_LOGOUT },
142         { N_("Account connected"), EMPATHY_PREFS_SOUNDS_SERVICE_LOGIN },
143         { N_("Account disconnected"), EMPATHY_PREFS_SOUNDS_SERVICE_LOGOUT }
144 };
145
146 static void
147 preferences_setup_widgets (EmpathyPreferences *preferences)
148 {
149         g_settings_bind (preferences->gsettings_notify,
150                          EMPATHY_PREFS_NOTIFICATIONS_ENABLED,
151                          preferences->checkbutton_notifications_enabled,
152                          "active",
153                          G_SETTINGS_BIND_DEFAULT);
154         g_settings_bind (preferences->gsettings_notify,
155                          EMPATHY_PREFS_NOTIFICATIONS_DISABLED_AWAY,
156                          preferences->checkbutton_notifications_disabled_away,
157                          "active",
158                          G_SETTINGS_BIND_DEFAULT);
159         g_settings_bind (preferences->gsettings_notify,
160                          EMPATHY_PREFS_NOTIFICATIONS_FOCUS,
161                          preferences->checkbutton_notifications_focus,
162                          "active",
163                          G_SETTINGS_BIND_DEFAULT);
164         g_settings_bind (preferences->gsettings_notify,
165                          EMPATHY_PREFS_NOTIFICATIONS_CONTACT_SIGNIN,
166                          preferences->checkbutton_notifications_contact_signin,
167                          "active",
168                          G_SETTINGS_BIND_DEFAULT);
169         g_settings_bind (preferences->gsettings_notify,
170                          EMPATHY_PREFS_NOTIFICATIONS_CONTACT_SIGNOUT,
171                          preferences->checkbutton_notifications_contact_signout,
172                          "active",
173                          G_SETTINGS_BIND_DEFAULT);
174
175         g_settings_bind (preferences->gsettings_notify,
176                          EMPATHY_PREFS_NOTIFICATIONS_ENABLED,
177                          preferences->checkbutton_notifications_disabled_away,
178                          "sensitive",
179                          G_SETTINGS_BIND_GET);
180         g_settings_bind (preferences->gsettings_notify,
181                          EMPATHY_PREFS_NOTIFICATIONS_ENABLED,
182                          preferences->checkbutton_notifications_focus,
183                          "sensitive",
184                          G_SETTINGS_BIND_GET);
185         g_settings_bind (preferences->gsettings_notify,
186                          EMPATHY_PREFS_NOTIFICATIONS_ENABLED,
187                          preferences->checkbutton_notifications_contact_signin,
188                          "sensitive",
189                          G_SETTINGS_BIND_GET);
190         g_settings_bind (preferences->gsettings_notify,
191                          EMPATHY_PREFS_NOTIFICATIONS_ENABLED,
192                          preferences->checkbutton_notifications_contact_signout,
193                          "sensitive",
194                          G_SETTINGS_BIND_GET);
195
196         g_settings_bind (preferences->gsettings_sound,
197                          EMPATHY_PREFS_SOUNDS_ENABLED,
198                          preferences->checkbutton_sounds_enabled,
199                          "active",
200                          G_SETTINGS_BIND_DEFAULT);
201         g_settings_bind (preferences->gsettings_sound,
202                          EMPATHY_PREFS_SOUNDS_DISABLED_AWAY,
203                          preferences->checkbutton_sounds_disabled_away,
204                          "active",
205                          G_SETTINGS_BIND_DEFAULT);
206
207         g_settings_bind (preferences->gsettings_sound,
208                          EMPATHY_PREFS_SOUNDS_ENABLED,
209                          preferences->checkbutton_sounds_disabled_away,
210                          "sensitive",
211                          G_SETTINGS_BIND_GET);
212         g_settings_bind (preferences->gsettings_sound,
213                         EMPATHY_PREFS_SOUNDS_ENABLED,
214                         preferences->treeview_sounds,
215                         "sensitive",
216                         G_SETTINGS_BIND_GET);
217
218         g_settings_bind (preferences->gsettings_ui,
219                          EMPATHY_PREFS_UI_SEPARATE_CHAT_WINDOWS,
220                          preferences->checkbutton_separate_chat_windows,
221                          "active",
222                          G_SETTINGS_BIND_DEFAULT);
223
224         g_settings_bind (preferences->gsettings_chat,
225                          EMPATHY_PREFS_CHAT_SHOW_SMILEYS,
226                          preferences->checkbutton_show_smileys,
227                          "active",
228                          G_SETTINGS_BIND_DEFAULT);
229         g_settings_bind (preferences->gsettings_chat,
230                          EMPATHY_PREFS_CHAT_SHOW_CONTACTS_IN_ROOMS,
231                          preferences->checkbutton_show_contacts_in_rooms,
232                          "active",
233                          G_SETTINGS_BIND_DEFAULT);
234
235         g_settings_bind (preferences->gsettings,
236                          EMPATHY_PREFS_AUTOCONNECT,
237                          preferences->checkbutton_autoconnect,
238                          "active",
239                          G_SETTINGS_BIND_DEFAULT);
240
241         g_settings_bind (preferences->gsettings_loc,
242                          EMPATHY_PREFS_LOCATION_PUBLISH,
243                          preferences->checkbutton_location_publish,
244                          "active",
245                          G_SETTINGS_BIND_DEFAULT);
246
247         g_settings_bind (preferences->gsettings_loc,
248                          EMPATHY_PREFS_LOCATION_RESOURCE_NETWORK,
249                          preferences->checkbutton_location_resource_network,
250                          "active",
251                          G_SETTINGS_BIND_DEFAULT);
252         g_settings_bind (preferences->gsettings_loc,
253                          EMPATHY_PREFS_LOCATION_PUBLISH,
254                          preferences->checkbutton_location_resource_network,
255                          "sensitive",
256                          G_SETTINGS_BIND_GET);
257
258         g_settings_bind (preferences->gsettings_loc,
259                          EMPATHY_PREFS_LOCATION_RESOURCE_CELL,
260                          preferences->checkbutton_location_resource_cell,
261                          "active",
262                          G_SETTINGS_BIND_DEFAULT);
263         g_settings_bind (preferences->gsettings_loc,
264                          EMPATHY_PREFS_LOCATION_PUBLISH,
265                          preferences->checkbutton_location_resource_cell,
266                          "sensitive",
267                          G_SETTINGS_BIND_GET);
268
269         g_settings_bind (preferences->gsettings_loc,
270                          EMPATHY_PREFS_LOCATION_RESOURCE_GPS,
271                          preferences->checkbutton_location_resource_gps,
272                          "active",
273                          G_SETTINGS_BIND_DEFAULT);
274         g_settings_bind (preferences->gsettings_loc,
275                          EMPATHY_PREFS_LOCATION_PUBLISH,
276                          preferences->checkbutton_location_resource_gps,
277                          "sensitive",
278                          G_SETTINGS_BIND_GET);
279
280         g_settings_bind (preferences->gsettings_loc,
281                          EMPATHY_PREFS_LOCATION_REDUCE_ACCURACY,
282                          preferences->checkbutton_location_reduce_accuracy,
283                          "active",
284                          G_SETTINGS_BIND_DEFAULT);
285         g_settings_bind (preferences->gsettings_loc,
286                          EMPATHY_PREFS_LOCATION_PUBLISH,
287                          preferences->checkbutton_location_reduce_accuracy,
288                          "sensitive",
289                          G_SETTINGS_BIND_GET);
290 }
291
292 static void
293 preferences_sound_cell_toggled_cb (GtkCellRendererToggle *toggle,
294                                    char *path_string,
295                                    EmpathyPreferences *preferences)
296 {
297         GtkTreePath *path;
298         gboolean toggled, instore;
299         GtkTreeIter iter;
300         GtkTreeView *view;
301         GtkTreeModel *model;
302         char *key;
303
304         view = GTK_TREE_VIEW (preferences->treeview_sounds);
305         model = gtk_tree_view_get_model (view);
306
307         path = gtk_tree_path_new_from_string (path_string);
308         toggled = gtk_cell_renderer_toggle_get_active (toggle);
309
310         gtk_tree_model_get_iter (model, &iter, path);
311         gtk_tree_model_get (model, &iter, COL_SOUND_KEY, &key,
312                             COL_SOUND_ENABLED, &instore, -1);
313
314         instore ^= 1;
315
316         gtk_list_store_set (GTK_LIST_STORE (model), &iter,
317                             COL_SOUND_ENABLED, instore, -1);
318
319         g_settings_set_boolean (preferences->gsettings_sound, key, instore);
320
321         g_free (key);
322         gtk_tree_path_free (path);
323 }
324
325 static void
326 preferences_sound_load (EmpathyPreferences *preferences)
327 {
328         guint i;
329         GtkTreeView *view;
330         GtkListStore *store;
331         GtkTreeIter iter;
332         gboolean set;
333
334         view = GTK_TREE_VIEW (preferences->treeview_sounds);
335         store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
336
337         for (i = 0; i < G_N_ELEMENTS (sound_entries); i++) {
338                 set = g_settings_get_boolean (preferences->gsettings_sound,
339                                               sound_entries[i].key);
340
341                 gtk_list_store_insert_with_values (store, &iter, i,
342                                                    COL_SOUND_NAME, gettext (sound_entries[i].name),
343                                                    COL_SOUND_KEY, sound_entries[i].key,
344                                                    COL_SOUND_ENABLED, set, -1);
345         }
346 }
347
348 static void
349 preferences_sound_setup (EmpathyPreferences *preferences)
350 {
351         GtkTreeView *view;
352         GtkListStore *store;
353         GtkCellRenderer *renderer;
354         GtkTreeViewColumn *column;
355
356         view = GTK_TREE_VIEW (preferences->treeview_sounds);
357
358         store = gtk_list_store_new (COL_SOUND_COUNT,
359                                     G_TYPE_BOOLEAN, /* enabled */
360                                     G_TYPE_STRING,  /* name */
361                                     G_TYPE_STRING); /* key */
362
363         gtk_tree_view_set_model (view, GTK_TREE_MODEL (store));
364
365         renderer = gtk_cell_renderer_toggle_new ();
366         g_signal_connect (renderer, "toggled",
367                           G_CALLBACK (preferences_sound_cell_toggled_cb),
368                           preferences);
369
370         column = gtk_tree_view_column_new ();
371         gtk_tree_view_column_pack_start (column, renderer, FALSE);
372         gtk_tree_view_column_add_attribute (column, renderer,
373                                             "active", COL_SOUND_ENABLED);
374
375         renderer = gtk_cell_renderer_text_new ();
376         gtk_tree_view_column_pack_start (column, renderer, FALSE);
377         gtk_tree_view_column_add_attribute (column, renderer,
378                                             "text", COL_SOUND_NAME);
379
380         gtk_tree_view_append_column (view, column);
381
382         gtk_tree_view_column_set_resizable (column, FALSE);
383         gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
384
385         g_object_unref (store);
386 }
387
388 static void
389 preferences_languages_setup (EmpathyPreferences *preferences)
390 {
391         GtkTreeView       *view;
392         GtkListStore      *store;
393         GtkTreeSelection  *selection;
394         GtkTreeModel      *model;
395         GtkTreeViewColumn *column;
396         GtkCellRenderer   *renderer;
397         guint              col_offset;
398
399         view = GTK_TREE_VIEW (preferences->treeview_spell_checker);
400
401         store = gtk_list_store_new (COL_LANG_COUNT,
402                                     G_TYPE_BOOLEAN,  /* enabled */
403                                     G_TYPE_STRING,   /* code */
404                                     G_TYPE_STRING);  /* name */
405
406         gtk_tree_view_set_model (view, GTK_TREE_MODEL (store));
407
408         selection = gtk_tree_view_get_selection (view);
409         gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
410
411         model = GTK_TREE_MODEL (store);
412
413         renderer = gtk_cell_renderer_toggle_new ();
414         g_signal_connect (renderer, "toggled",
415                           G_CALLBACK (preferences_languages_cell_toggled_cb),
416                           preferences);
417
418         column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
419                                                            "active", COL_LANG_ENABLED,
420                                                            NULL);
421
422         gtk_tree_view_append_column (view, column);
423
424         renderer = gtk_cell_renderer_text_new ();
425         col_offset = gtk_tree_view_insert_column_with_attributes (view,
426                                                                   -1, _("Language"),
427                                                                   renderer,
428                                                                   "text", COL_LANG_NAME,
429                                                                   NULL);
430
431         g_object_set_data (G_OBJECT (renderer),
432                            "column", GINT_TO_POINTER (COL_LANG_NAME));
433
434         column = gtk_tree_view_get_column (view, col_offset - 1);
435         gtk_tree_view_column_set_sort_column_id (column, COL_LANG_NAME);
436         gtk_tree_view_column_set_resizable (column, FALSE);
437         gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
438
439         g_object_unref (store);
440 }
441
442 static void
443 preferences_languages_add (EmpathyPreferences *preferences)
444 {
445         GtkTreeView  *view;
446         GtkListStore *store;
447         GList        *codes, *l;
448
449         view = GTK_TREE_VIEW (preferences->treeview_spell_checker);
450         store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
451
452         codes = empathy_spell_get_language_codes ();
453
454         g_settings_set_boolean (preferences->gsettings_chat,
455                                 EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED,
456                                 codes != NULL);
457         if (!codes) {
458                 gtk_widget_set_sensitive (preferences->treeview_spell_checker, FALSE);
459         }
460
461         for (l = codes; l; l = l->next) {
462                 GtkTreeIter  iter;
463                 const gchar *code;
464                 const gchar *name;
465
466                 code = l->data;
467                 name = empathy_spell_get_language_name (code);
468                 if (!name) {
469                         continue;
470                 }
471
472                 gtk_list_store_append (store, &iter);
473                 gtk_list_store_set (store, &iter,
474                                     COL_LANG_CODE, code,
475                                     COL_LANG_NAME, name,
476                                     -1);
477         }
478
479         empathy_spell_free_language_codes (codes);
480 }
481
482 static void
483 preferences_languages_save (EmpathyPreferences *preferences)
484 {
485         GtkTreeView       *view;
486         GtkTreeModel      *model;
487
488         gchar             *languages = NULL;
489
490         view = GTK_TREE_VIEW (preferences->treeview_spell_checker);
491         model = gtk_tree_view_get_model (view);
492
493         gtk_tree_model_foreach (model,
494                                 (GtkTreeModelForeachFunc) preferences_languages_save_foreach,
495                                 &languages);
496
497         /* if user selects no languages, we don't want spell check */
498         g_settings_set_boolean (preferences->gsettings_chat,
499                                 EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED,
500                                 languages != NULL);
501
502         g_settings_set_string (preferences->gsettings_chat,
503                                EMPATHY_PREFS_CHAT_SPELL_CHECKER_LANGUAGES,
504                                languages != NULL ? languages : "");
505
506         g_free (languages);
507 }
508
509 static gboolean
510 preferences_languages_save_foreach (GtkTreeModel  *model,
511                                     GtkTreePath   *path,
512                                     GtkTreeIter   *iter,
513                                     gchar        **languages)
514 {
515         gboolean  enabled;
516         gchar    *code;
517
518         if (!languages) {
519                 return TRUE;
520         }
521
522         gtk_tree_model_get (model, iter, COL_LANG_ENABLED, &enabled, -1);
523         if (!enabled) {
524                 return FALSE;
525         }
526
527         gtk_tree_model_get (model, iter, COL_LANG_CODE, &code, -1);
528         if (!code) {
529                 return FALSE;
530         }
531
532         if (!(*languages)) {
533                 *languages = g_strdup (code);
534         } else {
535                 gchar *str = *languages;
536                 *languages = g_strdup_printf ("%s,%s", str, code);
537                 g_free (str);
538         }
539
540         g_free (code);
541
542         return FALSE;
543 }
544
545 static void
546 preferences_languages_load (EmpathyPreferences *preferences)
547 {
548         GtkTreeView   *view;
549         GtkTreeModel  *model;
550         gchar         *value;
551         gchar        **vlanguages;
552
553         value = g_settings_get_string (preferences->gsettings_chat,
554                                        EMPATHY_PREFS_CHAT_SPELL_CHECKER_LANGUAGES);
555
556         if (value == NULL)
557                 return;
558
559         vlanguages = g_strsplit (value, ",", -1);
560         g_free (value);
561
562         view = GTK_TREE_VIEW (preferences->treeview_spell_checker);
563         model = gtk_tree_view_get_model (view);
564
565         gtk_tree_model_foreach (model,
566                                 (GtkTreeModelForeachFunc) preferences_languages_load_foreach,
567                                 vlanguages);
568
569         g_strfreev (vlanguages);
570 }
571
572 static gboolean
573 preferences_languages_load_foreach (GtkTreeModel  *model,
574                                     GtkTreePath   *path,
575                                     GtkTreeIter   *iter,
576                                     gchar        **languages)
577 {
578         gchar    *code;
579         gchar    *lang;
580         gint      i;
581         gboolean  found = FALSE;
582
583         if (!languages) {
584                 return TRUE;
585         }
586
587         gtk_tree_model_get (model, iter, COL_LANG_CODE, &code, -1);
588         if (!code) {
589                 return FALSE;
590         }
591
592         for (i = 0, lang = languages[i]; lang; lang = languages[++i]) {
593                 if (!tp_strdiff (lang, code)) {
594                         found = TRUE;
595                 }
596         }
597
598         g_free (code);
599         gtk_list_store_set (GTK_LIST_STORE (model), iter, COL_LANG_ENABLED, found, -1);
600         return FALSE;
601 }
602
603 static void
604 preferences_languages_cell_toggled_cb (GtkCellRendererToggle *cell,
605                                        gchar                 *path_string,
606                                        EmpathyPreferences     *preferences)
607 {
608         GtkTreeView  *view;
609         GtkTreeModel *model;
610         GtkListStore *store;
611         GtkTreePath  *path;
612         GtkTreeIter   iter;
613         gboolean      enabled;
614
615         view = GTK_TREE_VIEW (preferences->treeview_spell_checker);
616         model = gtk_tree_view_get_model (view);
617         store = GTK_LIST_STORE (model);
618
619         path = gtk_tree_path_new_from_string (path_string);
620
621         gtk_tree_model_get_iter (model, &iter, path);
622         gtk_tree_model_get (model, &iter, COL_LANG_ENABLED, &enabled, -1);
623
624         enabled ^= 1;
625
626         gtk_list_store_set (store, &iter, COL_LANG_ENABLED, enabled, -1);
627         gtk_tree_path_free (path);
628
629         preferences_languages_save (preferences);
630 }
631
632 static void
633 preferences_theme_notify_cb (GSettings   *gsettings,
634                              const gchar *key,
635                              gpointer     user_data)
636 {
637         EmpathyPreferences *preferences = user_data;
638         GtkComboBox        *combo;
639         gchar              *conf_name;
640         gchar              *conf_path;
641         GtkTreeModel       *model;
642         GtkTreeIter         iter;
643         gboolean            found = FALSE;
644
645         conf_name = g_settings_get_string (gsettings, EMPATHY_PREFS_CHAT_THEME);
646         conf_path = g_settings_get_string (gsettings, EMPATHY_PREFS_CHAT_ADIUM_PATH);
647
648         combo = GTK_COMBO_BOX (preferences->combobox_chat_theme);
649         model = gtk_combo_box_get_model (combo);
650         if (gtk_tree_model_get_iter_first (model, &iter)) {
651                 gboolean is_adium;
652                 gchar *name;
653                 gchar *path;
654
655                 do {
656                         gtk_tree_model_get (model, &iter,
657                                             COL_COMBO_IS_ADIUM, &is_adium,
658                                             COL_COMBO_NAME, &name,
659                                             COL_COMBO_PATH, &path,
660                                             -1);
661
662                         if (!tp_strdiff (name, conf_name)) {
663                                 if (tp_strdiff (name, "adium") ||
664                                     !tp_strdiff (path, conf_path)) {
665                                         found = TRUE;
666                                         gtk_combo_box_set_active_iter (combo, &iter);
667                                         g_free (name);
668                                         g_free (path);
669                                         break;
670                                 }
671                         }
672
673                         g_free (name);
674                         g_free (path);
675                 } while (gtk_tree_model_iter_next (model, &iter));
676         }
677
678         /* Fallback to the first one. */
679         if (!found) {
680                 if (gtk_tree_model_get_iter_first (model, &iter)) {
681                         gtk_combo_box_set_active_iter (combo, &iter);
682                 }
683         }
684
685         g_free (conf_name);
686         g_free (conf_path);
687 }
688
689 static void
690 preferences_theme_changed_cb (GtkComboBox        *combo,
691                               EmpathyPreferences *preferences)
692 {
693         GtkTreeModel *model;
694         GtkTreeIter   iter;
695         gboolean      is_adium;
696         gchar        *name;
697         gchar        *path;
698
699         if (gtk_combo_box_get_active_iter (combo, &iter)) {
700                 model = gtk_combo_box_get_model (combo);
701
702                 gtk_tree_model_get (model, &iter,
703                                     COL_COMBO_IS_ADIUM, &is_adium,
704                                     COL_COMBO_NAME, &name,
705                                     COL_COMBO_PATH, &path,
706                                     -1);
707
708                 g_settings_set_string (preferences->gsettings_chat,
709                                        EMPATHY_PREFS_CHAT_THEME,
710                                        name);
711                 if (is_adium == TRUE)
712                         g_settings_set_string (preferences->gsettings_chat,
713                                                EMPATHY_PREFS_CHAT_ADIUM_PATH,
714                                                path);
715                 g_free (name);
716                 g_free (path);
717         }
718 }
719
720 static void
721 preferences_themes_setup (EmpathyPreferences *preferences)
722 {
723         GtkComboBox   *combo;
724         GtkCellLayout *cell_layout;
725         GtkCellRenderer *renderer;
726         GtkListStore  *store;
727         const gchar  **themes;
728         GList         *adium_themes;
729         gint           i;
730
731         combo = GTK_COMBO_BOX (preferences->combobox_chat_theme);
732         cell_layout = GTK_CELL_LAYOUT (combo);
733
734         /* Create the model */
735         store = gtk_list_store_new (COL_COMBO_COUNT,
736                                     G_TYPE_BOOLEAN, /* Is an Adium theme */
737                                     G_TYPE_STRING,  /* Display name */
738                                     G_TYPE_STRING,  /* Theme name */
739                                     G_TYPE_STRING); /* Theme path */
740         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
741                 COL_COMBO_VISIBLE_NAME, GTK_SORT_ASCENDING);
742
743         /* Fill the model */
744         themes = empathy_theme_manager_get_themes ();
745         for (i = 0; themes[i]; i += 2) {
746                 gtk_list_store_insert_with_values (store, NULL, -1,
747                         COL_COMBO_IS_ADIUM, FALSE,
748                         COL_COMBO_VISIBLE_NAME, _(themes[i + 1]),
749                         COL_COMBO_NAME, themes[i],
750                         COL_COMBO_PATH, NULL,
751                         -1);
752         }
753
754         adium_themes = empathy_theme_manager_get_adium_themes ();
755         while (adium_themes != NULL) {
756                 GHashTable *info;
757                 const gchar *name;
758                 const gchar *path;
759
760                 info = adium_themes->data;
761                 name = tp_asv_get_string (info, "CFBundleName");
762                 path = tp_asv_get_string (info, "path");
763
764                 if (name != NULL && path != NULL) {
765                         gtk_list_store_insert_with_values (store, NULL, -1,
766                                 COL_COMBO_IS_ADIUM, TRUE,
767                                 COL_COMBO_VISIBLE_NAME, name,
768                                 COL_COMBO_NAME, "adium",
769                                 COL_COMBO_PATH, path,
770                                 -1);
771                 }
772                 g_hash_table_unref (info);
773                 adium_themes = g_list_delete_link (adium_themes, adium_themes);
774         }
775
776         /* Add cell renderer */
777         renderer = gtk_cell_renderer_text_new ();
778         gtk_cell_layout_pack_start (cell_layout, renderer, TRUE);
779         gtk_cell_layout_set_attributes (cell_layout, renderer,
780                 "text", COL_COMBO_VISIBLE_NAME, NULL);
781
782         gtk_combo_box_set_model (combo, GTK_TREE_MODEL (store));
783         g_object_unref (store);
784
785         g_signal_connect (combo, "changed",
786                           G_CALLBACK (preferences_theme_changed_cb),
787                           preferences);
788
789         /* Select the theme from the GSetting key and track changes */
790         preferences_theme_notify_cb (preferences->gsettings_chat,
791                                      EMPATHY_PREFS_CHAT_THEME,
792                                      preferences);
793         g_signal_connect (preferences->gsettings_chat,
794                           "changed::" EMPATHY_PREFS_CHAT_THEME,
795                           G_CALLBACK (preferences_theme_notify_cb),
796                           preferences);
797
798         g_signal_connect (preferences->gsettings_chat,
799                           "changed::" EMPATHY_PREFS_CHAT_ADIUM_PATH,
800                           G_CALLBACK (preferences_theme_notify_cb),
801                           preferences);
802 }
803
804 static void
805 preferences_response_cb (GtkWidget         *widget,
806                          gint               response,
807                          EmpathyPreferences *preferences)
808 {
809         gtk_widget_destroy (widget);
810 }
811
812 static void
813 preferences_destroy_cb (GtkWidget         *widget,
814                         EmpathyPreferences *preferences)
815 {
816         g_object_unref (preferences->gsettings);
817         g_object_unref (preferences->gsettings_chat);
818         g_object_unref (preferences->gsettings_loc);
819         g_object_unref (preferences->gsettings_notify);
820         g_object_unref (preferences->gsettings_sound);
821         g_object_unref (preferences->gsettings_ui);
822
823         g_free (preferences);
824 }
825
826 GtkWidget *
827 empathy_preferences_show (GtkWindow *parent)
828 {
829         static EmpathyPreferences *preferences;
830         GtkBuilder                *gui;
831         gchar                     *filename;
832         GtkWidget                 *page;
833
834         if (preferences) {
835                 gtk_window_present (GTK_WINDOW (preferences->dialog));
836                 return preferences->dialog;
837         }
838
839         preferences = g_new0 (EmpathyPreferences, 1);
840
841         filename = empathy_file_lookup ("empathy-preferences.ui", "src");
842         gui = empathy_builder_get_file (filename,
843                 "preferences_dialog", &preferences->dialog,
844                 "notebook", &preferences->notebook,
845                 "checkbutton_show_smileys", &preferences->checkbutton_show_smileys,
846                 "checkbutton_show_contacts_in_rooms", &preferences->checkbutton_show_contacts_in_rooms,
847                 "combobox_chat_theme", &preferences->combobox_chat_theme,
848                 "checkbutton_separate_chat_windows", &preferences->checkbutton_separate_chat_windows,
849                 "checkbutton_autoconnect", &preferences->checkbutton_autoconnect,
850                 "checkbutton_notifications_enabled", &preferences->checkbutton_notifications_enabled,
851                 "checkbutton_notifications_disabled_away", &preferences->checkbutton_notifications_disabled_away,
852                 "checkbutton_notifications_focus", &preferences->checkbutton_notifications_focus,
853                 "checkbutton_notifications_contact_signin", &preferences->checkbutton_notifications_contact_signin,
854                 "checkbutton_notifications_contact_signout", &preferences->checkbutton_notifications_contact_signout,
855                 "checkbutton_sounds_enabled", &preferences->checkbutton_sounds_enabled,
856                 "checkbutton_sounds_disabled_away", &preferences->checkbutton_sounds_disabled_away,
857                 "treeview_sounds", &preferences->treeview_sounds,
858                 "treeview_spell_checker", &preferences->treeview_spell_checker,
859                 "checkbutton_location_publish", &preferences->checkbutton_location_publish,
860                 "checkbutton_location_reduce_accuracy", &preferences->checkbutton_location_reduce_accuracy,
861                 "checkbutton_location_resource_network", &preferences->checkbutton_location_resource_network,
862                 "checkbutton_location_resource_cell", &preferences->checkbutton_location_resource_cell,
863                 "checkbutton_location_resource_gps", &preferences->checkbutton_location_resource_gps,
864                 NULL);
865         g_free (filename);
866
867         empathy_builder_connect (gui, preferences,
868                               "preferences_dialog", "destroy", preferences_destroy_cb,
869                               "preferences_dialog", "response", preferences_response_cb,
870                               NULL);
871
872         g_object_unref (gui);
873
874         g_object_add_weak_pointer (G_OBJECT (preferences->dialog), (gpointer) &preferences);
875
876         preferences->gsettings = g_settings_new (EMPATHY_PREFS_SCHEMA);
877         preferences->gsettings_chat = g_settings_new (EMPATHY_PREFS_CHAT_SCHEMA);
878         preferences->gsettings_loc = g_settings_new (EMPATHY_PREFS_LOCATION_SCHEMA);
879         preferences->gsettings_notify = g_settings_new (EMPATHY_PREFS_NOTIFICATIONS_SCHEMA);
880         preferences->gsettings_sound = g_settings_new (EMPATHY_PREFS_SOUNDS_SCHEMA);
881         preferences->gsettings_ui = g_settings_new (EMPATHY_PREFS_UI_SCHEMA);
882
883         preferences_themes_setup (preferences);
884
885         preferences_setup_widgets (preferences);
886
887         preferences_languages_setup (preferences);
888         preferences_languages_add (preferences);
889         preferences_languages_load (preferences);
890
891         preferences_sound_setup (preferences);
892         preferences_sound_load (preferences);
893
894         if (empathy_spell_supported ()) {
895                 page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (preferences->notebook), 2);
896                 gtk_widget_show (page);
897         }
898
899         page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (preferences->notebook), 3);
900 #if HAVE_GEOCLUE
901         gtk_widget_show (page);
902 #else
903         gtk_widget_hide (page);
904 #endif
905
906
907         if (parent) {
908                 gtk_window_set_transient_for (GTK_WINDOW (preferences->dialog),
909                                               GTK_WINDOW (parent));
910         }
911
912         gtk_widget_show (preferences->dialog);
913
914         return preferences->dialog;
915 }
916