]> git.0d.be Git - empathy.git/blob - src/empathy-preferences.c
Preferences: Show chat theme preview
[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  *          Danielle Madeley <danielle.madeley@collabora.co.uk>
24  */
25
26 #include <config.h>
27
28 #include <string.h>
29 #include <stdio.h>
30
31 #include <gtk/gtk.h>
32 #include <glib/gi18n.h>
33 #include <telepathy-glib/dbus.h>
34 #include <telepathy-glib/util.h>
35
36 #include <libempathy/empathy-gsettings.h>
37 #include <libempathy/empathy-utils.h>
38
39 #include <libempathy-gtk/empathy-ui-utils.h>
40 #include <libempathy-gtk/empathy-theme-manager.h>
41 #include <libempathy-gtk/empathy-spell.h>
42 #include <libempathy-gtk/empathy-contact-list-store.h>
43 #include <libempathy-gtk/empathy-gtk-enum-types.h>
44
45 #ifdef HAVE_WEBKIT
46 #include <libempathy-gtk/empathy-theme-adium.h>
47 #endif
48
49 #include "empathy-preferences.h"
50
51 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
52 #include <libempathy/empathy-debug.h>
53
54 G_DEFINE_TYPE (EmpathyPreferences, empathy_preferences, GTK_TYPE_DIALOG);
55
56 #define GET_PRIV(self) ((EmpathyPreferencesPriv *)((EmpathyPreferences *) self)->priv)
57
58 struct _EmpathyPreferencesPriv {
59         GtkWidget *notebook;
60
61         GtkWidget *checkbutton_show_smileys;
62         GtkWidget *checkbutton_show_contacts_in_rooms;
63         GtkWidget *checkbutton_separate_chat_windows;
64         GtkWidget *checkbutton_events_notif_area;
65         GtkWidget *checkbutton_autoconnect;
66         GtkWidget *checkbutton_logging;
67
68         GtkWidget *checkbutton_sounds_enabled;
69         GtkWidget *checkbutton_sounds_disabled_away;
70         GtkWidget *treeview_sounds;
71
72         GtkWidget *checkbutton_notifications_enabled;
73         GtkWidget *checkbutton_notifications_disabled_away;
74         GtkWidget *checkbutton_notifications_focus;
75         GtkWidget *checkbutton_notifications_contact_signin;
76         GtkWidget *checkbutton_notifications_contact_signout;
77
78         GtkWidget *treeview_spell_checker;
79
80         GtkWidget *checkbutton_location_publish;
81         GtkWidget *checkbutton_location_reduce_accuracy;
82         GtkWidget *checkbutton_location_resource_network;
83         GtkWidget *checkbutton_location_resource_cell;
84         GtkWidget *checkbutton_location_resource_gps;
85
86         GtkWidget *vbox_chat_theme;
87         GtkWidget *combobox_chat_theme;
88         GtkWidget *sw_chat_theme_preview;
89         EmpathyChatView *chat_theme_preview;
90         EmpathyThemeManager *theme_manager;
91
92         GSettings *gsettings;
93         GSettings *gsettings_chat;
94         GSettings *gsettings_loc;
95         GSettings *gsettings_notify;
96         GSettings *gsettings_sound;
97         GSettings *gsettings_ui;
98         GSettings *gsettings_logger;
99 };
100
101 static void     preferences_setup_widgets                (EmpathyPreferences      *preferences);
102 static void     preferences_languages_setup              (EmpathyPreferences      *preferences);
103 static void     preferences_languages_add                (EmpathyPreferences      *preferences);
104 static void     preferences_languages_save               (EmpathyPreferences      *preferences);
105 static gboolean preferences_languages_save_foreach       (GtkTreeModel           *model,
106                                                           GtkTreePath            *path,
107                                                           GtkTreeIter            *iter,
108                                                           gchar                 **languages);
109 static void     preferences_languages_load               (EmpathyPreferences      *preferences);
110 static gboolean preferences_languages_load_foreach       (GtkTreeModel           *model,
111                                                           GtkTreePath            *path,
112                                                           GtkTreeIter            *iter,
113                                                           GList                  *languages);
114 static void     preferences_languages_cell_toggled_cb    (GtkCellRendererToggle  *cell,
115                                                           gchar                  *path_string,
116                                                           EmpathyPreferences      *preferences);
117
118 enum {
119         COL_LANG_ENABLED,
120         COL_LANG_CODE,
121         COL_LANG_NAME,
122         COL_LANG_COUNT
123 };
124
125 enum {
126         COL_THEME_VISIBLE_NAME,
127         COL_THEME_NAME,
128         COL_THEME_IS_ADIUM,
129         COL_THEME_ADIUM_PATH,
130         COL_THEME_COUNT
131 };
132
133 enum {
134         COL_SOUND_ENABLED,
135         COL_SOUND_NAME,
136         COL_SOUND_KEY,
137         COL_SOUND_COUNT
138 };
139
140 typedef struct {
141         const char *name;
142         const char *key;
143 } SoundEventEntry;
144
145 /* TODO: add phone related sounds also? */
146 static SoundEventEntry sound_entries [] = {
147         { N_("Message received"), EMPATHY_PREFS_SOUNDS_INCOMING_MESSAGE },
148         { N_("Message sent"), EMPATHY_PREFS_SOUNDS_OUTGOING_MESSAGE },
149         { N_("New conversation"), EMPATHY_PREFS_SOUNDS_NEW_CONVERSATION },
150         { N_("Contact goes online"), EMPATHY_PREFS_SOUNDS_CONTACT_LOGIN },
151         { N_("Contact goes offline"), EMPATHY_PREFS_SOUNDS_CONTACT_LOGOUT },
152         { N_("Account connected"), EMPATHY_PREFS_SOUNDS_SERVICE_LOGIN },
153         { N_("Account disconnected"), EMPATHY_PREFS_SOUNDS_SERVICE_LOGOUT }
154 };
155
156 static void
157 preferences_setup_widgets (EmpathyPreferences *preferences)
158 {
159         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
160
161         g_settings_bind (priv->gsettings_notify,
162                          EMPATHY_PREFS_NOTIFICATIONS_ENABLED,
163                          priv->checkbutton_notifications_enabled,
164                          "active",
165                          G_SETTINGS_BIND_DEFAULT);
166         g_settings_bind (priv->gsettings_notify,
167                          EMPATHY_PREFS_NOTIFICATIONS_DISABLED_AWAY,
168                          priv->checkbutton_notifications_disabled_away,
169                          "active",
170                          G_SETTINGS_BIND_DEFAULT);
171         g_settings_bind (priv->gsettings_notify,
172                          EMPATHY_PREFS_NOTIFICATIONS_FOCUS,
173                          priv->checkbutton_notifications_focus,
174                          "active",
175                          G_SETTINGS_BIND_DEFAULT);
176         g_settings_bind (priv->gsettings_notify,
177                          EMPATHY_PREFS_NOTIFICATIONS_CONTACT_SIGNIN,
178                          priv->checkbutton_notifications_contact_signin,
179                          "active",
180                          G_SETTINGS_BIND_DEFAULT);
181         g_settings_bind (priv->gsettings_notify,
182                          EMPATHY_PREFS_NOTIFICATIONS_CONTACT_SIGNOUT,
183                          priv->checkbutton_notifications_contact_signout,
184                          "active",
185                          G_SETTINGS_BIND_DEFAULT);
186
187         g_settings_bind (priv->gsettings_notify,
188                          EMPATHY_PREFS_NOTIFICATIONS_ENABLED,
189                          priv->checkbutton_notifications_disabled_away,
190                          "sensitive",
191                          G_SETTINGS_BIND_GET);
192         g_settings_bind (priv->gsettings_notify,
193                          EMPATHY_PREFS_NOTIFICATIONS_ENABLED,
194                          priv->checkbutton_notifications_focus,
195                          "sensitive",
196                          G_SETTINGS_BIND_GET);
197         g_settings_bind (priv->gsettings_notify,
198                          EMPATHY_PREFS_NOTIFICATIONS_ENABLED,
199                          priv->checkbutton_notifications_contact_signin,
200                          "sensitive",
201                          G_SETTINGS_BIND_GET);
202         g_settings_bind (priv->gsettings_notify,
203                          EMPATHY_PREFS_NOTIFICATIONS_ENABLED,
204                          priv->checkbutton_notifications_contact_signout,
205                          "sensitive",
206                          G_SETTINGS_BIND_GET);
207
208         g_settings_bind (priv->gsettings_sound,
209                          EMPATHY_PREFS_SOUNDS_ENABLED,
210                          priv->checkbutton_sounds_enabled,
211                          "active",
212                          G_SETTINGS_BIND_DEFAULT);
213         g_settings_bind (priv->gsettings_sound,
214                          EMPATHY_PREFS_SOUNDS_DISABLED_AWAY,
215                          priv->checkbutton_sounds_disabled_away,
216                          "active",
217                          G_SETTINGS_BIND_DEFAULT);
218
219         g_settings_bind (priv->gsettings_sound,
220                          EMPATHY_PREFS_SOUNDS_ENABLED,
221                          priv->checkbutton_sounds_disabled_away,
222                          "sensitive",
223                          G_SETTINGS_BIND_GET);
224         g_settings_bind (priv->gsettings_sound,
225                         EMPATHY_PREFS_SOUNDS_ENABLED,
226                         priv->treeview_sounds,
227                         "sensitive",
228                         G_SETTINGS_BIND_GET);
229
230         g_settings_bind (priv->gsettings_ui,
231                          EMPATHY_PREFS_UI_SEPARATE_CHAT_WINDOWS,
232                          priv->checkbutton_separate_chat_windows,
233                          "active",
234                          G_SETTINGS_BIND_DEFAULT);
235
236         g_settings_bind (priv->gsettings_ui,
237                          EMPATHY_PREFS_UI_EVENTS_NOTIFY_AREA,
238                          priv->checkbutton_events_notif_area,
239                          "active",
240                          G_SETTINGS_BIND_DEFAULT);
241
242         g_settings_bind (priv->gsettings_chat,
243                          EMPATHY_PREFS_CHAT_SHOW_SMILEYS,
244                          priv->checkbutton_show_smileys,
245                          "active",
246                          G_SETTINGS_BIND_DEFAULT);
247         g_settings_bind (priv->gsettings_chat,
248                          EMPATHY_PREFS_CHAT_SHOW_CONTACTS_IN_ROOMS,
249                          priv->checkbutton_show_contacts_in_rooms,
250                          "active",
251                          G_SETTINGS_BIND_DEFAULT);
252
253         g_settings_bind (priv->gsettings,
254                          EMPATHY_PREFS_AUTOCONNECT,
255                          priv->checkbutton_autoconnect,
256                          "active",
257                          G_SETTINGS_BIND_DEFAULT);
258
259         g_settings_bind (priv->gsettings_loc,
260                          EMPATHY_PREFS_LOCATION_PUBLISH,
261                          priv->checkbutton_location_publish,
262                          "active",
263                          G_SETTINGS_BIND_DEFAULT);
264
265         g_settings_bind (priv->gsettings_loc,
266                          EMPATHY_PREFS_LOCATION_RESOURCE_NETWORK,
267                          priv->checkbutton_location_resource_network,
268                          "active",
269                          G_SETTINGS_BIND_DEFAULT);
270         g_settings_bind (priv->gsettings_loc,
271                          EMPATHY_PREFS_LOCATION_PUBLISH,
272                          priv->checkbutton_location_resource_network,
273                          "sensitive",
274                          G_SETTINGS_BIND_GET);
275
276         g_settings_bind (priv->gsettings_loc,
277                          EMPATHY_PREFS_LOCATION_RESOURCE_CELL,
278                          priv->checkbutton_location_resource_cell,
279                          "active",
280                          G_SETTINGS_BIND_DEFAULT);
281         g_settings_bind (priv->gsettings_loc,
282                          EMPATHY_PREFS_LOCATION_PUBLISH,
283                          priv->checkbutton_location_resource_cell,
284                          "sensitive",
285                          G_SETTINGS_BIND_GET);
286
287         g_settings_bind (priv->gsettings_loc,
288                          EMPATHY_PREFS_LOCATION_RESOURCE_GPS,
289                          priv->checkbutton_location_resource_gps,
290                          "active",
291                          G_SETTINGS_BIND_DEFAULT);
292         g_settings_bind (priv->gsettings_loc,
293                          EMPATHY_PREFS_LOCATION_PUBLISH,
294                          priv->checkbutton_location_resource_gps,
295                          "sensitive",
296                          G_SETTINGS_BIND_GET);
297
298         g_settings_bind (priv->gsettings_loc,
299                          EMPATHY_PREFS_LOCATION_REDUCE_ACCURACY,
300                          priv->checkbutton_location_reduce_accuracy,
301                          "active",
302                          G_SETTINGS_BIND_DEFAULT);
303         g_settings_bind (priv->gsettings_loc,
304                          EMPATHY_PREFS_LOCATION_PUBLISH,
305                          priv->checkbutton_location_reduce_accuracy,
306                          "sensitive",
307                          G_SETTINGS_BIND_GET);
308
309         g_settings_bind (priv->gsettings_logger,
310                          EMPATHY_PREFS_LOGGER_ENABLED,
311                          priv->checkbutton_logging,
312                          "active",
313                          G_SETTINGS_BIND_DEFAULT);
314 }
315
316 static void
317 preferences_sound_cell_toggled_cb (GtkCellRendererToggle *toggle,
318                                    char *path_string,
319                                    EmpathyPreferences *preferences)
320 {
321         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
322         GtkTreePath *path;
323         gboolean toggled, instore;
324         GtkTreeIter iter;
325         GtkTreeView *view;
326         GtkTreeModel *model;
327         char *key;
328
329         view = GTK_TREE_VIEW (priv->treeview_sounds);
330         model = gtk_tree_view_get_model (view);
331
332         path = gtk_tree_path_new_from_string (path_string);
333         toggled = gtk_cell_renderer_toggle_get_active (toggle);
334
335         gtk_tree_model_get_iter (model, &iter, path);
336         gtk_tree_model_get (model, &iter, COL_SOUND_KEY, &key,
337                             COL_SOUND_ENABLED, &instore, -1);
338
339         instore ^= 1;
340
341         gtk_list_store_set (GTK_LIST_STORE (model), &iter,
342                             COL_SOUND_ENABLED, instore, -1);
343
344         g_settings_set_boolean (priv->gsettings_sound, key, instore);
345
346         g_free (key);
347         gtk_tree_path_free (path);
348 }
349
350 static void
351 preferences_sound_load (EmpathyPreferences *preferences)
352 {
353         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
354         guint i;
355         GtkTreeView *view;
356         GtkListStore *store;
357         GtkTreeIter iter;
358         gboolean set;
359
360         view = GTK_TREE_VIEW (priv->treeview_sounds);
361         store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
362
363         for (i = 0; i < G_N_ELEMENTS (sound_entries); i++) {
364                 set = g_settings_get_boolean (priv->gsettings_sound,
365                                               sound_entries[i].key);
366
367                 gtk_list_store_insert_with_values (store, &iter, i,
368                                                    COL_SOUND_NAME, gettext (sound_entries[i].name),
369                                                    COL_SOUND_KEY, sound_entries[i].key,
370                                                    COL_SOUND_ENABLED, set, -1);
371         }
372 }
373
374 static void
375 preferences_sound_setup (EmpathyPreferences *preferences)
376 {
377         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
378         GtkTreeView *view;
379         GtkListStore *store;
380         GtkCellRenderer *renderer;
381         GtkTreeViewColumn *column;
382
383         view = GTK_TREE_VIEW (priv->treeview_sounds);
384
385         store = gtk_list_store_new (COL_SOUND_COUNT,
386                                     G_TYPE_BOOLEAN, /* enabled */
387                                     G_TYPE_STRING,  /* name */
388                                     G_TYPE_STRING); /* key */
389
390         gtk_tree_view_set_model (view, GTK_TREE_MODEL (store));
391
392         renderer = gtk_cell_renderer_toggle_new ();
393         g_signal_connect (renderer, "toggled",
394                           G_CALLBACK (preferences_sound_cell_toggled_cb),
395                           preferences);
396
397         column = gtk_tree_view_column_new ();
398         gtk_tree_view_column_pack_start (column, renderer, FALSE);
399         gtk_tree_view_column_add_attribute (column, renderer,
400                                             "active", COL_SOUND_ENABLED);
401
402         renderer = gtk_cell_renderer_text_new ();
403         gtk_tree_view_column_pack_start (column, renderer, FALSE);
404         gtk_tree_view_column_add_attribute (column, renderer,
405                                             "text", COL_SOUND_NAME);
406
407         gtk_tree_view_append_column (view, column);
408
409         gtk_tree_view_column_set_resizable (column, FALSE);
410         gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
411
412         g_object_unref (store);
413 }
414
415 static void
416 preferences_languages_setup (EmpathyPreferences *preferences)
417 {
418         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
419         GtkTreeView       *view;
420         GtkListStore      *store;
421         GtkTreeSelection  *selection;
422         GtkTreeModel      *model;
423         GtkTreeViewColumn *column;
424         GtkCellRenderer   *renderer;
425         guint              col_offset;
426
427         view = GTK_TREE_VIEW (priv->treeview_spell_checker);
428
429         store = gtk_list_store_new (COL_LANG_COUNT,
430                                     G_TYPE_BOOLEAN,  /* enabled */
431                                     G_TYPE_STRING,   /* code */
432                                     G_TYPE_STRING);  /* name */
433
434         gtk_tree_view_set_model (view, GTK_TREE_MODEL (store));
435
436         selection = gtk_tree_view_get_selection (view);
437         gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
438
439         model = GTK_TREE_MODEL (store);
440
441         renderer = gtk_cell_renderer_toggle_new ();
442         g_signal_connect (renderer, "toggled",
443                           G_CALLBACK (preferences_languages_cell_toggled_cb),
444                           preferences);
445
446         column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
447                                                            "active", COL_LANG_ENABLED,
448                                                            NULL);
449
450         gtk_tree_view_append_column (view, column);
451
452         renderer = gtk_cell_renderer_text_new ();
453         col_offset = gtk_tree_view_insert_column_with_attributes (view,
454                                                                   -1, _("Language"),
455                                                                   renderer,
456                                                                   "text", COL_LANG_NAME,
457                                                                   NULL);
458
459         g_object_set_data (G_OBJECT (renderer),
460                            "column", GINT_TO_POINTER (COL_LANG_NAME));
461
462         column = gtk_tree_view_get_column (view, col_offset - 1);
463         gtk_tree_view_column_set_sort_column_id (column, COL_LANG_NAME);
464         gtk_tree_view_column_set_resizable (column, FALSE);
465         gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
466
467         g_object_unref (store);
468 }
469
470 static void
471 preferences_languages_add (EmpathyPreferences *preferences)
472 {
473         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
474         GtkTreeView  *view;
475         GtkListStore *store;
476         GList        *codes, *l;
477
478         view = GTK_TREE_VIEW (priv->treeview_spell_checker);
479         store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
480
481         codes = empathy_spell_get_language_codes ();
482
483         if (!codes) {
484                 gtk_widget_set_sensitive (priv->treeview_spell_checker, FALSE);
485         }
486
487         for (l = codes; l; l = l->next) {
488                 GtkTreeIter  iter;
489                 const gchar *code;
490                 const gchar *name;
491
492                 code = l->data;
493                 name = empathy_spell_get_language_name (code);
494                 if (!name) {
495                         continue;
496                 }
497
498                 gtk_list_store_append (store, &iter);
499                 gtk_list_store_set (store, &iter,
500                                     COL_LANG_CODE, code,
501                                     COL_LANG_NAME, name,
502                                     -1);
503         }
504
505         empathy_spell_free_language_codes (codes);
506 }
507
508 static void
509 preferences_languages_save (EmpathyPreferences *preferences)
510 {
511         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
512         GtkTreeView       *view;
513         GtkTreeModel      *model;
514
515         gchar             *languages = NULL;
516
517         view = GTK_TREE_VIEW (priv->treeview_spell_checker);
518         model = gtk_tree_view_get_model (view);
519
520         gtk_tree_model_foreach (model,
521                                 (GtkTreeModelForeachFunc) preferences_languages_save_foreach,
522                                 &languages);
523
524         /* if user selects no languages, we don't want spell check */
525         g_settings_set_boolean (priv->gsettings_chat,
526                                 EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED,
527                                 languages != NULL);
528
529         g_settings_set_string (priv->gsettings_chat,
530                                EMPATHY_PREFS_CHAT_SPELL_CHECKER_LANGUAGES,
531                                languages != NULL ? languages : "");
532
533         g_free (languages);
534 }
535
536 static gboolean
537 preferences_languages_save_foreach (GtkTreeModel  *model,
538                                     GtkTreePath   *path,
539                                     GtkTreeIter   *iter,
540                                     gchar        **languages)
541 {
542         gboolean  enabled;
543         gchar    *code;
544
545         if (!languages) {
546                 return TRUE;
547         }
548
549         gtk_tree_model_get (model, iter, COL_LANG_ENABLED, &enabled, -1);
550         if (!enabled) {
551                 return FALSE;
552         }
553
554         gtk_tree_model_get (model, iter, COL_LANG_CODE, &code, -1);
555         if (!code) {
556                 return FALSE;
557         }
558
559         if (!(*languages)) {
560                 *languages = g_strdup (code);
561         } else {
562                 gchar *str = *languages;
563                 *languages = g_strdup_printf ("%s,%s", str, code);
564                 g_free (str);
565         }
566
567         g_free (code);
568
569         return FALSE;
570 }
571
572 static void
573 preferences_languages_load (EmpathyPreferences *preferences)
574 {
575         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
576         GtkTreeView   *view;
577         GtkTreeModel  *model;
578         GList         *enabled_codes;
579
580         enabled_codes = empathy_spell_get_enabled_language_codes ();
581
582         g_settings_set_boolean (priv->gsettings_chat,
583                                 EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED,
584                                 enabled_codes != NULL);
585
586         if (enabled_codes == NULL)
587                 return;
588
589         view = GTK_TREE_VIEW (priv->treeview_spell_checker);
590         model = gtk_tree_view_get_model (view);
591
592         gtk_tree_model_foreach (model,
593                                 (GtkTreeModelForeachFunc) preferences_languages_load_foreach,
594                                 enabled_codes);
595
596         g_list_free (enabled_codes);
597 }
598
599 static gboolean
600 preferences_languages_load_foreach (GtkTreeModel  *model,
601                                     GtkTreePath   *path,
602                                     GtkTreeIter   *iter,
603                                     GList         *languages)
604 {
605         gchar    *code;
606         gboolean  found = FALSE;
607
608         if (!languages) {
609                 return TRUE;
610         }
611
612         gtk_tree_model_get (model, iter, COL_LANG_CODE, &code, -1);
613         if (!code) {
614                 return FALSE;
615         }
616
617         if (g_list_find_custom (languages, code, (GCompareFunc) strcmp)) {
618                 found = TRUE;
619         }
620
621         g_free (code);
622         gtk_list_store_set (GTK_LIST_STORE (model), iter, COL_LANG_ENABLED, found, -1);
623         return FALSE;
624 }
625
626 static void
627 preferences_languages_cell_toggled_cb (GtkCellRendererToggle *cell,
628                                        gchar                 *path_string,
629                                        EmpathyPreferences     *preferences)
630 {
631         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
632         GtkTreeView  *view;
633         GtkTreeModel *model;
634         GtkListStore *store;
635         GtkTreePath  *path;
636         GtkTreeIter   iter;
637         gboolean      enabled;
638
639         view = GTK_TREE_VIEW (priv->treeview_spell_checker);
640         model = gtk_tree_view_get_model (view);
641         store = GTK_LIST_STORE (model);
642
643         path = gtk_tree_path_new_from_string (path_string);
644
645         gtk_tree_model_get_iter (model, &iter, path);
646         gtk_tree_model_get (model, &iter, COL_LANG_ENABLED, &enabled, -1);
647
648         enabled ^= 1;
649
650         gtk_list_store_set (store, &iter, COL_LANG_ENABLED, enabled, -1);
651         gtk_tree_path_free (path);
652
653         preferences_languages_save (preferences);
654 }
655
656 static void
657 preferences_preview_theme_append_message (EmpathyChatView *view,
658                                           EmpathyContact *sender,
659                                           EmpathyContact *receiver,
660                                           const gchar *text)
661 {
662         EmpathyMessage *message;
663
664         message = g_object_new (EMPATHY_TYPE_MESSAGE,
665                 "sender", sender,
666                 "receiver", receiver,
667                 "body", text,
668                 NULL);
669
670         empathy_chat_view_append_message (view, message);
671         g_object_unref (message);
672 }
673
674 static void
675 preferences_preview_theme_changed_cb (EmpathyThemeManager *manager,
676                                       EmpathyPreferences  *preferences)
677 {
678         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
679         TpDBusDaemon *dbus;
680         TpAccount *account;
681         EmpathyContact *juliet;
682         EmpathyContact *romeo;
683
684         DEBUG ("Theme changed, update preview widget");
685
686         if (priv->chat_theme_preview != NULL) {
687                 gtk_widget_destroy (GTK_WIDGET (priv->chat_theme_preview));
688         }
689         priv->chat_theme_preview = empathy_theme_manager_create_view (manager);
690         gtk_container_add (GTK_CONTAINER (priv->sw_chat_theme_preview),
691                            GTK_WIDGET (priv->chat_theme_preview));
692         gtk_widget_show (GTK_WIDGET (priv->chat_theme_preview));
693
694         /* FIXME: It is ugly to add a fake conversation like that.
695          * Would be cool if we could request a TplLogManager for a fake
696          * conversation */
697         dbus = tp_dbus_daemon_dup (NULL);
698         account = tp_account_new (dbus,
699                 TP_ACCOUNT_OBJECT_PATH_BASE "cm/jabber/account", NULL);
700         juliet = g_object_new (EMPATHY_TYPE_CONTACT,
701                 "account", account,
702                 "id", "juliet",
703                 /* translators: Contact name for the chat theme preview */
704                 "alias", _("Juliet"),
705                 "is-user", FALSE,
706                 NULL);
707         romeo = g_object_new (EMPATHY_TYPE_CONTACT,
708                 "account", account,
709                 "id", "romeo",
710                 /* translators: Contact name for the chat theme preview */
711                 "alias", _("Romeo"),
712                 "is-user", TRUE,
713                 NULL);
714
715         preferences_preview_theme_append_message (priv->chat_theme_preview,
716                 /* translators: Quote from Romeo & Julier, for chat theme preview */
717                 juliet, romeo, _("O Romeo, Romeo, wherefore art thou Romeo?"));
718         preferences_preview_theme_append_message (priv->chat_theme_preview,
719                 /* translators: Quote from Romeo & Julier, for chat theme preview */
720                 juliet, romeo, _("Deny thy father and refuse thy name;"));
721         preferences_preview_theme_append_message (priv->chat_theme_preview,
722                 /* translators: Quote from Romeo & Julier, for chat theme preview */
723                 juliet, romeo, _("Or if thou wilt not, be but sworn my love"));
724         preferences_preview_theme_append_message (priv->chat_theme_preview,
725                 /* translators: Quote from Romeo & Julier, for chat theme preview */
726                 juliet, romeo, _("And I'll no longer be a Capulet."));
727         preferences_preview_theme_append_message (priv->chat_theme_preview,
728                 /* translators: Quote from Romeo & Julier, for chat theme preview */
729                 romeo, juliet, _("Shall I hear more, or shall I speak at this?"));
730
731         /* translators: Quote from Romeo & Julier, for chat theme preview */
732         empathy_chat_view_append_event (priv->chat_theme_preview, _("Juliet has disconnected"));
733
734         g_object_unref (juliet);
735         g_object_unref (romeo);
736         g_object_unref (account);
737         g_object_unref (dbus);
738 }
739
740 static void
741 preferences_theme_changed_cb (GtkComboBox        *combo,
742                               EmpathyPreferences *preferences)
743 {
744         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
745         GtkTreeIter   iter;
746
747         if (gtk_combo_box_get_active_iter (combo, &iter)) {
748                 GtkTreeModel *model;
749                 gboolean      is_adium;
750                 gchar        *name;
751                 gchar        *path;
752
753                 model = gtk_combo_box_get_model (combo);
754                 gtk_tree_model_get (model, &iter,
755                                     COL_THEME_IS_ADIUM, &is_adium,
756                                     COL_THEME_NAME, &name,
757                                     COL_THEME_ADIUM_PATH, &path,
758                                     -1);
759
760                 g_settings_set_string (priv->gsettings_chat,
761                                        EMPATHY_PREFS_CHAT_THEME,
762                                        name);
763                 if (is_adium) {
764                         g_settings_set_string (priv->gsettings_chat,
765                                                EMPATHY_PREFS_CHAT_ADIUM_PATH,
766                                                path);
767                 }
768
769                 g_free (name);
770                 g_free (path);
771         }
772 }
773
774 static void
775 preferences_theme_notify_cb (GSettings   *gsettings,
776                              const gchar *key,
777                              gpointer     user_data)
778 {
779         EmpathyPreferences *preferences = user_data;
780         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
781         GtkComboBox        *combo;
782         gchar              *conf_name;
783         gchar              *conf_path;
784         GtkTreeModel       *model;
785         GtkTreeIter         iter;
786         gboolean            found = FALSE;
787         gboolean            ok;
788
789         conf_name = g_settings_get_string (gsettings, EMPATHY_PREFS_CHAT_THEME);
790         conf_path = g_settings_get_string (gsettings, EMPATHY_PREFS_CHAT_ADIUM_PATH);
791
792         combo = GTK_COMBO_BOX (priv->combobox_chat_theme);
793         model = gtk_combo_box_get_model (combo);
794         for (ok = gtk_tree_model_get_iter_first (model, &iter);
795              ok && !found;
796              ok = gtk_tree_model_iter_next (model, &iter)) {
797                 gboolean is_adium;
798                 gchar *name;
799                 gchar *path;
800
801                 gtk_tree_model_get (model, &iter,
802                                     COL_THEME_IS_ADIUM, &is_adium,
803                                     COL_THEME_NAME, &name,
804                                     COL_THEME_ADIUM_PATH, &path,
805                                     -1);
806
807                 if (!tp_strdiff (name, conf_name) &&
808                     (!is_adium || !tp_strdiff (path, conf_path))) {
809                         found = TRUE;
810                         gtk_combo_box_set_active_iter (combo, &iter);
811                 }
812
813                 g_free (name);
814                 g_free (path);
815         }
816
817         /* Fallback to the first one. */
818         if (!found) {
819                 if (gtk_tree_model_get_iter_first (model, &iter)) {
820                         gtk_combo_box_set_active_iter (combo, &iter);
821                 }
822         }
823
824         g_free (conf_name);
825         g_free (conf_path);
826 }
827
828 static void
829 preferences_themes_setup (EmpathyPreferences *preferences)
830 {
831         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
832         GtkComboBox   *combo;
833         GtkCellLayout *cell_layout;
834         GtkCellRenderer *renderer;
835         GtkListStore  *store;
836         const gchar  **themes;
837         GList         *adium_themes;
838         gint           i;
839
840         combo = GTK_COMBO_BOX (priv->combobox_chat_theme);
841         cell_layout = GTK_CELL_LAYOUT (combo);
842
843         /* Create the model */
844         store = gtk_list_store_new (COL_THEME_COUNT,
845                                     G_TYPE_STRING,      /* Display name */
846                                     G_TYPE_STRING,      /* Theme name */
847                                     G_TYPE_BOOLEAN,     /* Is an Adium theme */
848                                     G_TYPE_STRING);     /* Adium theme path */
849         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
850                 COL_THEME_VISIBLE_NAME, GTK_SORT_ASCENDING);
851
852         /* Fill the model */
853         themes = empathy_theme_manager_get_themes ();
854         for (i = 0; themes[i]; i += 2) {
855                 gtk_list_store_insert_with_values (store, NULL, -1,
856                         COL_THEME_VISIBLE_NAME, _(themes[i + 1]),
857                         COL_THEME_NAME, themes[i],
858                         COL_THEME_IS_ADIUM, FALSE,
859                         -1);
860         }
861
862         adium_themes = empathy_theme_manager_get_adium_themes ();
863         while (adium_themes != NULL) {
864                 GHashTable *info;
865                 const gchar *name;
866                 const gchar *path;
867
868                 info = adium_themes->data;
869                 name = tp_asv_get_string (info, "CFBundleName");
870                 path = tp_asv_get_string (info, "path");
871
872                 if (name != NULL && path != NULL) {
873                         gtk_list_store_insert_with_values (store, NULL, -1,
874                                 COL_THEME_VISIBLE_NAME, name,
875                                 COL_THEME_NAME, "adium",
876                                 COL_THEME_IS_ADIUM, TRUE,
877                                 COL_THEME_ADIUM_PATH, path,
878                                 -1);
879                 }
880                 g_hash_table_unref (info);
881                 adium_themes = g_list_delete_link (adium_themes, adium_themes);
882         }
883
884         /* Add cell renderer */
885         renderer = gtk_cell_renderer_text_new ();
886         gtk_cell_layout_pack_start (cell_layout, renderer, TRUE);
887         gtk_cell_layout_set_attributes (cell_layout, renderer,
888                 "text", COL_THEME_VISIBLE_NAME, NULL);
889
890         gtk_combo_box_set_model (combo, GTK_TREE_MODEL (store));
891         g_object_unref (store);
892
893         g_signal_connect (combo, "changed",
894                           G_CALLBACK (preferences_theme_changed_cb),
895                           preferences);
896
897         /* Select the theme from the GSetting key and track changes */
898         preferences_theme_notify_cb (priv->gsettings_chat,
899                                      EMPATHY_PREFS_CHAT_THEME,
900                                      preferences);
901         g_signal_connect (priv->gsettings_chat,
902                           "changed::" EMPATHY_PREFS_CHAT_THEME,
903                           G_CALLBACK (preferences_theme_notify_cb),
904                           preferences);
905
906         g_signal_connect (priv->gsettings_chat,
907                           "changed::" EMPATHY_PREFS_CHAT_ADIUM_PATH,
908                           G_CALLBACK (preferences_theme_notify_cb),
909                           preferences);
910 }
911
912 static void
913 empathy_preferences_response (GtkDialog *widget,
914                               gint response)
915 {
916         gtk_widget_destroy (GTK_WIDGET (widget));
917 }
918
919 static void
920 empathy_preferences_finalize (GObject *self)
921 {
922         EmpathyPreferencesPriv *priv = GET_PRIV (self);
923
924         g_object_unref (priv->theme_manager);
925
926         g_object_unref (priv->gsettings);
927         g_object_unref (priv->gsettings_chat);
928         g_object_unref (priv->gsettings_loc);
929         g_object_unref (priv->gsettings_notify);
930         g_object_unref (priv->gsettings_sound);
931         g_object_unref (priv->gsettings_ui);
932         g_object_unref (priv->gsettings_logger);
933
934         G_OBJECT_CLASS (empathy_preferences_parent_class)->finalize (self);
935 }
936
937 static void
938 empathy_preferences_class_init (EmpathyPreferencesClass *klass)
939 {
940         GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (klass);
941         GObjectClass *object_class = G_OBJECT_CLASS (klass);
942
943         dialog_class->response = empathy_preferences_response;
944
945         object_class->finalize = empathy_preferences_finalize;
946
947         g_type_class_add_private (object_class,
948                                   sizeof (EmpathyPreferencesPriv));
949 }
950
951 static void
952 empathy_preferences_init (EmpathyPreferences *preferences)
953 {
954         EmpathyPreferencesPriv    *priv;
955         GtkBuilder                *gui;
956         gchar                     *filename;
957         GtkWidget                 *page;
958
959         priv = preferences->priv = G_TYPE_INSTANCE_GET_PRIVATE (preferences,
960                         EMPATHY_TYPE_PREFERENCES, EmpathyPreferencesPriv);
961
962         gtk_dialog_add_button (GTK_DIALOG (preferences),
963                                GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
964
965         gtk_container_set_border_width (GTK_CONTAINER (preferences), 5);
966         gtk_window_set_title (GTK_WINDOW (preferences), _("Preferences"));
967         gtk_window_set_role (GTK_WINDOW (preferences), "preferences");
968         gtk_window_set_position (GTK_WINDOW (preferences),
969                                  GTK_WIN_POS_CENTER_ON_PARENT);
970         gtk_window_set_icon_name (GTK_WINDOW (preferences), "gtk-preferences");
971
972         filename = empathy_file_lookup ("empathy-preferences.ui", "src");
973         gui = empathy_builder_get_file (filename,
974                 "notebook", &priv->notebook,
975                 "checkbutton_show_smileys", &priv->checkbutton_show_smileys,
976                 "checkbutton_show_contacts_in_rooms", &priv->checkbutton_show_contacts_in_rooms,
977                 "vbox_chat_theme", &priv->vbox_chat_theme,
978                 "combobox_chat_theme", &priv->combobox_chat_theme,
979                 "sw_chat_theme_preview", &priv->sw_chat_theme_preview,
980                 "checkbutton_separate_chat_windows", &priv->checkbutton_separate_chat_windows,
981                 "checkbutton_events_notif_area", &priv->checkbutton_events_notif_area,
982                 "checkbutton_autoconnect", &priv->checkbutton_autoconnect,
983                 "checkbutton_logging", &priv->checkbutton_logging,
984                 "checkbutton_notifications_enabled", &priv->checkbutton_notifications_enabled,
985                 "checkbutton_notifications_disabled_away", &priv->checkbutton_notifications_disabled_away,
986                 "checkbutton_notifications_focus", &priv->checkbutton_notifications_focus,
987                 "checkbutton_notifications_contact_signin", &priv->checkbutton_notifications_contact_signin,
988                 "checkbutton_notifications_contact_signout", &priv->checkbutton_notifications_contact_signout,
989                 "checkbutton_sounds_enabled", &priv->checkbutton_sounds_enabled,
990                 "checkbutton_sounds_disabled_away", &priv->checkbutton_sounds_disabled_away,
991                 "treeview_sounds", &priv->treeview_sounds,
992                 "treeview_spell_checker", &priv->treeview_spell_checker,
993                 "checkbutton_location_publish", &priv->checkbutton_location_publish,
994                 "checkbutton_location_reduce_accuracy", &priv->checkbutton_location_reduce_accuracy,
995                 "checkbutton_location_resource_network", &priv->checkbutton_location_resource_network,
996                 "checkbutton_location_resource_cell", &priv->checkbutton_location_resource_cell,
997                 "checkbutton_location_resource_gps", &priv->checkbutton_location_resource_gps,
998                 NULL);
999         g_free (filename);
1000
1001         gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (preferences))), priv->notebook);
1002         gtk_widget_show (priv->notebook);
1003
1004         g_object_unref (gui);
1005
1006         priv->gsettings = g_settings_new (EMPATHY_PREFS_SCHEMA);
1007         priv->gsettings_chat = g_settings_new (EMPATHY_PREFS_CHAT_SCHEMA);
1008         priv->gsettings_loc = g_settings_new (EMPATHY_PREFS_LOCATION_SCHEMA);
1009         priv->gsettings_notify = g_settings_new (EMPATHY_PREFS_NOTIFICATIONS_SCHEMA);
1010         priv->gsettings_sound = g_settings_new (EMPATHY_PREFS_SOUNDS_SCHEMA);
1011         priv->gsettings_ui = g_settings_new (EMPATHY_PREFS_UI_SCHEMA);
1012         priv->gsettings_logger = g_settings_new (EMPATHY_PREFS_LOGGER_SCHEMA);
1013
1014         /* Create chat theme preview, and track changes */
1015         priv->theme_manager = empathy_theme_manager_dup_singleton ();
1016         tp_g_signal_connect_object (priv->theme_manager, "theme-changed",
1017                           G_CALLBACK (preferences_preview_theme_changed_cb),
1018                           preferences, 0);
1019         preferences_preview_theme_changed_cb (priv->theme_manager, preferences);
1020
1021         preferences_themes_setup (preferences);
1022
1023         preferences_setup_widgets (preferences);
1024
1025         preferences_languages_setup (preferences);
1026         preferences_languages_add (preferences);
1027         preferences_languages_load (preferences);
1028
1029         preferences_sound_setup (preferences);
1030         preferences_sound_load (preferences);
1031
1032         if (empathy_spell_supported ()) {
1033                 page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), 2);
1034                 gtk_widget_show (page);
1035         }
1036
1037         page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), 3);
1038 #ifdef HAVE_GEOCLUE
1039         gtk_widget_show (page);
1040 #else
1041         gtk_widget_hide (page);
1042 #endif
1043 }
1044
1045 GtkWidget *
1046 empathy_preferences_new (GtkWindow *parent)
1047 {
1048         GtkWidget *self;
1049
1050         g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), NULL);
1051
1052         self = g_object_new (EMPATHY_TYPE_PREFERENCES, NULL);
1053
1054         if (parent != NULL) {
1055                 gtk_window_set_transient_for (GTK_WINDOW (self),
1056                                               parent);
1057         }
1058
1059         return self;
1060 }