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