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