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