]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-account-widget.c
Merge branch 'fix-586098'
[empathy.git] / libempathy-gtk / empathy-account-widget.c
1 /*
2  * Copyright (C) 2006-2007 Imendio AB
3  * Copyright (C) 2007-2009 Collabora Ltd.
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: Xavier Claessens <xclaesse@gmail.com>
21  *          Martyn Russell <martyn@imendio.com>
22  *          Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
23  *          Jonathan Tellier <jonathan.tellier@gmail.com>
24  */
25
26 #include <config.h>
27
28 #include <string.h>
29
30 #include <gtk/gtk.h>
31 #include <glib/gi18n-lib.h>
32
33 #ifdef HAVE_MOBLIN
34 #include <nbtk/nbtk-gtk.h>
35 #endif
36
37 #include <libempathy/empathy-utils.h>
38 #include <libempathy/empathy-idle.h>
39
40 #include <telepathy-glib/account.h>
41 #include <telepathy-glib/connection-manager.h>
42 #include <telepathy-glib/util.h>
43 #include <dbus/dbus-protocol.h>
44
45 #include "empathy-account-widget.h"
46 #include "empathy-account-widget-private.h"
47 #include "empathy-account-widget-sip.h"
48 #include "empathy-account-widget-irc.h"
49 #include "empathy-ui-utils.h"
50
51 #define DEBUG_FLAG EMPATHY_DEBUG_ACCOUNT
52 #include <libempathy/empathy-debug.h>
53
54 G_DEFINE_TYPE (EmpathyAccountWidget, empathy_account_widget, G_TYPE_OBJECT)
55
56 typedef struct {
57   EmpathyAccountSettings *settings;
58
59   GtkWidget *table_common_settings;
60   GtkWidget *apply_button;
61   GtkWidget *cancel_button;
62   GtkWidget *entry_password;
63   GtkWidget *button_forget;
64   GtkWidget *spinbutton_port;
65   GtkWidget *enabled_checkbox;
66
67   gboolean simple;
68
69   gboolean contains_pending_changes;
70
71   /* An EmpathyAccountWidget can be used to either create an account or
72    * modify it. When we are creating an account, this member is set to TRUE */
73   gboolean creating_account;
74
75   EmpathyIdle *idle;
76
77   gboolean dispose_run;
78 } EmpathyAccountWidgetPriv;
79
80 enum {
81   PROP_PROTOCOL = 1,
82   PROP_SETTINGS,
83   PROP_SIMPLE,
84   PROP_CREATING_ACCOUNT
85 };
86
87 enum {
88   HANDLE_APPLY,
89   ACCOUNT_CREATED,
90   CANCELLED,
91   LAST_SIGNAL
92 };
93
94 static guint signals[LAST_SIGNAL] = { 0 };
95
96 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccountWidget)
97 #define CHANGED_TIMEOUT 300
98
99 static void
100 account_widget_set_control_buttons_sensitivity (EmpathyAccountWidget *self,
101     gboolean sensitive)
102 {
103   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
104
105   if (!priv->simple)
106     {
107       gtk_widget_set_sensitive (priv->apply_button, sensitive);
108       gtk_widget_set_sensitive (
109           priv->cancel_button, sensitive || priv->creating_account);
110
111       priv->contains_pending_changes = sensitive;
112     }
113 }
114
115 static void
116 account_widget_handle_control_buttons_sensitivity (EmpathyAccountWidget *self)
117 {
118   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
119   gboolean is_valid;
120
121   is_valid = empathy_account_settings_is_valid (priv->settings);
122
123   if (!priv->simple)
124       account_widget_set_control_buttons_sensitivity (self, is_valid);
125
126   g_signal_emit (self, signals[HANDLE_APPLY], 0, is_valid);
127 }
128
129 static void
130 account_widget_entry_changed_common (EmpathyAccountWidget *self,
131     GtkEntry *entry, gboolean focus)
132 {
133   const gchar *str;
134   const gchar *param_name;
135   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
136
137   str = gtk_entry_get_text (entry);
138   param_name = g_object_get_data (G_OBJECT (entry), "param_name");
139
140   if (EMP_STR_EMPTY (str))
141     {
142       const gchar *value = NULL;
143
144       empathy_account_settings_unset (priv->settings, param_name);
145
146       if (focus)
147         {
148           value = empathy_account_settings_get_string (priv->settings,
149               param_name);
150           DEBUG ("Unset %s and restore to %s", param_name, value);
151           gtk_entry_set_text (entry, value ? value : "");
152         }
153     }
154   else
155     {
156       DEBUG ("Setting %s to %s", param_name,
157           tp_strdiff (param_name, "password") ? str : "***");
158       empathy_account_settings_set_string (priv->settings, param_name, str);
159     }
160 }
161
162 static void
163 account_widget_entry_changed_cb (GtkEditable *entry,
164     EmpathyAccountWidget *self)
165 {
166   account_widget_entry_changed_common (self, GTK_ENTRY (entry), FALSE);
167   account_widget_handle_control_buttons_sensitivity (self);
168 }
169
170 static void
171 account_widget_int_changed_cb (GtkWidget *widget,
172     EmpathyAccountWidget *self)
173 {
174   const gchar *param_name;
175   gint value;
176   const gchar *signature;
177   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
178
179   value = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
180   param_name = g_object_get_data (G_OBJECT (widget), "param_name");
181
182   signature = empathy_account_settings_get_dbus_signature (priv->settings,
183     param_name);
184   g_return_if_fail (signature != NULL);
185
186   DEBUG ("Setting %s to %d", param_name, value);
187
188   switch ((int)*signature)
189     {
190     case DBUS_TYPE_INT16:
191     case DBUS_TYPE_INT32:
192       empathy_account_settings_set_int32 (priv->settings, param_name, value);
193       break;
194     case DBUS_TYPE_INT64:
195       empathy_account_settings_set_int64 (priv->settings, param_name, value);
196       break;
197     case DBUS_TYPE_UINT16:
198     case DBUS_TYPE_UINT32:
199       empathy_account_settings_set_uint32 (priv->settings, param_name, value);
200       break;
201     case DBUS_TYPE_UINT64:
202       empathy_account_settings_set_uint64 (priv->settings, param_name, value);
203       break;
204     default:
205       g_return_if_reached ();
206     }
207
208   account_widget_handle_control_buttons_sensitivity (self);
209 }
210
211 static void
212 account_widget_checkbutton_toggled_cb (GtkWidget *widget,
213     EmpathyAccountWidget *self)
214 {
215   gboolean     value;
216   gboolean     default_value;
217   const gchar *param_name;
218   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
219
220   value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
221   param_name = g_object_get_data (G_OBJECT (widget), "param_name");
222
223   /* FIXME: This is ugly! checkbox don't have a "not-set" value so we
224    * always unset the param and set the value if different from the
225    * default value. */
226   empathy_account_settings_unset (priv->settings, param_name);
227   default_value = empathy_account_settings_get_boolean (priv->settings,
228       param_name);
229
230   if (default_value == value)
231     {
232       DEBUG ("Unset %s and restore to %d", param_name, default_value);
233     }
234   else
235     {
236       DEBUG ("Setting %s to %d", param_name, value);
237       empathy_account_settings_set_boolean (priv->settings, param_name, value);
238     }
239
240   account_widget_handle_control_buttons_sensitivity (self);
241 }
242
243 static void
244 account_widget_forget_clicked_cb (GtkWidget *button,
245     EmpathyAccountWidget *self)
246 {
247   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
248   const gchar *param_name;
249
250   param_name = g_object_get_data (G_OBJECT (priv->entry_password),
251       "param_name");
252
253   DEBUG ("Unset %s", param_name);
254   empathy_account_settings_unset (priv->settings, param_name);
255   gtk_entry_set_text (GTK_ENTRY (priv->entry_password), "");
256
257   account_widget_handle_control_buttons_sensitivity (self);
258 }
259
260 static void
261 account_widget_password_changed_cb (GtkWidget *entry,
262     EmpathyAccountWidget *self)
263 {
264   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
265   const gchar *str;
266
267   str = gtk_entry_get_text (GTK_ENTRY (entry));
268   gtk_widget_set_sensitive (priv->button_forget, !EMP_STR_EMPTY (str));
269 }
270
271 static void
272 account_widget_jabber_ssl_toggled_cb (GtkWidget *checkbutton_ssl,
273     EmpathyAccountWidget *self)
274 {
275   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
276   gboolean   value;
277   gint32       port = 0;
278
279   value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbutton_ssl));
280   port = empathy_account_settings_get_uint32 (priv->settings, "port");
281
282   if (value)
283     {
284       if (port == 5222 || port == 0)
285         port = 5223;
286     }
287   else
288     {
289       if (port == 5223 || port == 0)
290         port = 5222;
291     }
292
293   gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->spinbutton_port), port);
294 }
295
296 static void
297 account_widget_setup_widget (EmpathyAccountWidget *self,
298     GtkWidget *widget,
299     const gchar *param_name)
300 {
301   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
302
303   g_object_set_data_full (G_OBJECT (widget), "param_name",
304       g_strdup (param_name), g_free);
305
306   if (GTK_IS_SPIN_BUTTON (widget))
307     {
308       gint value = 0;
309       const gchar *signature;
310
311       signature = empathy_account_settings_get_dbus_signature (priv->settings,
312           param_name);
313       g_return_if_fail (signature != NULL);
314
315       switch ((int)*signature)
316         {
317           case DBUS_TYPE_INT16:
318           case DBUS_TYPE_INT32:
319             value = empathy_account_settings_get_int32 (priv->settings,
320               param_name);
321             break;
322           case DBUS_TYPE_INT64:
323             value = empathy_account_settings_get_int64 (priv->settings,
324               param_name);
325             break;
326           case DBUS_TYPE_UINT16:
327           case DBUS_TYPE_UINT32:
328             value = empathy_account_settings_get_uint32 (priv->settings,
329               param_name);
330             break;
331           case DBUS_TYPE_UINT64:
332             value = empathy_account_settings_get_uint64 (priv->settings,
333                 param_name);
334             break;
335           default:
336             g_return_if_reached ();
337         }
338
339       gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
340
341       g_signal_connect (widget, "value-changed",
342           G_CALLBACK (account_widget_int_changed_cb),
343           self);
344     }
345   else if (GTK_IS_ENTRY (widget))
346     {
347       const gchar *str = NULL;
348
349       str = empathy_account_settings_get_string (priv->settings, param_name);
350       gtk_entry_set_text (GTK_ENTRY (widget), str ? str : "");
351
352       if (strstr (param_name, "password"))
353         {
354           gtk_entry_set_visibility (GTK_ENTRY (widget), FALSE);
355         }
356
357       g_signal_connect (widget, "changed",
358           G_CALLBACK (account_widget_entry_changed_cb), self);
359     }
360   else if (GTK_IS_TOGGLE_BUTTON (widget))
361     {
362       gboolean value = FALSE;
363
364       value = empathy_account_settings_get_boolean (priv->settings,
365           param_name);
366       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), value);
367
368       g_signal_connect (widget, "toggled",
369           G_CALLBACK (account_widget_checkbutton_toggled_cb),
370           self);
371     }
372   else
373     {
374       DEBUG ("Unknown type of widget for param %s", param_name);
375     }
376 }
377
378 static gchar *
379 account_widget_generic_format_param_name (const gchar *param_name)
380 {
381   gchar *str;
382   gchar *p;
383
384   str = g_strdup (param_name);
385
386   if (str && g_ascii_isalpha (str[0]))
387     str[0] = g_ascii_toupper (str[0]);
388
389   while ((p = strchr (str, '-')) != NULL)
390     {
391       if (p[1] != '\0' && g_ascii_isalpha (p[1]))
392         {
393           p[0] = ' ';
394           p[1] = g_ascii_toupper (p[1]);
395         }
396
397       p++;
398     }
399
400   return str;
401 }
402
403 static void
404 accounts_widget_generic_setup (EmpathyAccountWidget *self,
405     GtkWidget *table_common_settings,
406     GtkWidget *table_advanced_settings)
407 {
408   TpConnectionManagerParam *params, *param;
409   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
410
411   params = empathy_account_settings_get_tp_params (priv->settings);
412
413   for (param = params; param != NULL && param->name != NULL; param++)
414     {
415       GtkWidget       *table_settings;
416       guint            n_rows = 0;
417       GtkWidget       *widget = NULL;
418       gchar           *param_name_formatted;
419
420       if (param->flags & TP_CONN_MGR_PARAM_FLAG_REQUIRED)
421         table_settings = table_common_settings;
422       else if (priv->simple)
423         return;
424       else
425         table_settings = table_advanced_settings;
426
427       param_name_formatted = account_widget_generic_format_param_name
428         (param->name);
429       g_object_get (table_settings, "n-rows", &n_rows, NULL);
430       gtk_table_resize (GTK_TABLE (table_settings), ++n_rows, 2);
431
432       if (param->dbus_signature[0] == 's')
433         {
434           gchar *str;
435
436           str = g_strdup_printf (_("%s:"), param_name_formatted);
437           widget = gtk_label_new (str);
438           gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
439           g_free (str);
440
441           gtk_table_attach (GTK_TABLE (table_settings),
442               widget,
443               0, 1,
444               n_rows - 1, n_rows,
445               GTK_FILL, 0,
446               0, 0);
447           gtk_widget_show (widget);
448
449           widget = gtk_entry_new ();
450           if (strcmp (param->name, "account") == 0)
451             {
452               g_signal_connect (widget, "realize",
453                   G_CALLBACK (gtk_widget_grab_focus),
454                   NULL);
455             }
456           gtk_table_attach (GTK_TABLE (table_settings),
457               widget,
458               1, 2,
459               n_rows - 1, n_rows,
460               GTK_FILL | GTK_EXPAND, 0,
461               0, 0);
462           gtk_widget_show (widget);
463         }
464       /* int types: ynqiuxt. double type is 'd' */
465       else if (param->dbus_signature[0] == 'y' ||
466           param->dbus_signature[0] == 'n' ||
467           param->dbus_signature[0] == 'q' ||
468           param->dbus_signature[0] == 'i' ||
469           param->dbus_signature[0] == 'u' ||
470           param->dbus_signature[0] == 'x' ||
471           param->dbus_signature[0] == 't' ||
472           param->dbus_signature[0] == 'd')
473         {
474           gchar   *str = NULL;
475           gdouble  minint = 0;
476           gdouble  maxint = 0;
477           gdouble  step = 1;
478
479           switch (param->dbus_signature[0])
480             {
481             case 'y': minint = G_MININT8;  maxint = G_MAXINT8;   break;
482             case 'n': minint = G_MININT16; maxint = G_MAXINT16;  break;
483             case 'q': minint = 0;          maxint = G_MAXUINT16; break;
484             case 'i': minint = G_MININT32; maxint = G_MAXINT32;  break;
485             case 'u': minint = 0;          maxint = G_MAXUINT32; break;
486             case 'x': minint = G_MININT64; maxint = G_MAXINT64;  break;
487             case 't': minint = 0;          maxint = G_MAXUINT64; break;
488             case 'd': minint = G_MININT32; maxint = G_MAXINT32;
489               step = 0.1; break;
490             }
491
492           str = g_strdup_printf (_("%s:"), param_name_formatted);
493           widget = gtk_label_new (str);
494           gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
495           g_free (str);
496
497           gtk_table_attach (GTK_TABLE (table_settings),
498               widget,
499               0, 1,
500               n_rows - 1, n_rows,
501               GTK_FILL, 0,
502               0, 0);
503           gtk_widget_show (widget);
504
505           widget = gtk_spin_button_new_with_range (minint, maxint, step);
506           gtk_table_attach (GTK_TABLE (table_settings),
507               widget,
508               1, 2,
509               n_rows - 1, n_rows,
510               GTK_FILL | GTK_EXPAND, 0,
511               0, 0);
512           gtk_widget_show (widget);
513         }
514       else if (param->dbus_signature[0] == 'b')
515         {
516           widget = gtk_check_button_new_with_label (param_name_formatted);
517           gtk_table_attach (GTK_TABLE (table_settings),
518               widget,
519               0, 2,
520               n_rows - 1, n_rows,
521               GTK_FILL | GTK_EXPAND, 0,
522               0, 0);
523           gtk_widget_show (widget);
524         }
525       else
526         {
527           DEBUG ("Unknown signature for param %s: %s",
528               param_name_formatted, param->dbus_signature);
529         }
530
531       if (widget)
532         account_widget_setup_widget (self, widget, param->name);
533
534       g_free (param_name_formatted);
535     }
536 }
537
538 static void
539 account_widget_handle_params_valist (EmpathyAccountWidget *self,
540     const gchar *first_widget,
541     va_list args)
542 {
543   GObject *object;
544   const gchar *name;
545
546   for (name = first_widget; name; name = va_arg (args, const gchar *))
547     {
548       const gchar *param_name;
549
550       param_name = va_arg (args, const gchar *);
551       object = gtk_builder_get_object (self->ui_details->gui, name);
552
553       if (!object)
554         {
555           g_warning ("Builder is missing object '%s'.", name);
556           continue;
557         }
558
559       account_widget_setup_widget (self, GTK_WIDGET (object), param_name);
560     }
561 }
562
563 static void
564 account_widget_cancel_clicked_cb (GtkWidget *button,
565     EmpathyAccountWidget *self)
566 {
567   g_signal_emit (self, signals[CANCELLED], 0);
568 }
569
570 static void
571 account_widget_account_enabled_cb (GObject *source_object,
572     GAsyncResult *res,
573     gpointer user_data)
574 {
575   GError *error = NULL;
576   TpAccount *account = TP_ACCOUNT (source_object);
577   EmpathyAccountWidget *widget = EMPATHY_ACCOUNT_WIDGET (user_data);
578
579   tp_account_set_enabled_finish (account, res, &error);
580
581   if (error != NULL)
582     {
583       DEBUG ("Could not automatically enable new account: %s", error->message);
584       g_error_free (error);
585     }
586   else
587     {
588       g_signal_emit (widget, signals[ACCOUNT_CREATED], 0);
589     }
590 }
591
592 static void
593 account_widget_applied_cb (GObject *source_object,
594     GAsyncResult *res,
595     gpointer user_data)
596 {
597   GError *error = NULL;
598   TpAccount *account;
599   EmpathyAccountSettings *settings = EMPATHY_ACCOUNT_SETTINGS (source_object);
600   EmpathyAccountWidget *widget = EMPATHY_ACCOUNT_WIDGET (user_data);
601   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
602
603   empathy_account_settings_apply_finish (settings, res, &error);
604
605   if (error != NULL)
606     {
607       DEBUG ("Could not apply changes to account: %s", error->message);
608       g_error_free (error);
609       return;
610     }
611
612   account = empathy_account_settings_get_account (priv->settings);
613
614   if (account != NULL)
615     {
616       if (priv->creating_account)
617         {
618           /* By default, when an account is created, we enable it. */
619           tp_account_set_enabled_async (account, TRUE,
620               account_widget_account_enabled_cb, widget);
621         }
622       else if (priv->enabled_checkbox != NULL)
623         {
624           gboolean enabled_checked;
625
626           enabled_checked =
627 #ifndef HAVE_MOBLIN
628             gtk_toggle_button_get_active (
629                 GTK_TOGGLE_BUTTON (priv->enabled_checkbox));
630 #else
631             nbtk_gtk_light_switch_get_active (
632                 NBTK_GTK_LIGHT_SWITCH (priv->enabled_checkbox));
633 #endif
634
635           if (tp_account_is_enabled (account) && enabled_checked)
636             {
637               /* After having applied changes to a user account, we
638                * automatically reconnect it. This is done so the new
639                * information entered by the user is validated on the server. */
640               tp_account_reconnect_async (account, NULL, NULL);
641             }
642         }
643     }
644
645   account_widget_set_control_buttons_sensitivity (widget, FALSE);
646 }
647
648 static void
649 account_widget_apply_clicked_cb (GtkWidget *button,
650     EmpathyAccountWidget *self)
651 {
652   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
653
654   empathy_account_settings_apply_async (priv->settings,
655       account_widget_applied_cb, self);
656 }
657
658 static void
659 account_widget_setup_generic (EmpathyAccountWidget *self)
660 {
661   GtkWidget *table_common_settings;
662   GtkWidget *table_advanced_settings;
663
664   table_common_settings = GTK_WIDGET (gtk_builder_get_object
665       (self->ui_details->gui, "table_common_settings"));
666   table_advanced_settings = GTK_WIDGET (gtk_builder_get_object
667       (self->ui_details->gui, "table_advanced_settings"));
668
669   accounts_widget_generic_setup (self, table_common_settings,
670       table_advanced_settings);
671
672   g_object_unref (self->ui_details->gui);
673 }
674
675 static void
676 account_widget_settings_ready_cb (EmpathyAccountSettings *settings,
677     GParamSpec *pspec,
678     gpointer user_data)
679 {
680   EmpathyAccountWidget *self = user_data;
681   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
682
683   if (empathy_account_settings_is_ready (priv->settings))
684     account_widget_setup_generic (self);
685 }
686
687 static void
688 account_widget_build_generic (EmpathyAccountWidget *self,
689     const char *filename)
690 {
691   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
692   GtkWidget *expander_advanced;
693
694   self->ui_details->gui = empathy_builder_get_file (filename,
695       "table_common_settings", &priv->table_common_settings,
696       "vbox_generic_settings", &self->ui_details->widget,
697       "expander_advanced_settings", &expander_advanced,
698       NULL);
699
700   if (priv->simple)
701     gtk_widget_hide (expander_advanced);
702
703   g_object_ref (self->ui_details->gui);
704
705   if (empathy_account_settings_is_ready (priv->settings))
706     account_widget_setup_generic (self);
707   else
708     g_signal_connect (priv->settings, "notify::ready",
709         G_CALLBACK (account_widget_settings_ready_cb), self);
710 }
711
712 static void
713 account_widget_build_salut (EmpathyAccountWidget *self,
714     const char *filename)
715 {
716   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
717
718   self->ui_details->gui = empathy_builder_get_file (filename,
719       "table_common_settings", &priv->table_common_settings,
720       "vbox_salut_settings", &self->ui_details->widget,
721       NULL);
722
723   empathy_account_widget_handle_params (self,
724       "entry_published", "published-name",
725       "entry_nickname", "nickname",
726       "entry_first_name", "first-name",
727       "entry_last_name", "last-name",
728       "entry_email", "email",
729       "entry_jid", "jid",
730       NULL);
731
732   self->ui_details->default_focus = g_strdup ("entry_nickname");
733 }
734
735 static void
736 account_widget_build_irc (EmpathyAccountWidget *self,
737   const char *filename)
738 {
739   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
740   empathy_account_widget_irc_build (self, filename,
741     &priv->table_common_settings);
742 }
743
744 static void
745 account_widget_build_sip (EmpathyAccountWidget *self,
746   const char *filename)
747 {
748   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
749   empathy_account_widget_sip_build (self, filename,
750     &priv->table_common_settings);
751 }
752
753 static void
754 account_widget_build_msn (EmpathyAccountWidget *self,
755     const char *filename)
756 {
757   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
758
759   if (priv->simple)
760     {
761       self->ui_details->gui = empathy_builder_get_file (filename,
762           "vbox_msn_simple", &self->ui_details->widget,
763           NULL);
764
765       empathy_account_widget_handle_params (self,
766           "entry_id_simple", "account",
767           "entry_password_simple", "password",
768           NULL);
769
770       self->ui_details->default_focus = g_strdup ("entry_id_simple");
771     }
772   else
773     {
774       self->ui_details->gui = empathy_builder_get_file (filename,
775           "table_common_msn_settings", &priv->table_common_settings,
776           "vbox_msn_settings", &self->ui_details->widget,
777           NULL);
778
779       empathy_account_widget_handle_params (self,
780           "entry_id", "account",
781           "entry_password", "password",
782           "entry_server", "server",
783           "spinbutton_port", "port",
784           NULL);
785
786       self->ui_details->default_focus = g_strdup ("entry_id");
787       self->ui_details->add_forget = TRUE;
788     }
789 }
790
791 static void
792 account_widget_build_jabber (EmpathyAccountWidget *self,
793     const char *filename)
794 {
795   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
796   GtkWidget *spinbutton_port;
797   GtkWidget *checkbutton_ssl;
798   GtkWidget *label_id, *label_password;
799   GtkWidget *label_id_create, *label_password_create;
800   GtkWidget *label_example_gtalk, *label_example_jabber;
801   gboolean is_gtalk;
802
803   is_gtalk = !tp_strdiff (
804       empathy_account_settings_get_icon_name (priv->settings),
805       "im-google-talk");
806
807   if (priv->simple && !is_gtalk)
808     {
809       self->ui_details->gui = empathy_builder_get_file (filename,
810           "vbox_jabber_simple", &self->ui_details->widget,
811           "label_id_simple", &label_id,
812           "label_id_create", &label_id_create,
813           "label_password_simple", &label_password,
814           "label_password_create", &label_password_create,
815           NULL);
816
817       if (empathy_account_settings_get_boolean (priv->settings, "register"))
818         {
819           gtk_widget_hide (label_id);
820           gtk_widget_hide (label_password);
821           gtk_widget_show (label_id_create);
822           gtk_widget_show (label_password_create);
823         }
824
825       empathy_account_widget_handle_params (self,
826           "entry_id_simple", "account",
827           "entry_password_simple", "password",
828           NULL);
829
830       self->ui_details->default_focus = g_strdup ("entry_id_simple");
831     }
832   else if (priv->simple && is_gtalk)
833     {
834       self->ui_details->gui = empathy_builder_get_file (filename,
835           "vbox_gtalk_simple", &self->ui_details->widget,
836           NULL);
837
838       empathy_account_widget_handle_params (self,
839           "entry_id_g_simple", "account",
840           "entry_password_g_simple", "password",
841           NULL);
842
843       self->ui_details->default_focus = g_strdup ("entry_id_g_simple");
844     }
845   else
846     {
847       self->ui_details->gui = empathy_builder_get_file (filename,
848           "table_common_settings", &priv->table_common_settings,
849           "vbox_jabber_settings", &self->ui_details->widget,
850           "spinbutton_port", &spinbutton_port,
851           "checkbutton_ssl", &checkbutton_ssl,
852           "label_username_example", &label_example_jabber,
853           "label_username_g_example", &label_example_gtalk,
854           NULL);
855
856       empathy_account_widget_handle_params (self,
857           "entry_id", "account",
858           "entry_password", "password",
859           "entry_resource", "resource",
860           "entry_server", "server",
861           "spinbutton_port", "port",
862           "spinbutton_priority", "priority",
863           "checkbutton_ssl", "old-ssl",
864           "checkbutton_ignore_ssl_errors", "ignore-ssl-errors",
865           "checkbutton_encryption", "require-encryption",
866           NULL);
867
868       self->ui_details->default_focus = g_strdup ("entry_id");
869       self->ui_details->add_forget = TRUE;
870       priv->spinbutton_port = spinbutton_port;
871
872       g_signal_connect (checkbutton_ssl, "toggled",
873           G_CALLBACK (account_widget_jabber_ssl_toggled_cb),
874           self);
875
876       if (is_gtalk)
877         {
878           gtk_widget_hide (label_example_jabber);
879           gtk_widget_show (label_example_gtalk);
880         }
881     }
882 }
883
884 static void
885 account_widget_build_icq (EmpathyAccountWidget *self,
886     const char *filename)
887 {
888   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
889   GtkWidget *spinbutton_port;
890
891   if (priv->simple)
892     {
893       self->ui_details->gui = empathy_builder_get_file (filename,
894           "vbox_icq_simple", &self->ui_details->widget,
895           NULL);
896
897       empathy_account_widget_handle_params (self,
898           "entry_uin_simple", "account",
899           "entry_password_simple", "password",
900           NULL);
901
902       self->ui_details->default_focus = g_strdup ("entry_uin_simple");
903     }
904   else
905     {
906       self->ui_details->gui = empathy_builder_get_file (filename,
907           "table_common_settings", &priv->table_common_settings,
908           "vbox_icq_settings", &self->ui_details->widget,
909           "spinbutton_port", &spinbutton_port,
910           NULL);
911
912       empathy_account_widget_handle_params (self,
913           "entry_uin", "account",
914           "entry_password", "password",
915           "entry_server", "server",
916           "spinbutton_port", "port",
917           "entry_charset", "charset",
918           NULL);
919
920       self->ui_details->default_focus = g_strdup ("entry_uin");
921       self->ui_details->add_forget = TRUE;
922     }
923 }
924
925 static void
926 account_widget_build_aim (EmpathyAccountWidget *self,
927     const char *filename)
928 {
929   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
930   GtkWidget *spinbutton_port;
931
932   if (priv->simple)
933     {
934       self->ui_details->gui = empathy_builder_get_file (filename,
935           "vbox_aim_simple", &self->ui_details->widget,
936           NULL);
937
938       empathy_account_widget_handle_params (self,
939           "entry_screenname_simple", "account",
940           "entry_password_simple", "password",
941           NULL);
942
943       self->ui_details->default_focus = g_strdup ("entry_screenname_simple");
944     }
945   else
946     {
947       self->ui_details->gui = empathy_builder_get_file (filename,
948           "table_common_settings", &priv->table_common_settings,
949           "vbox_aim_settings", &self->ui_details->widget,
950           "spinbutton_port", &spinbutton_port,
951           NULL);
952
953       empathy_account_widget_handle_params (self,
954           "entry_screenname", "account",
955           "entry_password", "password",
956           "entry_server", "server",
957           "spinbutton_port", "port",
958           NULL);
959
960       self->ui_details->default_focus = g_strdup ("entry_screenname");
961       self->ui_details->add_forget = TRUE;
962     }
963 }
964
965 static void
966 account_widget_build_yahoo (EmpathyAccountWidget *self,
967     const char *filename)
968 {
969   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
970
971   if (priv->simple)
972     {
973       self->ui_details->gui = empathy_builder_get_file (filename,
974           "vbox_yahoo_simple", &self->ui_details->widget,
975           NULL);
976
977       empathy_account_widget_handle_params (self,
978           "entry_id_simple", "account",
979           "entry_password_simple", "password",
980           NULL);
981
982       self->ui_details->default_focus = g_strdup ("entry_id_simple");
983     }
984   else
985     {
986       self->ui_details->gui = empathy_builder_get_file (filename,
987           "table_common_settings", &priv->table_common_settings,
988           "vbox_yahoo_settings", &self->ui_details->widget,
989           NULL);
990
991       empathy_account_widget_handle_params (self,
992           "entry_id", "account",
993           "entry_password", "password",
994           "entry_server", "server",
995           "entry_locale", "room-list-locale",
996           "entry_charset", "charset",
997           "spinbutton_port", "port",
998           "checkbutton_yahoojp", "yahoojp",
999           "checkbutton_ignore_invites", "ignore-invites",
1000           NULL);
1001
1002       self->ui_details->default_focus = g_strdup ("entry_id");
1003       self->ui_details->add_forget = TRUE;
1004     }
1005 }
1006
1007 static void
1008 account_widget_build_groupwise (EmpathyAccountWidget *self,
1009     const char *filename)
1010 {
1011   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1012
1013   if (priv->simple)
1014     {
1015       self->ui_details->gui = empathy_builder_get_file (filename,
1016           "vbox_groupwise_simple", &self->ui_details->widget,
1017           NULL);
1018
1019       empathy_account_widget_handle_params (self,
1020           "entry_id_simple", "account",
1021           "entry_password_simple", "password",
1022           NULL);
1023
1024       self->ui_details->default_focus = g_strdup ("entry_id_simple");
1025     }
1026   else
1027     {
1028       self->ui_details->gui = empathy_builder_get_file (filename,
1029           "table_common_groupwise_settings", &priv->table_common_settings,
1030           "vbox_groupwise_settings", &self->ui_details->widget,
1031           NULL);
1032
1033       empathy_account_widget_handle_params (self,
1034           "entry_id", "account",
1035           "entry_password", "password",
1036           "entry_server", "server",
1037           "spinbutton_port", "port",
1038           NULL);
1039
1040       self->ui_details->default_focus = g_strdup ("entry_id");
1041       self->ui_details->add_forget = TRUE;
1042     }
1043 }
1044
1045 static void
1046 account_widget_destroy_cb (GtkWidget *widget,
1047     EmpathyAccountWidget *self)
1048 {
1049   g_object_unref (self);
1050 }
1051
1052 static void
1053 empathy_account_widget_enabled_cb (TpAccount *account,
1054       GParamSpec *spec,
1055       gpointer user_data)
1056 {
1057   EmpathyAccountWidget *widget = EMPATHY_ACCOUNT_WIDGET (user_data);
1058   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
1059   gboolean enabled = tp_account_is_enabled (account);
1060
1061   if (priv->enabled_checkbox != NULL)
1062     {
1063 #ifndef HAVE_MOBLIN
1064       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->enabled_checkbox),
1065           enabled);
1066 #else
1067       nbtk_gtk_light_switch_set_active (
1068           NBTK_GTK_LIGHT_SWITCH (priv->enabled_checkbox),
1069           enabled);
1070 #endif /* HAVE_MOBLIN */
1071     }
1072 }
1073
1074 static void
1075 #ifndef HAVE_MOBLIN
1076 account_widget_enabled_released_cb (GtkToggleButton *toggle_button,
1077     gpointer user_data)
1078 #else
1079 account_widget_switch_flipped_cb (NbtkGtkLightSwitch *sw,
1080     gboolean state,
1081     gpointer user_data)
1082 #endif /* HAVE_MOBLIN */
1083 {
1084   EmpathyAccountWidgetPriv *priv = GET_PRIV (user_data);
1085   TpAccount *account;
1086 #ifndef HAVE_MOBLIN
1087   gboolean state;
1088
1089   state = gtk_toggle_button_get_active (toggle_button);
1090 #endif
1091
1092   account = empathy_account_settings_get_account (priv->settings);
1093
1094   /* Enable the account according to the value of the "Enabled" checkbox */
1095   tp_account_set_enabled_async (account, state, NULL, NULL);
1096 }
1097
1098 static void
1099 do_set_property (GObject *object,
1100     guint prop_id,
1101     const GValue *value,
1102     GParamSpec *pspec)
1103 {
1104   EmpathyAccountWidgetPriv *priv = GET_PRIV (object);
1105
1106   switch (prop_id)
1107     {
1108     case PROP_SETTINGS:
1109       priv->settings = g_value_dup_object (value);
1110       break;
1111     case PROP_SIMPLE:
1112       priv->simple = g_value_get_boolean (value);
1113       break;
1114     case PROP_CREATING_ACCOUNT:
1115       priv->creating_account = g_value_get_boolean (value);
1116       break;
1117     default:
1118       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1119     }
1120 }
1121
1122 static void
1123 do_get_property (GObject *object,
1124     guint prop_id,
1125     GValue *value,
1126     GParamSpec *pspec)
1127 {
1128   EmpathyAccountWidgetPriv *priv = GET_PRIV (object);
1129
1130   switch (prop_id)
1131     {
1132     case PROP_PROTOCOL:
1133       g_value_set_string (value,
1134         empathy_account_settings_get_protocol (priv->settings));
1135       break;
1136     case PROP_SETTINGS:
1137       g_value_set_object (value, priv->settings);
1138       break;
1139     case PROP_SIMPLE:
1140       g_value_set_boolean (value, priv->simple);
1141       break;
1142     case PROP_CREATING_ACCOUNT:
1143       g_value_set_boolean (value, priv->creating_account);
1144       break;
1145     default:
1146       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1147     }
1148 }
1149
1150 static void
1151 idle_state_change_cb (EmpathyIdle *idle,
1152     GParamSpec *spec,
1153     EmpathyAccountWidget *self)
1154 {
1155   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1156   TpConnectionPresenceType state;
1157
1158   state = empathy_idle_get_state (priv->idle);
1159
1160   if (state > TP_CONNECTION_PRESENCE_TYPE_OFFLINE)
1161     {
1162       g_object_set (priv->apply_button, "label", GTK_STOCK_CONNECT, NULL);
1163     }
1164   else
1165     {
1166       g_object_set (priv->apply_button, "label", GTK_STOCK_APPLY, NULL);
1167     }
1168 }
1169
1170 #define WIDGET(cm, proto) \
1171   { #cm, #proto, "empathy-account-widget-"#proto".ui", \
1172     account_widget_build_##proto }
1173
1174 static void
1175 do_constructed (GObject *obj)
1176 {
1177   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
1178   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1179   TpAccount *account;
1180   const gchar *protocol, *cm_name;
1181   guint i = 0;
1182   struct {
1183     const gchar *cm_name;
1184     const gchar *protocol;
1185     const char *file;
1186     void (*func)(EmpathyAccountWidget *self, const gchar *filename);
1187   } widgets [] = {
1188     { "salut", "local-xmpp", "empathy-account-widget-local-xmpp.ui",
1189         account_widget_build_salut },
1190     WIDGET (gabble, jabber),
1191     WIDGET (butterfly, msn),
1192     WIDGET (haze, icq),
1193     WIDGET (haze, aim),
1194     WIDGET (haze, yahoo),
1195     WIDGET (haze, groupwise),
1196     WIDGET (idle, irc),
1197     WIDGET (sofiasip, sip),
1198   };
1199
1200   cm_name = empathy_account_settings_get_cm (priv->settings);
1201   protocol = empathy_account_settings_get_protocol (priv->settings);
1202
1203   for (i = 0 ; i < G_N_ELEMENTS (widgets); i++)
1204     {
1205       if (!tp_strdiff (widgets[i].cm_name, cm_name) &&
1206           !tp_strdiff (widgets[i].protocol, protocol))
1207         {
1208           gchar *filename;
1209
1210           filename = empathy_file_lookup (widgets[i].file,
1211               "libempathy-gtk");
1212           widgets[i].func (self, filename);
1213           g_free (filename);
1214
1215           break;
1216         }
1217     }
1218
1219   if (i == G_N_ELEMENTS (widgets))
1220     {
1221       gchar *filename = empathy_file_lookup (
1222           "empathy-account-widget-generic.ui", "libempathy-gtk");
1223       account_widget_build_generic (self, filename);
1224       g_free (filename);
1225     }
1226
1227   /* handle default focus */
1228   if (self->ui_details->default_focus != NULL)
1229     {
1230       GObject *default_focus_entry;
1231
1232       default_focus_entry = gtk_builder_get_object
1233         (self->ui_details->gui, self->ui_details->default_focus);
1234       g_signal_connect (default_focus_entry, "realize",
1235           G_CALLBACK (gtk_widget_grab_focus),
1236           NULL);
1237     }
1238
1239   /* handle forget button */
1240   if (self->ui_details->add_forget)
1241     {
1242       const gchar *password = NULL;
1243
1244       priv->button_forget = GTK_WIDGET (gtk_builder_get_object
1245           (self->ui_details->gui, "button_forget"));
1246       priv->entry_password = GTK_WIDGET (gtk_builder_get_object
1247           (self->ui_details->gui, "entry_password"));
1248
1249       password = empathy_account_settings_get_string (priv->settings,
1250           "password");
1251       gtk_widget_set_sensitive (priv->button_forget,
1252           !EMP_STR_EMPTY (password));
1253
1254       g_signal_connect (priv->button_forget, "clicked",
1255           G_CALLBACK (account_widget_forget_clicked_cb),
1256           self);
1257       g_signal_connect (priv->entry_password, "changed",
1258           G_CALLBACK (account_widget_password_changed_cb),
1259           self);
1260     }
1261
1262   /* handle apply and cancel button */
1263   if (!priv->simple)
1264     {
1265       GtkWidget *hbox = gtk_hbox_new (TRUE, 3);
1266       const gchar *apply_button_id;
1267
1268       priv->cancel_button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
1269
1270       if (priv->creating_account)
1271         {
1272           TpConnectionPresenceType state;
1273           priv->idle = empathy_idle_dup_singleton ();
1274
1275           empathy_signal_connect_weak (priv->idle, "notify::state",
1276               G_CALLBACK (idle_state_change_cb), obj);
1277
1278           state = empathy_idle_get_state (priv->idle);
1279
1280           if (state > TP_CONNECTION_PRESENCE_TYPE_OFFLINE)
1281             {
1282               /* We are online, display a Connect button */
1283               apply_button_id = GTK_STOCK_CONNECT;
1284             }
1285           else
1286             {
1287               /* We are offline, display a Save button */
1288               apply_button_id = GTK_STOCK_SAVE;
1289             }
1290         }
1291       else
1292         {
1293           /* We are editing an existing account, display an Apply button */
1294           apply_button_id = GTK_STOCK_APPLY;
1295         }
1296
1297       priv->apply_button = gtk_button_new_from_stock (apply_button_id);
1298
1299 #ifdef HAVE_MOBLIN
1300       if (priv->creating_account)
1301         /* Translators: this is used only when built on a moblin platform */
1302         gtk_button_set_label (GTK_BUTTON (priv->apply_button),
1303             _("L_og in"));
1304 #endif
1305
1306       gtk_box_pack_end (GTK_BOX (hbox), priv->apply_button, TRUE,
1307           TRUE, 3);
1308       gtk_box_pack_end (GTK_BOX (hbox), priv->cancel_button, TRUE,
1309           TRUE, 3);
1310
1311       gtk_box_pack_end (GTK_BOX (self->ui_details->widget), hbox, FALSE,
1312           FALSE, 3);
1313
1314       g_signal_connect (priv->cancel_button, "clicked",
1315           G_CALLBACK (account_widget_cancel_clicked_cb),
1316           self);
1317       g_signal_connect (priv->apply_button, "clicked",
1318           G_CALLBACK (account_widget_apply_clicked_cb),
1319           self);
1320       gtk_widget_show_all (hbox);
1321
1322       if (priv->creating_account)
1323         /* When creating an account, the user might have nothing to enter.
1324          * That means that no control interaction might occur,
1325          * so we update the control button sensitivity manually.
1326          */
1327         account_widget_handle_control_buttons_sensitivity (self);
1328       else
1329         account_widget_set_control_buttons_sensitivity (self, FALSE);
1330     }
1331
1332   account = empathy_account_settings_get_account (priv->settings);
1333
1334   if (account != NULL)
1335     {
1336       g_signal_connect (account, "notify::enabled",
1337           G_CALLBACK (empathy_account_widget_enabled_cb), self);
1338     }
1339
1340   /* handle the "Enabled" checkbox. We only add it when modifying an account */
1341   if (!priv->creating_account && priv->table_common_settings != NULL)
1342     {
1343 #ifdef HAVE_MOBLIN
1344       GtkWidget *w;
1345 #endif
1346       guint nb_rows, nb_columns;
1347       gboolean is_enabled;
1348
1349       is_enabled = tp_account_is_enabled (account);
1350
1351 #ifndef HAVE_MOBLIN
1352       priv->enabled_checkbox =
1353           gtk_check_button_new_with_label (_("Enabled"));
1354
1355       gtk_toggle_button_set_active (
1356           GTK_TOGGLE_BUTTON (priv->enabled_checkbox), is_enabled);
1357 #else
1358       /* Translators: this is used only when built on a moblin platform */
1359       w = gtk_label_new (_("Account:"));
1360       gtk_misc_set_alignment (GTK_MISC (w), 0, 0.5);
1361
1362       priv->enabled_checkbox = nbtk_gtk_light_switch_new ();
1363
1364       nbtk_gtk_light_switch_set_active (
1365           NBTK_GTK_LIGHT_SWITCH (priv->enabled_checkbox), is_enabled);
1366
1367       gtk_widget_show (w);
1368 #endif /* HAVE_MOBLIN */
1369
1370       g_object_get (priv->table_common_settings, "n-rows", &nb_rows,
1371           "n-columns", &nb_columns, NULL);
1372
1373       gtk_table_resize (GTK_TABLE (priv->table_common_settings), ++nb_rows,
1374           nb_columns);
1375
1376 #ifndef HAVE_MOBLIN
1377       gtk_table_attach (GTK_TABLE (priv->table_common_settings),
1378           priv->enabled_checkbox,
1379           0, nb_columns, nb_rows - 1, nb_rows,
1380           GTK_EXPAND | GTK_FILL, 0, 0, 0);
1381 #else
1382       gtk_table_attach (GTK_TABLE (priv->table_common_settings),
1383           w,
1384           0, 1, nb_rows - 1, nb_rows,
1385           GTK_FILL, 0, 0, 0);
1386       gtk_table_attach (GTK_TABLE (priv->table_common_settings),
1387           priv->enabled_checkbox,
1388           1, nb_columns, nb_rows - 1, nb_rows,
1389           GTK_EXPAND | GTK_FILL, 0, 0, 0);
1390 #endif /* HAVE_MOBLIN */
1391
1392       gtk_widget_show (priv->enabled_checkbox);
1393
1394 #ifndef HAVE_MOBLIN
1395       g_signal_connect (G_OBJECT (priv->enabled_checkbox), "released",
1396           G_CALLBACK (account_widget_enabled_released_cb), self);
1397 #else
1398       g_signal_connect (G_OBJECT (priv->enabled_checkbox), "switch-flipped",
1399           G_CALLBACK (account_widget_switch_flipped_cb), self);
1400 #endif /* HAVE_MOBLIN */
1401     }
1402
1403   /* hook up to widget destruction to unref ourselves */
1404   g_signal_connect (self->ui_details->widget, "destroy",
1405       G_CALLBACK (account_widget_destroy_cb), self);
1406
1407   empathy_builder_unref_and_keep_widget (self->ui_details->gui,
1408       self->ui_details->widget);
1409   self->ui_details->gui = NULL;
1410 }
1411
1412 static void
1413 do_dispose (GObject *obj)
1414 {
1415   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
1416   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1417
1418   if (priv->dispose_run)
1419     return;
1420
1421   priv->dispose_run = TRUE;
1422
1423   empathy_account_settings_is_ready (priv->settings);
1424
1425   if (priv->settings != NULL)
1426     {
1427       TpAccount *account;
1428       account = empathy_account_settings_get_account (priv->settings);
1429
1430       if (account != NULL)
1431         {
1432           g_signal_handlers_disconnect_by_func (account,
1433               empathy_account_widget_enabled_cb, self);
1434         }
1435
1436       g_object_unref (priv->settings);
1437       priv->settings = NULL;
1438     }
1439
1440   if (priv->idle != NULL)
1441     {
1442       g_object_unref (priv->idle);
1443       priv->idle = NULL;
1444     }
1445
1446   if (G_OBJECT_CLASS (empathy_account_widget_parent_class)->dispose != NULL)
1447     G_OBJECT_CLASS (empathy_account_widget_parent_class)->dispose (obj);
1448 }
1449
1450 static void
1451 do_finalize (GObject *obj)
1452 {
1453   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
1454
1455   g_free (self->ui_details->default_focus);
1456   g_slice_free (EmpathyAccountWidgetUIDetails, self->ui_details);
1457
1458   if (G_OBJECT_CLASS (empathy_account_widget_parent_class)->finalize != NULL)
1459     G_OBJECT_CLASS (empathy_account_widget_parent_class)->finalize (obj);
1460 }
1461
1462 static void
1463 empathy_account_widget_class_init (EmpathyAccountWidgetClass *klass)
1464 {
1465   GObjectClass *oclass = G_OBJECT_CLASS (klass);
1466   GParamSpec *param_spec;
1467
1468   oclass->get_property = do_get_property;
1469   oclass->set_property = do_set_property;
1470   oclass->constructed = do_constructed;
1471   oclass->dispose = do_dispose;
1472   oclass->finalize = do_finalize;
1473
1474   param_spec = g_param_spec_string ("protocol",
1475       "protocol", "The protocol of the account",
1476       NULL,
1477       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
1478   g_object_class_install_property (oclass, PROP_PROTOCOL, param_spec);
1479
1480   param_spec = g_param_spec_object ("settings",
1481       "settings", "The settings of the account",
1482       EMPATHY_TYPE_ACCOUNT_SETTINGS,
1483       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
1484   g_object_class_install_property (oclass, PROP_SETTINGS, param_spec);
1485
1486   param_spec = g_param_spec_boolean ("simple",
1487       "simple", "Whether the account widget is a simple or an advanced one",
1488       FALSE,
1489       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
1490   g_object_class_install_property (oclass, PROP_SIMPLE, param_spec);
1491
1492   param_spec = g_param_spec_boolean ("creating-account",
1493       "creating-account",
1494       "TRUE if we're creating an account, FALSE if we're modifying it",
1495       FALSE,
1496       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
1497   g_object_class_install_property (oclass, PROP_CREATING_ACCOUNT, param_spec);
1498
1499   signals[HANDLE_APPLY] =
1500     g_signal_new ("handle-apply", G_TYPE_FROM_CLASS (klass),
1501         G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1502         g_cclosure_marshal_VOID__BOOLEAN,
1503         G_TYPE_NONE,
1504         1, G_TYPE_BOOLEAN);
1505
1506   /* This signal is emitted when an account has been created and enabled. */
1507   signals[ACCOUNT_CREATED] =
1508       g_signal_new ("account-created", G_TYPE_FROM_CLASS (klass),
1509           G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1510           g_cclosure_marshal_VOID__VOID,
1511           G_TYPE_NONE,
1512           0);
1513
1514   signals[CANCELLED] =
1515       g_signal_new ("cancelled", G_TYPE_FROM_CLASS (klass),
1516           G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1517           g_cclosure_marshal_VOID__VOID,
1518           G_TYPE_NONE,
1519           0);
1520
1521   g_type_class_add_private (klass, sizeof (EmpathyAccountWidgetPriv));
1522 }
1523
1524 static void
1525 empathy_account_widget_init (EmpathyAccountWidget *self)
1526 {
1527   EmpathyAccountWidgetPriv *priv =
1528     G_TYPE_INSTANCE_GET_PRIVATE ((self), EMPATHY_TYPE_ACCOUNT_WIDGET,
1529         EmpathyAccountWidgetPriv);
1530
1531   self->priv = priv;
1532   priv->dispose_run = FALSE;
1533
1534   self->ui_details = g_slice_new0 (EmpathyAccountWidgetUIDetails);
1535 }
1536
1537 /* public methods */
1538
1539 void
1540 empathy_account_widget_discard_pending_changes
1541     (EmpathyAccountWidget *widget)
1542 {
1543   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
1544
1545   empathy_account_settings_discard_changes (priv->settings);
1546   priv->contains_pending_changes = FALSE;
1547 }
1548
1549 gboolean
1550 empathy_account_widget_contains_pending_changes (EmpathyAccountWidget *widget)
1551 {
1552   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
1553
1554   return priv->contains_pending_changes;
1555 }
1556
1557 void
1558 empathy_account_widget_handle_params (EmpathyAccountWidget *self,
1559     const gchar *first_widget,
1560     ...)
1561 {
1562   va_list args;
1563
1564   va_start (args, first_widget);
1565   account_widget_handle_params_valist (self, first_widget, args);
1566   va_end (args);
1567 }
1568
1569 GtkWidget *
1570 empathy_account_widget_get_widget (EmpathyAccountWidget *widget)
1571 {
1572   return widget->ui_details->widget;
1573 }
1574
1575 EmpathyAccountWidget *
1576 empathy_account_widget_new_for_protocol (EmpathyAccountSettings *settings,
1577     gboolean simple)
1578 {
1579   EmpathyAccountWidget *self;
1580
1581   g_return_val_if_fail (EMPATHY_IS_ACCOUNT_SETTINGS (settings), NULL);
1582
1583   self = g_object_new
1584     (EMPATHY_TYPE_ACCOUNT_WIDGET,
1585         "settings", settings, "simple", simple,
1586         "creating-account",
1587         empathy_account_settings_get_account (settings) == NULL,
1588         NULL);
1589
1590   return self;
1591 }