]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-account-widget.c
Merge branch 'more-accounts-fixes'
[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_MEEGO
34 #include <mx/mx-gtk.h>
35 #endif /* HAVE_MEEGO */
36
37 #include <libempathy/empathy-utils.h>
38
39 #include <telepathy-glib/account.h>
40 #include <telepathy-glib/account-manager.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   GtkWidget *radiobutton_reuse;
67
68   gboolean simple;
69
70   gboolean contains_pending_changes;
71
72   /* An EmpathyAccountWidget can be used to either create an account or
73    * modify it. When we are creating an account, this member is set to TRUE */
74   gboolean creating_account;
75
76   /* whether there are any other real accounts. Necessary so we know whether
77    * it's safe to dismiss this widget in some cases (eg, whether the Cancel
78    * button should be sensitive) */
79   gboolean other_accounts_exist;
80
81   /* if TRUE, the GTK+ destroy signal has been fired and so the widgets
82    * embedded in this account widget can't be used any more
83    * workaround because some async callbacks can be called after the
84    * widget has been destroyed */
85   gboolean destroyed;
86
87   TpAccountManager *account_manager;
88
89   GtkWidget *param_account_widget;
90   GtkWidget *param_password_widget;
91
92   gboolean dispose_run;
93 } EmpathyAccountWidgetPriv;
94
95 enum {
96   PROP_PROTOCOL = 1,
97   PROP_SETTINGS,
98   PROP_SIMPLE,
99   PROP_CREATING_ACCOUNT,
100   PROP_OTHER_ACCOUNTS_EXIST,
101 };
102
103 enum {
104   HANDLE_APPLY,
105   ACCOUNT_CREATED,
106   CANCELLED,
107   LAST_SIGNAL
108 };
109
110 static guint signals[LAST_SIGNAL] = { 0 };
111
112 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccountWidget)
113 #define CHANGED_TIMEOUT 300
114
115 static void
116 account_widget_set_control_buttons_sensitivity (EmpathyAccountWidget *self,
117     gboolean sensitive)
118 {
119   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
120
121   if (!priv->simple)
122     {
123       /* we hit this case because of the 'other-accounts-exist' property handler
124        * being called during init (before constructed()) */
125       if (priv->apply_button == NULL || priv->cancel_button == NULL)
126         return;
127
128       gtk_widget_set_sensitive (priv->apply_button, sensitive);
129       gtk_widget_set_sensitive (priv->cancel_button,
130           (sensitive || priv->creating_account) && priv->other_accounts_exist);
131     }
132 }
133
134 static void
135 account_widget_handle_control_buttons_sensitivity (EmpathyAccountWidget *self)
136 {
137   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
138   gboolean is_valid;
139
140   is_valid = empathy_account_settings_is_valid (priv->settings);
141
142   if (!priv->simple)
143       account_widget_set_control_buttons_sensitivity (self, is_valid);
144
145   g_signal_emit (self, signals[HANDLE_APPLY], 0, is_valid);
146 }
147
148 static void
149 account_widget_entry_changed_common (EmpathyAccountWidget *self,
150     GtkEntry *entry, gboolean focus)
151 {
152   const gchar *str;
153   const gchar *param_name;
154   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
155
156   str = gtk_entry_get_text (entry);
157   param_name = g_object_get_data (G_OBJECT (entry), "param_name");
158
159   if (EMP_STR_EMPTY (str))
160     {
161       const gchar *value = NULL;
162
163       empathy_account_settings_unset (priv->settings, param_name);
164
165       if (focus)
166         {
167           value = empathy_account_settings_get_string (priv->settings,
168               param_name);
169           DEBUG ("Unset %s and restore to %s", param_name, value);
170           gtk_entry_set_text (entry, value ? value : "");
171         }
172     }
173   else
174     {
175       DEBUG ("Setting %s to %s", param_name,
176           tp_strdiff (param_name, "password") ? str : "***");
177       empathy_account_settings_set_string (priv->settings, param_name, str);
178     }
179 }
180
181 static void
182 account_widget_entry_changed_cb (GtkEditable *entry,
183     EmpathyAccountWidget *self)
184 {
185   account_widget_entry_changed_common (self, GTK_ENTRY (entry), FALSE);
186   empathy_account_widget_changed (self);
187 }
188
189 static void
190 account_widget_int_changed_cb (GtkWidget *widget,
191     EmpathyAccountWidget *self)
192 {
193   const gchar *param_name;
194   gint value;
195   const gchar *signature;
196   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
197
198   value = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
199   param_name = g_object_get_data (G_OBJECT (widget), "param_name");
200
201   signature = empathy_account_settings_get_dbus_signature (priv->settings,
202     param_name);
203   g_return_if_fail (signature != NULL);
204
205   DEBUG ("Setting %s to %d", param_name, value);
206
207   switch ((int)*signature)
208     {
209     case DBUS_TYPE_INT16:
210     case DBUS_TYPE_INT32:
211       empathy_account_settings_set_int32 (priv->settings, param_name, value);
212       break;
213     case DBUS_TYPE_INT64:
214       empathy_account_settings_set_int64 (priv->settings, param_name, value);
215       break;
216     case DBUS_TYPE_UINT16:
217     case DBUS_TYPE_UINT32:
218       empathy_account_settings_set_uint32 (priv->settings, param_name, value);
219       break;
220     case DBUS_TYPE_UINT64:
221       empathy_account_settings_set_uint64 (priv->settings, param_name, value);
222       break;
223     default:
224       g_return_if_reached ();
225     }
226
227   empathy_account_widget_changed (self);
228 }
229
230 static void
231 account_widget_checkbutton_toggled_cb (GtkWidget *widget,
232     EmpathyAccountWidget *self)
233 {
234   gboolean     value;
235   gboolean     default_value;
236   const gchar *param_name;
237   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
238
239   value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
240   param_name = g_object_get_data (G_OBJECT (widget), "param_name");
241
242   /* FIXME: This is ugly! checkbox don't have a "not-set" value so we
243    * always unset the param and set the value if different from the
244    * default value. */
245   empathy_account_settings_unset (priv->settings, param_name);
246   default_value = empathy_account_settings_get_boolean (priv->settings,
247       param_name);
248
249   if (default_value == value)
250     {
251       DEBUG ("Unset %s and restore to %d", param_name, default_value);
252     }
253   else
254     {
255       DEBUG ("Setting %s to %d", param_name, value);
256       empathy_account_settings_set_boolean (priv->settings, param_name, value);
257     }
258
259   empathy_account_widget_changed (self);
260 }
261
262 static void
263 account_widget_forget_clicked_cb (GtkWidget *button,
264     EmpathyAccountWidget *self)
265 {
266   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
267   const gchar *param_name;
268
269   param_name = g_object_get_data (G_OBJECT (priv->entry_password),
270       "param_name");
271
272   DEBUG ("Unset %s", param_name);
273   empathy_account_settings_unset (priv->settings, param_name);
274   gtk_entry_set_text (GTK_ENTRY (priv->entry_password), "");
275
276   empathy_account_widget_changed (self);
277 }
278
279 static void
280 account_widget_password_changed_cb (GtkWidget *entry,
281     EmpathyAccountWidget *self)
282 {
283   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
284   const gchar *str;
285
286   str = gtk_entry_get_text (GTK_ENTRY (entry));
287   gtk_widget_set_sensitive (priv->button_forget, !EMP_STR_EMPTY (str));
288
289   priv->contains_pending_changes = TRUE;
290 }
291
292 static void
293 account_widget_jabber_ssl_toggled_cb (GtkWidget *checkbutton_ssl,
294     EmpathyAccountWidget *self)
295 {
296   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
297   gboolean   value;
298   gint32       port = 0;
299
300   value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbutton_ssl));
301   port = empathy_account_settings_get_uint32 (priv->settings, "port");
302
303   if (value)
304     {
305       if (port == 5222 || port == 0)
306         port = 5223;
307     }
308   else
309     {
310       if (port == 5223 || port == 0)
311         port = 5222;
312     }
313
314   gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->spinbutton_port), port);
315
316   priv->contains_pending_changes = TRUE;
317 }
318
319 static void
320 account_widget_combobox_changed_cb (GtkWidget *widget,
321     EmpathyAccountWidget *self)
322 {
323   GtkTreeIter iter;
324   GtkTreeModel *model;
325   const gchar *value;
326   const GValue *v;
327   const gchar *default_value = NULL;
328   const gchar *param_name;
329   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
330
331   if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter))
332     return;
333
334   model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
335   /* the param value is stored in the first column */
336   gtk_tree_model_get (model, &iter, 0, &value, -1);
337
338   param_name = g_object_get_data (G_OBJECT (widget), "param_name");
339
340   v = empathy_account_settings_get_default (priv->settings, param_name);
341   if (v != NULL)
342     default_value = g_value_get_string (v);
343
344   if (!tp_strdiff (value, default_value))
345     {
346       DEBUG ("Unset %s and restore to %s", param_name, default_value);
347       empathy_account_settings_unset (priv->settings, param_name);
348     }
349   else
350     {
351       DEBUG ("Setting %s to %s", param_name, value);
352       empathy_account_settings_set_string (priv->settings, param_name, value);
353     }
354
355   empathy_account_widget_changed (self);
356 }
357
358 void
359 empathy_account_widget_setup_widget (EmpathyAccountWidget *self,
360     GtkWidget *widget,
361     const gchar *param_name)
362 {
363   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
364
365   g_object_set_data_full (G_OBJECT (widget), "param_name",
366       g_strdup (param_name), g_free);
367
368   if (GTK_IS_SPIN_BUTTON (widget))
369     {
370       gint value = 0;
371       const gchar *signature;
372
373       signature = empathy_account_settings_get_dbus_signature (priv->settings,
374           param_name);
375       g_return_if_fail (signature != NULL);
376
377       switch ((int)*signature)
378         {
379           case DBUS_TYPE_INT16:
380           case DBUS_TYPE_INT32:
381             value = empathy_account_settings_get_int32 (priv->settings,
382               param_name);
383             break;
384           case DBUS_TYPE_INT64:
385             value = empathy_account_settings_get_int64 (priv->settings,
386               param_name);
387             break;
388           case DBUS_TYPE_UINT16:
389           case DBUS_TYPE_UINT32:
390             value = empathy_account_settings_get_uint32 (priv->settings,
391               param_name);
392             break;
393           case DBUS_TYPE_UINT64:
394             value = empathy_account_settings_get_uint64 (priv->settings,
395                 param_name);
396             break;
397           default:
398             g_return_if_reached ();
399         }
400
401       gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
402
403       g_signal_connect (widget, "value-changed",
404           G_CALLBACK (account_widget_int_changed_cb),
405           self);
406     }
407   else if (GTK_IS_ENTRY (widget))
408     {
409       const gchar *str = NULL;
410
411       str = empathy_account_settings_get_string (priv->settings, param_name);
412       gtk_entry_set_text (GTK_ENTRY (widget), str ? str : "");
413
414       if (!tp_strdiff (param_name, "account"))
415         priv->param_account_widget = widget;
416       else if (!tp_strdiff (param_name, "password"))
417         priv->param_password_widget = widget;
418
419       if (strstr (param_name, "password"))
420         {
421           gtk_entry_set_visibility (GTK_ENTRY (widget), FALSE);
422         }
423
424       g_signal_connect (widget, "changed",
425           G_CALLBACK (account_widget_entry_changed_cb), self);
426     }
427   else if (GTK_IS_TOGGLE_BUTTON (widget))
428     {
429       gboolean value = FALSE;
430
431       value = empathy_account_settings_get_boolean (priv->settings,
432           param_name);
433       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), value);
434
435       g_signal_connect (widget, "toggled",
436           G_CALLBACK (account_widget_checkbutton_toggled_cb),
437           self);
438     }
439   else if (GTK_IS_COMBO_BOX (widget))
440     {
441       /* The combo box's model has to contain the param value in its first
442        * column (as a string) */
443       const gchar *str;
444       GtkTreeModel *model;
445       GtkTreeIter iter;
446       gboolean valid;
447
448       str = empathy_account_settings_get_string (priv->settings, param_name);
449       model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
450
451       valid = gtk_tree_model_get_iter_first (model, &iter);
452       while (valid)
453         {
454           gchar *name;
455
456           gtk_tree_model_get (model, &iter, 0, &name, -1);
457           if (!tp_strdiff (name, str))
458             {
459               gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter);
460               valid = FALSE;
461             }
462           else
463             {
464               valid = gtk_tree_model_iter_next (model, &iter);
465             }
466
467           g_free (name);
468         }
469
470       g_signal_connect (widget, "changed",
471           G_CALLBACK (account_widget_combobox_changed_cb),
472           self);
473     }
474   else
475     {
476       DEBUG ("Unknown type of widget for param %s", param_name);
477     }
478 }
479
480 static gchar *
481 account_widget_generic_format_param_name (const gchar *param_name)
482 {
483   gchar *str;
484   gchar *p;
485
486   str = g_strdup (param_name);
487
488   if (str && g_ascii_isalpha (str[0]))
489     str[0] = g_ascii_toupper (str[0]);
490
491   while ((p = strchr (str, '-')) != NULL)
492     {
493       if (p[1] != '\0' && g_ascii_isalpha (p[1]))
494         {
495           p[0] = ' ';
496           p[1] = g_ascii_toupper (p[1]);
497         }
498
499       p++;
500     }
501
502   return str;
503 }
504
505 static void
506 accounts_widget_generic_setup (EmpathyAccountWidget *self,
507     GtkWidget *table_common_settings,
508     GtkWidget *table_advanced_settings)
509 {
510   TpConnectionManagerParam *params, *param;
511   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
512
513   params = empathy_account_settings_get_tp_params (priv->settings);
514
515   for (param = params; param != NULL && param->name != NULL; param++)
516     {
517       GtkWidget       *table_settings;
518       guint            n_rows = 0;
519       GtkWidget       *widget = NULL;
520       gchar           *param_name_formatted;
521
522       if (param->flags & TP_CONN_MGR_PARAM_FLAG_REQUIRED)
523         table_settings = table_common_settings;
524       else if (priv->simple)
525         return;
526       else
527         table_settings = table_advanced_settings;
528
529       param_name_formatted = account_widget_generic_format_param_name
530         (param->name);
531       g_object_get (table_settings, "n-rows", &n_rows, NULL);
532       gtk_table_resize (GTK_TABLE (table_settings), ++n_rows, 2);
533
534       if (param->dbus_signature[0] == 's')
535         {
536           gchar *str;
537
538           str = g_strdup_printf (_("%s:"), param_name_formatted);
539           widget = gtk_label_new (str);
540           gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
541           g_free (str);
542
543           gtk_table_attach (GTK_TABLE (table_settings),
544               widget,
545               0, 1,
546               n_rows - 1, n_rows,
547               GTK_FILL, 0,
548               0, 0);
549           gtk_widget_show (widget);
550
551           widget = gtk_entry_new ();
552           if (strcmp (param->name, "account") == 0)
553             {
554               g_signal_connect (widget, "realize",
555                   G_CALLBACK (gtk_widget_grab_focus),
556                   NULL);
557             }
558           gtk_table_attach (GTK_TABLE (table_settings),
559               widget,
560               1, 2,
561               n_rows - 1, n_rows,
562               GTK_FILL | GTK_EXPAND, 0,
563               0, 0);
564           gtk_widget_show (widget);
565         }
566       /* int types: ynqiuxt. double type is 'd' */
567       else if (param->dbus_signature[0] == 'y' ||
568           param->dbus_signature[0] == 'n' ||
569           param->dbus_signature[0] == 'q' ||
570           param->dbus_signature[0] == 'i' ||
571           param->dbus_signature[0] == 'u' ||
572           param->dbus_signature[0] == 'x' ||
573           param->dbus_signature[0] == 't' ||
574           param->dbus_signature[0] == 'd')
575         {
576           gchar   *str = NULL;
577           gdouble  minint = 0;
578           gdouble  maxint = 0;
579           gdouble  step = 1;
580
581           switch (param->dbus_signature[0])
582             {
583             case 'y': minint = G_MININT8;  maxint = G_MAXINT8;   break;
584             case 'n': minint = G_MININT16; maxint = G_MAXINT16;  break;
585             case 'q': minint = 0;          maxint = G_MAXUINT16; break;
586             case 'i': minint = G_MININT32; maxint = G_MAXINT32;  break;
587             case 'u': minint = 0;          maxint = G_MAXUINT32; break;
588             case 'x': minint = G_MININT64; maxint = G_MAXINT64;  break;
589             case 't': minint = 0;          maxint = G_MAXUINT64; break;
590             case 'd': minint = G_MININT32; maxint = G_MAXINT32;
591               step = 0.1; break;
592             }
593
594           str = g_strdup_printf (_("%s:"), param_name_formatted);
595           widget = gtk_label_new (str);
596           gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
597           g_free (str);
598
599           gtk_table_attach (GTK_TABLE (table_settings),
600               widget,
601               0, 1,
602               n_rows - 1, n_rows,
603               GTK_FILL, 0,
604               0, 0);
605           gtk_widget_show (widget);
606
607           widget = gtk_spin_button_new_with_range (minint, maxint, step);
608           gtk_table_attach (GTK_TABLE (table_settings),
609               widget,
610               1, 2,
611               n_rows - 1, n_rows,
612               GTK_FILL | GTK_EXPAND, 0,
613               0, 0);
614           gtk_widget_show (widget);
615         }
616       else if (param->dbus_signature[0] == 'b')
617         {
618           widget = gtk_check_button_new_with_label (param_name_formatted);
619           gtk_table_attach (GTK_TABLE (table_settings),
620               widget,
621               0, 2,
622               n_rows - 1, n_rows,
623               GTK_FILL | GTK_EXPAND, 0,
624               0, 0);
625           gtk_widget_show (widget);
626         }
627       else
628         {
629           DEBUG ("Unknown signature for param %s: %s",
630               param_name_formatted, param->dbus_signature);
631         }
632
633       if (widget)
634         empathy_account_widget_setup_widget (self, widget, param->name);
635
636       g_free (param_name_formatted);
637     }
638 }
639
640 static void
641 account_widget_handle_params_valist (EmpathyAccountWidget *self,
642     const gchar *first_widget,
643     va_list args)
644 {
645   GObject *object;
646   const gchar *name;
647
648   for (name = first_widget; name; name = va_arg (args, const gchar *))
649     {
650       const gchar *param_name;
651
652       param_name = va_arg (args, const gchar *);
653       object = gtk_builder_get_object (self->ui_details->gui, name);
654
655       if (!object)
656         {
657           g_warning ("Builder is missing object '%s'.", name);
658           continue;
659         }
660
661       empathy_account_widget_setup_widget (self, GTK_WIDGET (object),
662           param_name);
663     }
664 }
665
666 static void
667 account_widget_cancel_clicked_cb (GtkWidget *button,
668     EmpathyAccountWidget *self)
669 {
670   g_signal_emit (self, signals[CANCELLED], 0);
671 }
672
673 static void
674 account_widget_account_enabled_cb (GObject *source_object,
675     GAsyncResult *res,
676     gpointer user_data)
677 {
678   GError *error = NULL;
679   TpAccount *account = TP_ACCOUNT (source_object);
680   EmpathyAccountWidget *widget = EMPATHY_ACCOUNT_WIDGET (user_data);
681   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
682
683   tp_account_set_enabled_finish (account, res, &error);
684
685   if (error != NULL)
686     {
687       DEBUG ("Could not enable the account: %s", error->message);
688       g_error_free (error);
689     }
690   else
691     {
692       empathy_connect_new_account (account, priv->account_manager);
693     }
694
695   /* unref widget - part of the workaround */
696   g_object_unref (widget);
697 }
698
699 static void
700 account_widget_applied_cb (GObject *source_object,
701     GAsyncResult *res,
702     gpointer user_data)
703 {
704   GError *error = NULL;
705   TpAccount *account;
706   EmpathyAccountSettings *settings = EMPATHY_ACCOUNT_SETTINGS (source_object);
707   EmpathyAccountWidget *widget = EMPATHY_ACCOUNT_WIDGET (user_data);
708   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
709
710   empathy_account_settings_apply_finish (settings, res, &error);
711
712   if (error != NULL)
713     {
714       DEBUG ("Could not apply changes to account: %s", error->message);
715       g_error_free (error);
716       return;
717     }
718
719   account = empathy_account_settings_get_account (priv->settings);
720
721   if (account != NULL)
722     {
723       if (priv->creating_account)
724         {
725           /* By default, when an account is created, we enable it. */
726
727           /* workaround to keep widget alive during async call */
728           g_object_ref (widget);
729
730           tp_account_set_enabled_async (account, TRUE,
731               account_widget_account_enabled_cb, widget);
732           g_signal_emit (widget, signals[ACCOUNT_CREATED], 0, account);
733         }
734       else if (priv->enabled_checkbox != NULL)
735         {
736           gboolean enabled_checked;
737
738           enabled_checked =
739 #ifdef HAVE_MEEGO
740             mx_gtk_light_switch_get_active (
741                 MX_GTK_LIGHT_SWITCH (priv->enabled_checkbox));
742 #else
743             gtk_toggle_button_get_active (
744                 GTK_TOGGLE_BUTTON (priv->enabled_checkbox));
745 #endif /* HAVE_MEEGO */
746
747           if (tp_account_is_enabled (account) && enabled_checked)
748             {
749               /* After having applied changes to a user account, we
750                * automatically reconnect it. This is done so the new
751                * information entered by the user is validated on the server. */
752               tp_account_reconnect_async (account, NULL, NULL);
753             }
754         }
755     }
756
757   if (!priv->destroyed)
758     account_widget_set_control_buttons_sensitivity (widget, FALSE);
759
760   priv->contains_pending_changes = FALSE;
761
762   /* unref the widget - part of the workaround */
763   g_object_unref (widget);
764 }
765
766 static void
767 account_widget_apply_clicked_cb (GtkWidget *button,
768     EmpathyAccountWidget *self)
769 {
770   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
771
772   if (priv->radiobutton_reuse != NULL)
773     {
774       gboolean reuse = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
775             priv->radiobutton_reuse));
776
777       DEBUG ("Set register param: %d", !reuse);
778       empathy_account_settings_set_boolean (priv->settings, "register", !reuse);
779     }
780
781   /* workaround to keep widget alive during async call */
782   g_object_ref (self);
783   empathy_account_settings_apply_async (priv->settings,
784       account_widget_applied_cb, self);
785 }
786
787 static void
788 account_widget_setup_generic (EmpathyAccountWidget *self)
789 {
790   GtkWidget *table_common_settings;
791   GtkWidget *table_advanced_settings;
792
793   table_common_settings = GTK_WIDGET (gtk_builder_get_object
794       (self->ui_details->gui, "table_common_settings"));
795   table_advanced_settings = GTK_WIDGET (gtk_builder_get_object
796       (self->ui_details->gui, "table_advanced_settings"));
797
798   accounts_widget_generic_setup (self, table_common_settings,
799       table_advanced_settings);
800
801   g_object_unref (self->ui_details->gui);
802 }
803
804 static void
805 account_widget_settings_ready_cb (EmpathyAccountSettings *settings,
806     GParamSpec *pspec,
807     gpointer user_data)
808 {
809   EmpathyAccountWidget *self = user_data;
810   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
811
812   if (empathy_account_settings_is_ready (priv->settings))
813     account_widget_setup_generic (self);
814 }
815
816 static void
817 account_widget_build_generic (EmpathyAccountWidget *self,
818     const char *filename)
819 {
820   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
821   GtkWidget *expander_advanced;
822
823   self->ui_details->gui = empathy_builder_get_file (filename,
824       "table_common_settings", &priv->table_common_settings,
825       "vbox_generic_settings", &self->ui_details->widget,
826       "expander_advanced_settings", &expander_advanced,
827       NULL);
828
829   if (priv->simple)
830     gtk_widget_hide (expander_advanced);
831
832   g_object_ref (self->ui_details->gui);
833
834   if (empathy_account_settings_is_ready (priv->settings))
835     account_widget_setup_generic (self);
836   else
837     g_signal_connect (priv->settings, "notify::ready",
838         G_CALLBACK (account_widget_settings_ready_cb), self);
839 }
840
841 static void
842 account_widget_build_salut (EmpathyAccountWidget *self,
843     const char *filename)
844 {
845   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
846   GtkWidget *expander_advanced;
847
848   self->ui_details->gui = empathy_builder_get_file (filename,
849       "table_common_settings", &priv->table_common_settings,
850       "vbox_salut_settings", &self->ui_details->widget,
851       "expander_advanced_settings", &expander_advanced,
852       NULL);
853
854   empathy_account_widget_handle_params (self,
855       "entry_published", "published-name",
856       "entry_nickname", "nickname",
857       "entry_first_name", "first-name",
858       "entry_last_name", "last-name",
859       "entry_email", "email",
860       "entry_jid", "jid",
861       NULL);
862
863   if (priv->simple)
864     gtk_widget_hide (expander_advanced);
865
866   self->ui_details->default_focus = g_strdup ("entry_first_name");
867 }
868
869 static void
870 account_widget_build_irc (EmpathyAccountWidget *self,
871   const char *filename)
872 {
873   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
874   empathy_account_widget_irc_build (self, filename,
875     &priv->table_common_settings);
876 }
877
878 static void
879 account_widget_build_sip (EmpathyAccountWidget *self,
880   const char *filename)
881 {
882   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
883   empathy_account_widget_sip_build (self, filename,
884     &priv->table_common_settings);
885 }
886
887 static void
888 account_widget_build_msn (EmpathyAccountWidget *self,
889     const char *filename)
890 {
891   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
892
893   if (priv->simple)
894     {
895       self->ui_details->gui = empathy_builder_get_file (filename,
896           "vbox_msn_simple", &self->ui_details->widget,
897           NULL);
898
899       empathy_account_widget_handle_params (self,
900           "entry_id_simple", "account",
901           "entry_password_simple", "password",
902           NULL);
903
904       self->ui_details->default_focus = g_strdup ("entry_id_simple");
905     }
906   else
907     {
908       self->ui_details->gui = empathy_builder_get_file (filename,
909           "table_common_msn_settings", &priv->table_common_settings,
910           "vbox_msn_settings", &self->ui_details->widget,
911           NULL);
912
913       empathy_account_widget_handle_params (self,
914           "entry_id", "account",
915           "entry_password", "password",
916           "entry_server", "server",
917           "spinbutton_port", "port",
918           NULL);
919
920       self->ui_details->default_focus = g_strdup ("entry_id");
921       self->ui_details->add_forget = TRUE;
922     }
923 }
924
925 static gboolean
926 account_widget_is_gtalk (EmpathyAccountWidget *self)
927 {
928   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
929
930   return !tp_strdiff (empathy_account_settings_get_icon_name (priv->settings),
931       "im-google-talk");
932 }
933
934 static gboolean
935 account_widget_is_facebook (EmpathyAccountWidget *self)
936 {
937   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
938
939   return !tp_strdiff (empathy_account_settings_get_icon_name (priv->settings),
940       "im-facebook");
941 }
942
943 #define FACEBOOK_SUFFIX "@chat.facebook.com"
944
945 static void
946 facebook_id_widget_changed_cb (GtkWidget *entry,
947     EmpathyAccountWidget *self)
948 {
949   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
950   const gchar *account;
951
952   account_widget_entry_changed_common (self, GTK_ENTRY (entry), FALSE);
953
954   account = empathy_account_settings_get_string (priv->settings, "account");
955   if (!EMP_STR_EMPTY (account) &&
956       !g_str_has_suffix (account, FACEBOOK_SUFFIX))
957     {
958       gchar *tmp;
959
960       tmp = g_strdup_printf ("%s%s", account, FACEBOOK_SUFFIX);
961
962       DEBUG ("Change account from '%s' to '%s'", account, tmp);
963
964       empathy_account_settings_set_string (priv->settings, "account", tmp);
965       g_free (tmp);
966     }
967
968   empathy_account_widget_changed (self);
969 }
970
971 static gchar *
972 remove_facebook_suffix (const gchar *str)
973 {
974   if (!g_str_has_suffix (str, FACEBOOK_SUFFIX))
975     return g_strdup (str);
976
977   return g_strndup (str, strlen (str) - strlen (FACEBOOK_SUFFIX));
978 }
979
980 static void
981 setup_facebook_id_widget (EmpathyAccountWidget *self,
982     GtkWidget *widget)
983 {
984   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
985   const gchar *str = NULL;
986
987   g_object_set_data_full (G_OBJECT (widget), "param_name",
988       g_strdup ("account"), g_free);
989
990   str = empathy_account_settings_get_string (priv->settings, "account");
991   if (str != NULL)
992     {
993       gchar *tmp;
994
995       tmp = remove_facebook_suffix (str);
996       gtk_entry_set_text (GTK_ENTRY (widget), tmp);
997       g_free (tmp);
998     }
999
1000   priv->param_account_widget = widget;
1001
1002   g_signal_connect (widget, "changed",
1003       G_CALLBACK (facebook_id_widget_changed_cb), self);
1004 }
1005
1006 static void
1007 account_widget_build_jabber (EmpathyAccountWidget *self,
1008     const char *filename)
1009 {
1010   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1011   GtkWidget *spinbutton_port;
1012   GtkWidget *checkbutton_ssl;
1013   GtkWidget *label_id, *label_password;
1014   GtkWidget *label_id_create, *label_password_create;
1015   GtkWidget *label_example_gtalk, *label_example_jabber, *label_example_fb;
1016   gboolean is_gtalk, is_facebook;
1017   GtkWidget *expander_advanced;
1018   GtkWidget *entry_id;
1019
1020   is_gtalk = account_widget_is_gtalk (self);
1021   is_facebook = account_widget_is_facebook (self);
1022
1023   if (priv->simple && !is_gtalk && !is_facebook)
1024     {
1025       /* Simple widget for XMPP */
1026       self->ui_details->gui = empathy_builder_get_file (filename,
1027           "vbox_jabber_simple", &self->ui_details->widget,
1028           "label_id_simple", &label_id,
1029           "label_id_create", &label_id_create,
1030           "label_password_simple", &label_password,
1031           "label_password_create", &label_password_create,
1032           NULL);
1033
1034       if (empathy_account_settings_get_boolean (priv->settings, "register"))
1035         {
1036           gtk_widget_hide (label_id);
1037           gtk_widget_hide (label_password);
1038           gtk_widget_show (label_id_create);
1039           gtk_widget_show (label_password_create);
1040         }
1041
1042       empathy_account_widget_handle_params (self,
1043           "entry_id_simple", "account",
1044           "entry_password_simple", "password",
1045           NULL);
1046
1047       self->ui_details->default_focus = g_strdup ("entry_id_simple");
1048     }
1049   else if (priv->simple && is_gtalk)
1050     {
1051       /* Simple widget for Google Talk */
1052       self->ui_details->gui = empathy_builder_get_file (filename,
1053           "vbox_gtalk_simple", &self->ui_details->widget,
1054           NULL);
1055
1056       empathy_account_widget_handle_params (self,
1057           "entry_id_g_simple", "account",
1058           "entry_password_g_simple", "password",
1059           NULL);
1060
1061       self->ui_details->default_focus = g_strdup ("entry_id_g_simple");
1062     }
1063   else if (priv->simple && is_facebook)
1064     {
1065       /* Simple widget for Facebook */
1066       self->ui_details->gui = empathy_builder_get_file (filename,
1067           "vbox_fb_simple", &self->ui_details->widget,
1068           "entry_id_fb_simple", &entry_id,
1069           NULL);
1070
1071       empathy_account_widget_handle_params (self,
1072           "entry_password_fb_simple", "password",
1073           NULL);
1074
1075       setup_facebook_id_widget (self, entry_id);
1076
1077       self->ui_details->default_focus = g_strdup ("entry_id_fb_simple");
1078     }
1079   else
1080     {
1081       /* Full widget for XMPP, Google Talk and Facebook*/
1082       self->ui_details->gui = empathy_builder_get_file (filename,
1083           "table_common_settings", &priv->table_common_settings,
1084           "vbox_jabber_settings", &self->ui_details->widget,
1085           "spinbutton_port", &spinbutton_port,
1086           "checkbutton_ssl", &checkbutton_ssl,
1087           "label_username_example", &label_example_jabber,
1088           "label_username_g_example", &label_example_gtalk,
1089           "label_username_f_example", &label_example_fb,
1090           "expander_advanced", &expander_advanced,
1091           "entry_id", &entry_id,
1092           "label_id", &label_id,
1093           NULL);
1094
1095       empathy_account_widget_handle_params (self,
1096           "entry_password", "password",
1097           "entry_resource", "resource",
1098           "entry_server", "server",
1099           "spinbutton_port", "port",
1100           "spinbutton_priority", "priority",
1101           "checkbutton_ssl", "old-ssl",
1102           "checkbutton_ignore_ssl_errors", "ignore-ssl-errors",
1103           "checkbutton_encryption", "require-encryption",
1104           NULL);
1105
1106       if (is_facebook)
1107         {
1108           gtk_label_set_label (GTK_LABEL (label_id), _("Username:"));
1109
1110           /* Facebook special case the entry ID widget to hide the
1111            * "@chat.facebook.com" part */
1112           setup_facebook_id_widget (self, entry_id);
1113         }
1114       else
1115         {
1116           empathy_account_widget_setup_widget (self, entry_id, "account");
1117         }
1118
1119       self->ui_details->default_focus = g_strdup ("entry_id");
1120       self->ui_details->add_forget = TRUE;
1121       priv->spinbutton_port = spinbutton_port;
1122
1123       g_signal_connect (checkbutton_ssl, "toggled",
1124           G_CALLBACK (account_widget_jabber_ssl_toggled_cb),
1125           self);
1126
1127       if (is_gtalk)
1128         {
1129           gtk_widget_hide (label_example_jabber);
1130           gtk_widget_show (label_example_gtalk);
1131         }
1132       else if (is_facebook)
1133         {
1134           gtk_widget_hide (label_example_jabber);
1135           gtk_widget_show (label_example_fb);
1136           gtk_widget_hide (expander_advanced);
1137         }
1138     }
1139 }
1140
1141 static void
1142 account_widget_build_icq (EmpathyAccountWidget *self,
1143     const char *filename)
1144 {
1145   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1146   GtkWidget *spinbutton_port;
1147
1148   if (priv->simple)
1149     {
1150       self->ui_details->gui = empathy_builder_get_file (filename,
1151           "vbox_icq_simple", &self->ui_details->widget,
1152           NULL);
1153
1154       empathy_account_widget_handle_params (self,
1155           "entry_uin_simple", "account",
1156           "entry_password_simple", "password",
1157           NULL);
1158
1159       self->ui_details->default_focus = g_strdup ("entry_uin_simple");
1160     }
1161   else
1162     {
1163       self->ui_details->gui = empathy_builder_get_file (filename,
1164           "table_common_settings", &priv->table_common_settings,
1165           "vbox_icq_settings", &self->ui_details->widget,
1166           "spinbutton_port", &spinbutton_port,
1167           NULL);
1168
1169       empathy_account_widget_handle_params (self,
1170           "entry_uin", "account",
1171           "entry_password", "password",
1172           "entry_server", "server",
1173           "spinbutton_port", "port",
1174           "entry_charset", "charset",
1175           NULL);
1176
1177       self->ui_details->default_focus = g_strdup ("entry_uin");
1178       self->ui_details->add_forget = TRUE;
1179     }
1180 }
1181
1182 static void
1183 account_widget_build_aim (EmpathyAccountWidget *self,
1184     const char *filename)
1185 {
1186   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1187   GtkWidget *spinbutton_port;
1188
1189   if (priv->simple)
1190     {
1191       self->ui_details->gui = empathy_builder_get_file (filename,
1192           "vbox_aim_simple", &self->ui_details->widget,
1193           NULL);
1194
1195       empathy_account_widget_handle_params (self,
1196           "entry_screenname_simple", "account",
1197           "entry_password_simple", "password",
1198           NULL);
1199
1200       self->ui_details->default_focus = g_strdup ("entry_screenname_simple");
1201     }
1202   else
1203     {
1204       self->ui_details->gui = empathy_builder_get_file (filename,
1205           "table_common_settings", &priv->table_common_settings,
1206           "vbox_aim_settings", &self->ui_details->widget,
1207           "spinbutton_port", &spinbutton_port,
1208           NULL);
1209
1210       empathy_account_widget_handle_params (self,
1211           "entry_screenname", "account",
1212           "entry_password", "password",
1213           "entry_server", "server",
1214           "spinbutton_port", "port",
1215           NULL);
1216
1217       self->ui_details->default_focus = g_strdup ("entry_screenname");
1218       self->ui_details->add_forget = TRUE;
1219     }
1220 }
1221
1222 static void
1223 account_widget_build_yahoo (EmpathyAccountWidget *self,
1224     const char *filename)
1225 {
1226   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1227
1228   if (priv->simple)
1229     {
1230       self->ui_details->gui = empathy_builder_get_file (filename,
1231           "vbox_yahoo_simple", &self->ui_details->widget,
1232           NULL);
1233
1234       empathy_account_widget_handle_params (self,
1235           "entry_id_simple", "account",
1236           "entry_password_simple", "password",
1237           NULL);
1238
1239       self->ui_details->default_focus = g_strdup ("entry_id_simple");
1240     }
1241   else
1242     {
1243       self->ui_details->gui = empathy_builder_get_file (filename,
1244           "table_common_settings", &priv->table_common_settings,
1245           "vbox_yahoo_settings", &self->ui_details->widget,
1246           NULL);
1247
1248       empathy_account_widget_handle_params (self,
1249           "entry_id", "account",
1250           "entry_password", "password",
1251           "entry_server", "server",
1252           "entry_locale", "room-list-locale",
1253           "entry_charset", "charset",
1254           "spinbutton_port", "port",
1255           "checkbutton_yahoojp", "yahoojp",
1256           "checkbutton_ignore_invites", "ignore-invites",
1257           NULL);
1258
1259       self->ui_details->default_focus = g_strdup ("entry_id");
1260       self->ui_details->add_forget = TRUE;
1261     }
1262 }
1263
1264 static void
1265 account_widget_build_groupwise (EmpathyAccountWidget *self,
1266     const char *filename)
1267 {
1268   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1269
1270   if (priv->simple)
1271     {
1272       self->ui_details->gui = empathy_builder_get_file (filename,
1273           "vbox_groupwise_simple", &self->ui_details->widget,
1274           NULL);
1275
1276       empathy_account_widget_handle_params (self,
1277           "entry_id_simple", "account",
1278           "entry_password_simple", "password",
1279           NULL);
1280
1281       self->ui_details->default_focus = g_strdup ("entry_id_simple");
1282     }
1283   else
1284     {
1285       self->ui_details->gui = empathy_builder_get_file (filename,
1286           "table_common_groupwise_settings", &priv->table_common_settings,
1287           "vbox_groupwise_settings", &self->ui_details->widget,
1288           NULL);
1289
1290       empathy_account_widget_handle_params (self,
1291           "entry_id", "account",
1292           "entry_password", "password",
1293           "entry_server", "server",
1294           "spinbutton_port", "port",
1295           NULL);
1296
1297       self->ui_details->default_focus = g_strdup ("entry_id");
1298       self->ui_details->add_forget = TRUE;
1299     }
1300 }
1301
1302 static void
1303 account_widget_destroy_cb (GtkWidget *widget,
1304     EmpathyAccountWidget *self)
1305 {
1306   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1307   /* set the destroyed flag - workaround */
1308   priv->destroyed = TRUE;
1309
1310   g_object_unref (self);
1311 }
1312
1313 static void
1314 empathy_account_widget_enabled_cb (TpAccount *account,
1315       GParamSpec *spec,
1316       gpointer user_data)
1317 {
1318   EmpathyAccountWidget *widget = EMPATHY_ACCOUNT_WIDGET (user_data);
1319   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
1320   gboolean enabled = tp_account_is_enabled (account);
1321
1322   if (priv->enabled_checkbox != NULL)
1323     {
1324 #ifdef HAVE_MEEGO
1325       mx_gtk_light_switch_set_active (
1326           MX_GTK_LIGHT_SWITCH (priv->enabled_checkbox),
1327           enabled);
1328 #else
1329       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->enabled_checkbox),
1330           enabled);
1331 #endif /* HAVE_MEEGO */
1332     }
1333 }
1334
1335 static void
1336 #ifdef HAVE_MEEGO
1337 account_widget_switch_flipped_cb (MxGtkLightSwitch *sw,
1338     gboolean state,
1339     gpointer user_data)
1340 #else
1341 account_widget_enabled_released_cb (GtkToggleButton *toggle_button,
1342     gpointer user_data)
1343 #endif /* HAVE_MEEGO */
1344 {
1345   EmpathyAccountWidgetPriv *priv = GET_PRIV (user_data);
1346   TpAccount *account;
1347 #ifndef HAVE_MEEGO
1348   gboolean state;
1349
1350   state = gtk_toggle_button_get_active (toggle_button);
1351 #endif /* HAVE_MEEGO */
1352
1353   account = empathy_account_settings_get_account (priv->settings);
1354
1355   /* Enable the account according to the value of the "Enabled" checkbox */
1356   /* workaround to keep widget alive during async call */
1357   g_object_ref (user_data);
1358   tp_account_set_enabled_async (account, state,
1359       account_widget_account_enabled_cb, user_data);
1360 }
1361
1362 void
1363 empathy_account_widget_set_other_accounts_exist (EmpathyAccountWidget *self,
1364     gboolean others_exist)
1365 {
1366   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1367
1368   priv->other_accounts_exist = others_exist;
1369
1370   if (priv->creating_account)
1371     account_widget_handle_control_buttons_sensitivity (self);
1372 }
1373
1374 static void
1375 do_set_property (GObject *object,
1376     guint prop_id,
1377     const GValue *value,
1378     GParamSpec *pspec)
1379 {
1380   EmpathyAccountWidgetPriv *priv = GET_PRIV (object);
1381
1382   switch (prop_id)
1383     {
1384     case PROP_SETTINGS:
1385       priv->settings = g_value_dup_object (value);
1386       break;
1387     case PROP_SIMPLE:
1388       priv->simple = g_value_get_boolean (value);
1389       break;
1390     case PROP_CREATING_ACCOUNT:
1391       priv->creating_account = g_value_get_boolean (value);
1392       break;
1393     case PROP_OTHER_ACCOUNTS_EXIST:
1394       empathy_account_widget_set_other_accounts_exist (
1395           EMPATHY_ACCOUNT_WIDGET (object), g_value_get_boolean (value));
1396       break;
1397     default:
1398       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1399     }
1400 }
1401
1402 static void
1403 do_get_property (GObject *object,
1404     guint prop_id,
1405     GValue *value,
1406     GParamSpec *pspec)
1407 {
1408   EmpathyAccountWidgetPriv *priv = GET_PRIV (object);
1409
1410   switch (prop_id)
1411     {
1412     case PROP_PROTOCOL:
1413       g_value_set_string (value,
1414         empathy_account_settings_get_protocol (priv->settings));
1415       break;
1416     case PROP_SETTINGS:
1417       g_value_set_object (value, priv->settings);
1418       break;
1419     case PROP_SIMPLE:
1420       g_value_set_boolean (value, priv->simple);
1421       break;
1422     case PROP_CREATING_ACCOUNT:
1423       g_value_set_boolean (value, priv->creating_account);
1424       break;
1425     case PROP_OTHER_ACCOUNTS_EXIST:
1426       g_value_set_boolean (value, priv->other_accounts_exist);
1427       break;
1428     default:
1429       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1430     }
1431 }
1432
1433 static void
1434 presence_changed_cb (TpAccountManager *manager,
1435     TpConnectionPresenceType state,
1436     const gchar *status,
1437     const gchar *message,
1438     EmpathyAccountWidget *self)
1439 {
1440   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1441
1442   if (priv->destroyed)
1443     return;
1444
1445   if (priv->apply_button == NULL)
1446     /* This button doesn't exist in 'simple' mode */
1447     return;
1448
1449   if (state > TP_CONNECTION_PRESENCE_TYPE_OFFLINE &&
1450       priv->creating_account)
1451     {
1452       /* We are online and creating a new account, display a Login button */
1453       GtkWidget *image;
1454
1455       gtk_button_set_use_stock (GTK_BUTTON (priv->apply_button), FALSE);
1456       gtk_button_set_label (GTK_BUTTON (priv->apply_button), _("L_og in"));
1457
1458       image = gtk_image_new_from_stock (GTK_STOCK_CONNECT,
1459           GTK_ICON_SIZE_BUTTON);
1460       gtk_button_set_image (GTK_BUTTON (priv->apply_button), image);
1461     }
1462   else
1463     {
1464       /* We are offline or modifying an existing account, display
1465        * a Save button */
1466       gtk_button_set_image (GTK_BUTTON (priv->apply_button), NULL);
1467       gtk_button_set_use_stock (GTK_BUTTON (priv->apply_button), TRUE);
1468       gtk_button_set_label (GTK_BUTTON (priv->apply_button), GTK_STOCK_APPLY);
1469     }
1470 }
1471
1472 static void
1473 account_manager_ready_cb (GObject *source_object,
1474     GAsyncResult *result,
1475     gpointer user_data)
1476 {
1477   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (user_data);
1478   TpAccountManager *account_manager = TP_ACCOUNT_MANAGER (source_object);
1479   GError *error = NULL;
1480   TpConnectionPresenceType state;
1481
1482   if (!tp_account_manager_prepare_finish (account_manager, result, &error))
1483     {
1484       DEBUG ("Failed to prepare account manager: %s", error->message);
1485       g_error_free (error);
1486       goto out;
1487     }
1488
1489   state = tp_account_manager_get_most_available_presence (account_manager, NULL,
1490       NULL);
1491
1492   /* simulate a presence change so the apply button will be changed
1493    * if needed */
1494   presence_changed_cb (account_manager, state, NULL, NULL, self);
1495
1496 out:
1497   g_object_unref (self);
1498 }
1499
1500 #define WIDGET(cm, proto) \
1501   { #cm, #proto, "empathy-account-widget-"#proto".ui", \
1502     account_widget_build_##proto }
1503
1504 static void
1505 add_enable_checkbox (EmpathyAccountWidget *self,
1506     TpAccount *account)
1507 {
1508   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1509 #ifdef HAVE_MEEGO
1510   GtkWidget *w;
1511 #else
1512   GtkWidget *vbox = self->ui_details->widget;
1513 #endif /* HAVE_MEEGO */
1514   guint nb_rows, nb_columns;
1515   gboolean is_enabled;
1516
1517   /* handle the "Enabled" checkbox. We only add it when modifying an account */
1518   if (priv->creating_account || priv->table_common_settings == NULL)
1519     return;
1520
1521   is_enabled = tp_account_is_enabled (account);
1522
1523 #ifdef HAVE_MEEGO
1524   w = gtk_label_new (_("Account:"));
1525   gtk_misc_set_alignment (GTK_MISC (w), 0, 0.5);
1526
1527   priv->enabled_checkbox = mx_gtk_light_switch_new ();
1528
1529   mx_gtk_light_switch_set_active (
1530       MX_GTK_LIGHT_SWITCH (priv->enabled_checkbox), is_enabled);
1531
1532   gtk_widget_show (w);
1533 #else
1534   priv->enabled_checkbox =
1535       gtk_check_button_new_with_label (_("Enabled"));
1536
1537   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->enabled_checkbox),
1538       is_enabled);
1539 #endif /* HAVE_MEEGO */
1540
1541   g_object_get (priv->table_common_settings, "n-rows", &nb_rows,
1542       "n-columns", &nb_columns, NULL);
1543
1544   gtk_table_resize (GTK_TABLE (priv->table_common_settings), ++nb_rows,
1545       nb_columns);
1546
1547 #ifdef HAVE_MEEGO
1548   gtk_table_attach (GTK_TABLE (priv->table_common_settings),
1549       w,
1550       0, 1, nb_rows - 1, nb_rows,
1551       GTK_FILL, 0, 0, 0);
1552   gtk_table_attach (GTK_TABLE (priv->table_common_settings),
1553       priv->enabled_checkbox,
1554       1, nb_columns, nb_rows - 1, nb_rows,
1555       GTK_EXPAND | GTK_FILL, 0, 0, 0);
1556 #else
1557   gtk_box_pack_start (GTK_BOX (vbox), priv->enabled_checkbox, FALSE, FALSE, 0);
1558   gtk_box_reorder_child (GTK_BOX (vbox), priv->enabled_checkbox, 0);
1559 #endif /* HAVE_MEEGO */
1560
1561   gtk_widget_show (priv->enabled_checkbox);
1562
1563 #ifdef HAVE_MEEGO
1564   g_signal_connect (G_OBJECT (priv->enabled_checkbox), "switch-flipped",
1565       G_CALLBACK (account_widget_switch_flipped_cb), self);
1566 #else
1567   g_signal_connect (G_OBJECT (priv->enabled_checkbox), "released",
1568       G_CALLBACK (account_widget_enabled_released_cb), self);
1569 #endif /* HAVE_MEEGO */
1570 }
1571
1572 #ifndef HAVE_MEEGO
1573 /* Meego doesn't support registration */
1574 static void
1575 add_register_buttons (EmpathyAccountWidget *self,
1576     TpAccount *account)
1577 {
1578   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1579   const TpConnectionManagerProtocol *protocol;
1580   GtkWidget *radiobutton_register;
1581   GtkWidget *vbox = self->ui_details->widget;
1582
1583   if (!priv->creating_account)
1584     return;
1585
1586   protocol = empathy_account_settings_get_tp_protocol (priv->settings);
1587   if (protocol == NULL)
1588     return;
1589
1590   if (!tp_connection_manager_protocol_can_register (protocol))
1591     return;
1592
1593   if (account_widget_is_gtalk (self) || account_widget_is_facebook (self))
1594     return;
1595
1596   if (priv->simple)
1597     return;
1598
1599   priv->radiobutton_reuse = gtk_radio_button_new_with_label (NULL,
1600       _("This account already exists on the server"));
1601   radiobutton_register = gtk_radio_button_new_with_label (
1602       gtk_radio_button_get_group (GTK_RADIO_BUTTON (priv->radiobutton_reuse)),
1603       _("Create a new account on the server"));
1604
1605   gtk_box_pack_start (GTK_BOX (vbox), priv->radiobutton_reuse, FALSE, FALSE, 0);
1606   gtk_box_pack_start (GTK_BOX (vbox), radiobutton_register, FALSE, FALSE, 0);
1607   gtk_box_reorder_child (GTK_BOX (vbox), priv->radiobutton_reuse, 0);
1608   gtk_box_reorder_child (GTK_BOX (vbox), radiobutton_register, 1);
1609   gtk_widget_show (priv->radiobutton_reuse);
1610   gtk_widget_show (radiobutton_register);
1611 }
1612 #endif /* HAVE_MEEGO */
1613
1614 static void
1615 do_constructed (GObject *obj)
1616 {
1617   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
1618   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1619   TpAccount *account;
1620   const gchar *protocol, *cm_name;
1621   guint i = 0;
1622   struct {
1623     const gchar *cm_name;
1624     const gchar *protocol;
1625     const char *file;
1626     void (*func)(EmpathyAccountWidget *self, const gchar *filename);
1627   } widgets [] = {
1628     { "salut", "local-xmpp", "empathy-account-widget-local-xmpp.ui",
1629         account_widget_build_salut },
1630     WIDGET (gabble, jabber),
1631     WIDGET (butterfly, msn),
1632     WIDGET (haze, icq),
1633     WIDGET (haze, aim),
1634     WIDGET (haze, yahoo),
1635     WIDGET (haze, groupwise),
1636     WIDGET (idle, irc),
1637     WIDGET (sofiasip, sip),
1638   };
1639
1640   cm_name = empathy_account_settings_get_cm (priv->settings);
1641   protocol = empathy_account_settings_get_protocol (priv->settings);
1642
1643   for (i = 0 ; i < G_N_ELEMENTS (widgets); i++)
1644     {
1645       if (!tp_strdiff (widgets[i].cm_name, cm_name) &&
1646           !tp_strdiff (widgets[i].protocol, protocol))
1647         {
1648           gchar *filename;
1649
1650           filename = empathy_file_lookup (widgets[i].file,
1651               "libempathy-gtk");
1652           widgets[i].func (self, filename);
1653           g_free (filename);
1654
1655           break;
1656         }
1657     }
1658
1659   if (i == G_N_ELEMENTS (widgets))
1660     {
1661       gchar *filename = empathy_file_lookup (
1662           "empathy-account-widget-generic.ui", "libempathy-gtk");
1663       account_widget_build_generic (self, filename);
1664       g_free (filename);
1665     }
1666
1667   /* handle default focus */
1668   if (self->ui_details->default_focus != NULL)
1669     {
1670       GObject *default_focus_entry;
1671
1672       default_focus_entry = gtk_builder_get_object
1673         (self->ui_details->gui, self->ui_details->default_focus);
1674       g_signal_connect (default_focus_entry, "realize",
1675           G_CALLBACK (gtk_widget_grab_focus),
1676           NULL);
1677     }
1678
1679   /* handle forget button */
1680   if (self->ui_details->add_forget)
1681     {
1682       const gchar *password = NULL;
1683
1684       priv->button_forget = GTK_WIDGET (gtk_builder_get_object
1685           (self->ui_details->gui, "button_forget"));
1686       priv->entry_password = GTK_WIDGET (gtk_builder_get_object
1687           (self->ui_details->gui, "entry_password"));
1688
1689       password = empathy_account_settings_get_string (priv->settings,
1690           "password");
1691       gtk_widget_set_sensitive (priv->button_forget,
1692           !EMP_STR_EMPTY (password));
1693
1694       g_signal_connect (priv->button_forget, "clicked",
1695           G_CALLBACK (account_widget_forget_clicked_cb),
1696           self);
1697       g_signal_connect (priv->entry_password, "changed",
1698           G_CALLBACK (account_widget_password_changed_cb),
1699           self);
1700     }
1701
1702   /* dup and init the account-manager */
1703   priv->account_manager = tp_account_manager_dup ();
1704
1705   g_object_ref (self);
1706   tp_account_manager_prepare_async (priv->account_manager, NULL,
1707       account_manager_ready_cb, self);
1708
1709   /* handle apply and cancel button */
1710   if (!priv->simple)
1711     {
1712       GtkWidget *hbox = gtk_hbox_new (TRUE, 3);
1713
1714       priv->cancel_button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
1715
1716       priv->apply_button = gtk_button_new_from_stock (GTK_STOCK_APPLY);
1717
1718       /* We'll change this button to a "Log in" one if we are creating a new
1719        * account and are connected. */
1720       empathy_signal_connect_weak (priv->account_manager,
1721           "most-available-presence-changed",
1722           G_CALLBACK (presence_changed_cb), obj);
1723
1724       gtk_box_pack_end (GTK_BOX (hbox), priv->apply_button, TRUE,
1725           TRUE, 3);
1726       gtk_box_pack_end (GTK_BOX (hbox), priv->cancel_button, TRUE,
1727           TRUE, 3);
1728
1729       gtk_box_pack_end (GTK_BOX (self->ui_details->widget), hbox, FALSE,
1730           FALSE, 3);
1731
1732       g_signal_connect (priv->cancel_button, "clicked",
1733           G_CALLBACK (account_widget_cancel_clicked_cb),
1734           self);
1735       g_signal_connect (priv->apply_button, "clicked",
1736           G_CALLBACK (account_widget_apply_clicked_cb),
1737           self);
1738       gtk_widget_show_all (hbox);
1739
1740       if (priv->creating_account)
1741         /* When creating an account, the user might have nothing to enter.
1742          * That means that no control interaction might occur,
1743          * so we update the control button sensitivity manually.
1744          */
1745         account_widget_handle_control_buttons_sensitivity (self);
1746       else
1747         account_widget_set_control_buttons_sensitivity (self, FALSE);
1748     }
1749
1750   account = empathy_account_settings_get_account (priv->settings);
1751
1752   if (account != NULL)
1753     {
1754       g_signal_connect (account, "notify::enabled",
1755           G_CALLBACK (empathy_account_widget_enabled_cb), self);
1756     }
1757
1758 #ifndef HAVE_MEEGO
1759   add_register_buttons (self, account);
1760 #endif /* HAVE_MEEGO */
1761   add_enable_checkbox (self, account);
1762
1763   /* hook up to widget destruction to unref ourselves */
1764   g_signal_connect (self->ui_details->widget, "destroy",
1765       G_CALLBACK (account_widget_destroy_cb), self);
1766
1767   empathy_builder_unref_and_keep_widget (self->ui_details->gui,
1768       self->ui_details->widget);
1769   self->ui_details->gui = NULL;
1770 }
1771
1772 static void
1773 do_dispose (GObject *obj)
1774 {
1775   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
1776   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1777
1778   if (priv->dispose_run)
1779     return;
1780
1781   priv->dispose_run = TRUE;
1782
1783   empathy_account_settings_is_ready (priv->settings);
1784
1785   if (priv->settings != NULL)
1786     {
1787       TpAccount *account;
1788       account = empathy_account_settings_get_account (priv->settings);
1789
1790       if (account != NULL)
1791         {
1792           g_signal_handlers_disconnect_by_func (account,
1793               empathy_account_widget_enabled_cb, self);
1794         }
1795
1796       g_object_unref (priv->settings);
1797       priv->settings = NULL;
1798     }
1799
1800   if (priv->account_manager != NULL)
1801     {
1802       g_object_unref (priv->account_manager);
1803       priv->account_manager = NULL;
1804     }
1805
1806   if (G_OBJECT_CLASS (empathy_account_widget_parent_class)->dispose != NULL)
1807     G_OBJECT_CLASS (empathy_account_widget_parent_class)->dispose (obj);
1808 }
1809
1810 static void
1811 do_finalize (GObject *obj)
1812 {
1813   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
1814
1815   g_free (self->ui_details->default_focus);
1816   g_slice_free (EmpathyAccountWidgetUIDetails, self->ui_details);
1817
1818   if (G_OBJECT_CLASS (empathy_account_widget_parent_class)->finalize != NULL)
1819     G_OBJECT_CLASS (empathy_account_widget_parent_class)->finalize (obj);
1820 }
1821
1822 static void
1823 empathy_account_widget_class_init (EmpathyAccountWidgetClass *klass)
1824 {
1825   GObjectClass *oclass = G_OBJECT_CLASS (klass);
1826   GParamSpec *param_spec;
1827
1828   oclass->get_property = do_get_property;
1829   oclass->set_property = do_set_property;
1830   oclass->constructed = do_constructed;
1831   oclass->dispose = do_dispose;
1832   oclass->finalize = do_finalize;
1833
1834   param_spec = g_param_spec_string ("protocol",
1835       "protocol", "The protocol of the account",
1836       NULL,
1837       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
1838   g_object_class_install_property (oclass, PROP_PROTOCOL, param_spec);
1839
1840   param_spec = g_param_spec_object ("settings",
1841       "settings", "The settings of the account",
1842       EMPATHY_TYPE_ACCOUNT_SETTINGS,
1843       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
1844   g_object_class_install_property (oclass, PROP_SETTINGS, param_spec);
1845
1846   param_spec = g_param_spec_boolean ("simple",
1847       "simple", "Whether the account widget is a simple or an advanced one",
1848       FALSE,
1849       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
1850   g_object_class_install_property (oclass, PROP_SIMPLE, param_spec);
1851
1852   param_spec = g_param_spec_boolean ("creating-account",
1853       "creating-account",
1854       "TRUE if we're creating an account, FALSE if we're modifying it",
1855       FALSE,
1856       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
1857   g_object_class_install_property (oclass, PROP_CREATING_ACCOUNT, param_spec);
1858
1859   param_spec = g_param_spec_boolean ("other-accounts-exist",
1860       "other-accounts-exist",
1861       "TRUE if there are any other accounts (even if this isn't yet saved)",
1862       FALSE,
1863       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
1864   g_object_class_install_property (oclass, PROP_OTHER_ACCOUNTS_EXIST,
1865                   param_spec);
1866
1867   signals[HANDLE_APPLY] =
1868     g_signal_new ("handle-apply", G_TYPE_FROM_CLASS (klass),
1869         G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1870         g_cclosure_marshal_VOID__BOOLEAN,
1871         G_TYPE_NONE,
1872         1, G_TYPE_BOOLEAN);
1873
1874   /* This signal is emitted when an account has been created and enabled. */
1875   signals[ACCOUNT_CREATED] =
1876       g_signal_new ("account-created", G_TYPE_FROM_CLASS (klass),
1877           G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1878           g_cclosure_marshal_VOID__POINTER,
1879           G_TYPE_NONE,
1880           1, G_TYPE_OBJECT);
1881
1882   signals[CANCELLED] =
1883       g_signal_new ("cancelled", G_TYPE_FROM_CLASS (klass),
1884           G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1885           g_cclosure_marshal_VOID__VOID,
1886           G_TYPE_NONE,
1887           0);
1888
1889   g_type_class_add_private (klass, sizeof (EmpathyAccountWidgetPriv));
1890 }
1891
1892 static void
1893 empathy_account_widget_init (EmpathyAccountWidget *self)
1894 {
1895   EmpathyAccountWidgetPriv *priv =
1896     G_TYPE_INSTANCE_GET_PRIVATE ((self), EMPATHY_TYPE_ACCOUNT_WIDGET,
1897         EmpathyAccountWidgetPriv);
1898
1899   self->priv = priv;
1900   priv->dispose_run = FALSE;
1901
1902   self->ui_details = g_slice_new0 (EmpathyAccountWidgetUIDetails);
1903 }
1904
1905 /* public methods */
1906
1907 void
1908 empathy_account_widget_discard_pending_changes
1909     (EmpathyAccountWidget *widget)
1910 {
1911   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
1912
1913   empathy_account_settings_discard_changes (priv->settings);
1914   priv->contains_pending_changes = FALSE;
1915 }
1916
1917 gboolean
1918 empathy_account_widget_contains_pending_changes (EmpathyAccountWidget *widget)
1919 {
1920   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
1921
1922   return priv->contains_pending_changes;
1923 }
1924
1925 void
1926 empathy_account_widget_handle_params (EmpathyAccountWidget *self,
1927     const gchar *first_widget,
1928     ...)
1929 {
1930   va_list args;
1931
1932   va_start (args, first_widget);
1933   account_widget_handle_params_valist (self, first_widget, args);
1934   va_end (args);
1935 }
1936
1937 GtkWidget *
1938 empathy_account_widget_get_widget (EmpathyAccountWidget *widget)
1939 {
1940   return widget->ui_details->widget;
1941 }
1942
1943 EmpathyAccountWidget *
1944 empathy_account_widget_new_for_protocol (EmpathyAccountSettings *settings,
1945     gboolean simple)
1946 {
1947   EmpathyAccountWidget *self;
1948
1949   g_return_val_if_fail (EMPATHY_IS_ACCOUNT_SETTINGS (settings), NULL);
1950
1951   self = g_object_new
1952     (EMPATHY_TYPE_ACCOUNT_WIDGET,
1953         "settings", settings, "simple", simple,
1954         "creating-account",
1955         empathy_account_settings_get_account (settings) == NULL,
1956         NULL);
1957
1958   return self;
1959 }
1960
1961 gchar *
1962 empathy_account_widget_get_default_display_name (EmpathyAccountWidget *self)
1963 {
1964   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1965   const gchar *login_id;
1966   const gchar *protocol, *p;
1967   gchar *default_display_name;
1968
1969   login_id = empathy_account_settings_get_string (priv->settings, "account");
1970   protocol = empathy_account_settings_get_protocol (priv->settings);
1971
1972   if (login_id != NULL)
1973     {
1974       /* TODO: this should be done in empathy-account-widget-irc */
1975       if (!tp_strdiff (protocol, "irc"))
1976         {
1977           const gchar* server;
1978           server = empathy_account_settings_get_string (priv->settings,
1979               "server");
1980
1981           /* To translators: The first parameter is the login id and the
1982            * second one is the server. The resulting string will be something
1983            * like: "MyUserName on chat.freenode.net".
1984            * You should reverse the order of these arguments if the
1985            * server should come before the login id in your locale.*/
1986           default_display_name = g_strdup_printf (_("%1$s on %2$s"),
1987               login_id, server);
1988         }
1989       else if (account_widget_is_facebook (self))
1990         {
1991           gchar *tmp;
1992
1993           tmp = remove_facebook_suffix (login_id);
1994           default_display_name = g_strdup_printf ("Facebook (%s)", tmp);
1995           g_free (tmp);
1996         }
1997       else
1998         {
1999           default_display_name = g_strdup (login_id);
2000         }
2001
2002       return default_display_name;
2003     }
2004
2005   if ((p = empathy_protocol_name_to_display_name (protocol)) != NULL)
2006     protocol = p;
2007
2008   if (protocol != NULL)
2009     {
2010       /* To translators: The parameter is the protocol name. The resulting
2011        * string will be something like: "Jabber Account" */
2012       default_display_name = g_strdup_printf (_("%s Account"), protocol);
2013     }
2014   else
2015     {
2016       default_display_name = g_strdup (_("New account"));
2017     }
2018
2019   return default_display_name;
2020 }
2021
2022 /* Used by subclass to indicate that widget contains pending changes */
2023 void
2024 empathy_account_widget_changed (EmpathyAccountWidget *self)
2025 {
2026   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
2027
2028   account_widget_handle_control_buttons_sensitivity (self);
2029   priv->contains_pending_changes = TRUE;
2030 }
2031
2032 void
2033 empathy_account_widget_set_account_param (EmpathyAccountWidget *self,
2034     const gchar *account)
2035 {
2036   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
2037
2038   if (priv->param_account_widget == NULL)
2039     return;
2040
2041   gtk_entry_set_text (GTK_ENTRY (priv->param_account_widget), account);
2042 }
2043
2044 void
2045 empathy_account_widget_set_password_param (EmpathyAccountWidget *self,
2046     const gchar *account)
2047 {
2048   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
2049
2050   if (priv->param_password_widget == NULL)
2051     return;
2052
2053   gtk_entry_set_text (GTK_ENTRY (priv->param_password_widget), account);
2054 }