]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-account-widget.c
Merge commit 'wjt/all'
[empathy.git] / libempathy-gtk / empathy-account-widget.c
1 /*
2  * Copyright (C) 2006-2007 Imendio AB
3  * Copyright (C) 2007-2009 Collabora Ltd.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA  02110-1301  USA
19  *
20  * Authors: Xavier Claessens <xclaesse@gmail.com>
21  *          Martyn Russell <martyn@imendio.com>
22  *          Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
23  *          Jonathan Tellier <jonathan.tellier@gmail.com>
24  */
25
26 #include <config.h>
27
28 #include <string.h>
29
30 #include <gtk/gtk.h>
31 #include <glib/gi18n-lib.h>
32
33 #ifdef HAVE_MOBLIN
34 #include <mx/mx-gtk.h>
35 #endif
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   TpConnectionPresenceType presence;
672   gchar *message = NULL;
673   gchar *status = NULL;
674
675   tp_account_set_enabled_finish (account, res, &error);
676
677   if (error != NULL)
678     {
679       DEBUG ("Could not enable the account: %s", error->message);
680       g_error_free (error);
681     }
682   else
683     {
684       /* only force presence if presence was offline, unknown or unset */
685       presence = tp_account_get_requested_presence (account, NULL, NULL);
686       switch (presence)
687         {
688         case TP_CONNECTION_PRESENCE_TYPE_OFFLINE:
689         case TP_CONNECTION_PRESENCE_TYPE_UNKNOWN:
690         case TP_CONNECTION_PRESENCE_TYPE_UNSET:
691           presence = tp_account_manager_get_most_available_presence (
692               priv->account_manager, &status, &message);
693           tp_account_request_presence_async (account, presence,
694               status, NULL, NULL, NULL);
695           break;
696         default:
697           /* do nothing if the presence is not offline */
698           break;
699         }
700     }
701
702   /* unref widget - part of the workaround */
703   g_object_unref (widget);
704   g_free (message);
705   g_free (status);
706 }
707
708 static void
709 account_widget_applied_cb (GObject *source_object,
710     GAsyncResult *res,
711     gpointer user_data)
712 {
713   GError *error = NULL;
714   TpAccount *account;
715   EmpathyAccountSettings *settings = EMPATHY_ACCOUNT_SETTINGS (source_object);
716   EmpathyAccountWidget *widget = EMPATHY_ACCOUNT_WIDGET (user_data);
717   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
718
719   empathy_account_settings_apply_finish (settings, res, &error);
720
721   if (error != NULL)
722     {
723       DEBUG ("Could not apply changes to account: %s", error->message);
724       g_error_free (error);
725       return;
726     }
727
728   account = empathy_account_settings_get_account (priv->settings);
729
730   if (account != NULL)
731     {
732       if (priv->creating_account)
733         {
734           /* By default, when an account is created, we enable it. */
735
736           /* workaround to keep widget alive during async call */
737           g_object_ref (widget);
738
739           tp_account_set_enabled_async (account, TRUE,
740               account_widget_account_enabled_cb, widget);
741           g_signal_emit (widget, signals[ACCOUNT_CREATED], 0, account);
742         }
743       else if (priv->enabled_checkbox != NULL)
744         {
745           gboolean enabled_checked;
746
747           enabled_checked =
748 #ifdef HAVE_MOBLIN
749             mx_gtk_light_switch_get_active (
750                 MX_GTK_LIGHT_SWITCH (priv->enabled_checkbox));
751 #else
752             gtk_toggle_button_get_active (
753                 GTK_TOGGLE_BUTTON (priv->enabled_checkbox));
754 #endif
755
756           if (tp_account_is_enabled (account) && enabled_checked)
757             {
758               /* After having applied changes to a user account, we
759                * automatically reconnect it. This is done so the new
760                * information entered by the user is validated on the server. */
761               tp_account_reconnect_async (account, NULL, NULL);
762             }
763         }
764     }
765
766   if (!priv->destroyed)
767     account_widget_set_control_buttons_sensitivity (widget, FALSE);
768
769   priv->contains_pending_changes = FALSE;
770
771   /* unref the widget - part of the workaround */
772   g_object_unref (widget);
773 }
774
775 static void
776 account_widget_apply_clicked_cb (GtkWidget *button,
777     EmpathyAccountWidget *self)
778 {
779   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
780
781   if (priv->radiobutton_reuse != NULL)
782     {
783       gboolean reuse = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
784             priv->radiobutton_reuse));
785
786       DEBUG ("Set register param: %d", !reuse);
787       empathy_account_settings_set_boolean (priv->settings, "register", !reuse);
788     }
789
790   /* workaround to keep widget alive during async call */
791   g_object_ref (self);
792   empathy_account_settings_apply_async (priv->settings,
793       account_widget_applied_cb, self);
794 }
795
796 static void
797 account_widget_setup_generic (EmpathyAccountWidget *self)
798 {
799   GtkWidget *table_common_settings;
800   GtkWidget *table_advanced_settings;
801
802   table_common_settings = GTK_WIDGET (gtk_builder_get_object
803       (self->ui_details->gui, "table_common_settings"));
804   table_advanced_settings = GTK_WIDGET (gtk_builder_get_object
805       (self->ui_details->gui, "table_advanced_settings"));
806
807   accounts_widget_generic_setup (self, table_common_settings,
808       table_advanced_settings);
809
810   g_object_unref (self->ui_details->gui);
811 }
812
813 static void
814 account_widget_settings_ready_cb (EmpathyAccountSettings *settings,
815     GParamSpec *pspec,
816     gpointer user_data)
817 {
818   EmpathyAccountWidget *self = user_data;
819   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
820
821   if (empathy_account_settings_is_ready (priv->settings))
822     account_widget_setup_generic (self);
823 }
824
825 static void
826 account_widget_build_generic (EmpathyAccountWidget *self,
827     const char *filename)
828 {
829   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
830   GtkWidget *expander_advanced;
831
832   self->ui_details->gui = empathy_builder_get_file (filename,
833       "table_common_settings", &priv->table_common_settings,
834       "vbox_generic_settings", &self->ui_details->widget,
835       "expander_advanced_settings", &expander_advanced,
836       NULL);
837
838   if (priv->simple)
839     gtk_widget_hide (expander_advanced);
840
841   g_object_ref (self->ui_details->gui);
842
843   if (empathy_account_settings_is_ready (priv->settings))
844     account_widget_setup_generic (self);
845   else
846     g_signal_connect (priv->settings, "notify::ready",
847         G_CALLBACK (account_widget_settings_ready_cb), self);
848 }
849
850 static void
851 account_widget_build_salut (EmpathyAccountWidget *self,
852     const char *filename)
853 {
854   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
855   GtkWidget *expander_advanced;
856
857   self->ui_details->gui = empathy_builder_get_file (filename,
858       "table_common_settings", &priv->table_common_settings,
859       "vbox_salut_settings", &self->ui_details->widget,
860       "expander_advanced_settings", &expander_advanced,
861       NULL);
862
863   empathy_account_widget_handle_params (self,
864       "entry_published", "published-name",
865       "entry_nickname", "nickname",
866       "entry_first_name", "first-name",
867       "entry_last_name", "last-name",
868       "entry_email", "email",
869       "entry_jid", "jid",
870       NULL);
871
872   if (priv->simple)
873     gtk_widget_hide (expander_advanced);
874
875   self->ui_details->default_focus = g_strdup ("entry_first_name");
876 }
877
878 static void
879 account_widget_build_irc (EmpathyAccountWidget *self,
880   const char *filename)
881 {
882   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
883   empathy_account_widget_irc_build (self, filename,
884     &priv->table_common_settings);
885 }
886
887 static void
888 account_widget_build_sip (EmpathyAccountWidget *self,
889   const char *filename)
890 {
891   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
892   empathy_account_widget_sip_build (self, filename,
893     &priv->table_common_settings);
894 }
895
896 static void
897 account_widget_build_msn (EmpathyAccountWidget *self,
898     const char *filename)
899 {
900   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
901
902   if (priv->simple)
903     {
904       self->ui_details->gui = empathy_builder_get_file (filename,
905           "vbox_msn_simple", &self->ui_details->widget,
906           NULL);
907
908       empathy_account_widget_handle_params (self,
909           "entry_id_simple", "account",
910           "entry_password_simple", "password",
911           NULL);
912
913       self->ui_details->default_focus = g_strdup ("entry_id_simple");
914     }
915   else
916     {
917       self->ui_details->gui = empathy_builder_get_file (filename,
918           "table_common_msn_settings", &priv->table_common_settings,
919           "vbox_msn_settings", &self->ui_details->widget,
920           NULL);
921
922       empathy_account_widget_handle_params (self,
923           "entry_id", "account",
924           "entry_password", "password",
925           "entry_server", "server",
926           "spinbutton_port", "port",
927           NULL);
928
929       self->ui_details->default_focus = g_strdup ("entry_id");
930       self->ui_details->add_forget = TRUE;
931     }
932 }
933
934 static gboolean
935 account_widget_is_gtalk (EmpathyAccountWidget *self)
936 {
937   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
938
939   return !tp_strdiff (empathy_account_settings_get_icon_name (priv->settings),
940       "im-google-talk");
941 }
942
943 static gboolean
944 account_widget_is_facebook (EmpathyAccountWidget *self)
945 {
946   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
947
948   return !tp_strdiff (empathy_account_settings_get_icon_name (priv->settings),
949       "im-facebook");
950 }
951
952 #define FACEBOOK_SUFFIX "@chat.facebook.com"
953
954 static void
955 facebook_id_widget_changed_cb (GtkWidget *entry,
956     EmpathyAccountWidget *self)
957 {
958   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
959   const gchar *account;
960
961   account_widget_entry_changed_common (self, GTK_ENTRY (entry), FALSE);
962
963   account = empathy_account_settings_get_string (priv->settings, "account");
964   if (!EMP_STR_EMPTY (account) &&
965       !g_str_has_suffix (account, FACEBOOK_SUFFIX))
966     {
967       gchar *tmp;
968
969       tmp = g_strdup_printf ("%s%s", account, FACEBOOK_SUFFIX);
970
971       DEBUG ("Change account from '%s' to '%s'", account, tmp);
972
973       empathy_account_settings_set_string (priv->settings, "account", tmp);
974       g_free (tmp);
975     }
976
977   empathy_account_widget_changed (self);
978 }
979
980 static gchar *
981 remove_facebook_suffix (const gchar *str)
982 {
983   if (!g_str_has_suffix (str, FACEBOOK_SUFFIX))
984     return g_strdup (str);
985
986   return g_strndup (str, strlen (str) - strlen (FACEBOOK_SUFFIX));
987 }
988
989 static void
990 setup_facebook_id_widget (EmpathyAccountWidget *self,
991     GtkWidget *widget)
992 {
993   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
994   const gchar *str = NULL;
995
996   g_object_set_data_full (G_OBJECT (widget), "param_name",
997       g_strdup ("account"), g_free);
998
999   str = empathy_account_settings_get_string (priv->settings, "account");
1000   if (str != NULL)
1001     {
1002       gchar *tmp;
1003
1004       tmp = remove_facebook_suffix (str);
1005       gtk_entry_set_text (GTK_ENTRY (widget), tmp);
1006       g_free (tmp);
1007     }
1008
1009   priv->param_account_widget = widget;
1010
1011   g_signal_connect (widget, "changed",
1012       G_CALLBACK (facebook_id_widget_changed_cb), self);
1013 }
1014
1015 static void
1016 account_widget_build_jabber (EmpathyAccountWidget *self,
1017     const char *filename)
1018 {
1019   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1020   GtkWidget *spinbutton_port;
1021   GtkWidget *checkbutton_ssl;
1022   GtkWidget *label_id, *label_password;
1023   GtkWidget *label_id_create, *label_password_create;
1024   GtkWidget *label_example_gtalk, *label_example_jabber, *label_example_fb;
1025   gboolean is_gtalk, is_facebook;
1026   GtkWidget *expander_advanced;
1027   GtkWidget *entry_id;
1028
1029   is_gtalk = account_widget_is_gtalk (self);
1030   is_facebook = account_widget_is_facebook (self);
1031
1032   if (priv->simple && !is_gtalk && !is_facebook)
1033     {
1034       /* Simple widget for XMPP */
1035       self->ui_details->gui = empathy_builder_get_file (filename,
1036           "vbox_jabber_simple", &self->ui_details->widget,
1037           "label_id_simple", &label_id,
1038           "label_id_create", &label_id_create,
1039           "label_password_simple", &label_password,
1040           "label_password_create", &label_password_create,
1041           NULL);
1042
1043       if (empathy_account_settings_get_boolean (priv->settings, "register"))
1044         {
1045           gtk_widget_hide (label_id);
1046           gtk_widget_hide (label_password);
1047           gtk_widget_show (label_id_create);
1048           gtk_widget_show (label_password_create);
1049         }
1050
1051       empathy_account_widget_handle_params (self,
1052           "entry_id_simple", "account",
1053           "entry_password_simple", "password",
1054           NULL);
1055
1056       self->ui_details->default_focus = g_strdup ("entry_id_simple");
1057     }
1058   else if (priv->simple && is_gtalk)
1059     {
1060       /* Simple widget for Google Talk */
1061       self->ui_details->gui = empathy_builder_get_file (filename,
1062           "vbox_gtalk_simple", &self->ui_details->widget,
1063           NULL);
1064
1065       empathy_account_widget_handle_params (self,
1066           "entry_id_g_simple", "account",
1067           "entry_password_g_simple", "password",
1068           NULL);
1069
1070       self->ui_details->default_focus = g_strdup ("entry_id_g_simple");
1071     }
1072   else if (priv->simple && is_facebook)
1073     {
1074       /* Simple widget for Facebook */
1075       self->ui_details->gui = empathy_builder_get_file (filename,
1076           "vbox_fb_simple", &self->ui_details->widget,
1077           "entry_id_fb_simple", &entry_id,
1078           NULL);
1079
1080       empathy_account_widget_handle_params (self,
1081           "entry_password_fb_simple", "password",
1082           NULL);
1083
1084       setup_facebook_id_widget (self, entry_id);
1085
1086       self->ui_details->default_focus = g_strdup ("entry_id_fb_simple");
1087     }
1088   else
1089     {
1090       /* Full widget for XMPP, Google Talk and Facebook*/
1091       self->ui_details->gui = empathy_builder_get_file (filename,
1092           "table_common_settings", &priv->table_common_settings,
1093           "vbox_jabber_settings", &self->ui_details->widget,
1094           "spinbutton_port", &spinbutton_port,
1095           "checkbutton_ssl", &checkbutton_ssl,
1096           "label_username_example", &label_example_jabber,
1097           "label_username_g_example", &label_example_gtalk,
1098           "label_username_f_example", &label_example_fb,
1099           "expander_advanced", &expander_advanced,
1100           "entry_id", &entry_id,
1101           "label_id", &label_id,
1102           NULL);
1103
1104       empathy_account_widget_handle_params (self,
1105           "entry_password", "password",
1106           "entry_resource", "resource",
1107           "entry_server", "server",
1108           "spinbutton_port", "port",
1109           "spinbutton_priority", "priority",
1110           "checkbutton_ssl", "old-ssl",
1111           "checkbutton_ignore_ssl_errors", "ignore-ssl-errors",
1112           "checkbutton_encryption", "require-encryption",
1113           NULL);
1114
1115       if (is_facebook)
1116         {
1117           gtk_label_set_label (GTK_LABEL (label_id), _("Username:"));
1118
1119           /* Facebook special case the entry ID widget to hide the
1120            * "@chat.facebook.com" part */
1121           setup_facebook_id_widget (self, entry_id);
1122         }
1123       else
1124         {
1125           empathy_account_widget_setup_widget (self, entry_id, "account");
1126         }
1127
1128       self->ui_details->default_focus = g_strdup ("entry_id");
1129       self->ui_details->add_forget = TRUE;
1130       priv->spinbutton_port = spinbutton_port;
1131
1132       g_signal_connect (checkbutton_ssl, "toggled",
1133           G_CALLBACK (account_widget_jabber_ssl_toggled_cb),
1134           self);
1135
1136       if (is_gtalk)
1137         {
1138           gtk_widget_hide (label_example_jabber);
1139           gtk_widget_show (label_example_gtalk);
1140         }
1141       else if (is_facebook)
1142         {
1143           gtk_widget_hide (label_example_jabber);
1144           gtk_widget_show (label_example_fb);
1145           gtk_widget_hide (expander_advanced);
1146         }
1147     }
1148 }
1149
1150 static void
1151 account_widget_build_icq (EmpathyAccountWidget *self,
1152     const char *filename)
1153 {
1154   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1155   GtkWidget *spinbutton_port;
1156
1157   if (priv->simple)
1158     {
1159       self->ui_details->gui = empathy_builder_get_file (filename,
1160           "vbox_icq_simple", &self->ui_details->widget,
1161           NULL);
1162
1163       empathy_account_widget_handle_params (self,
1164           "entry_uin_simple", "account",
1165           "entry_password_simple", "password",
1166           NULL);
1167
1168       self->ui_details->default_focus = g_strdup ("entry_uin_simple");
1169     }
1170   else
1171     {
1172       self->ui_details->gui = empathy_builder_get_file (filename,
1173           "table_common_settings", &priv->table_common_settings,
1174           "vbox_icq_settings", &self->ui_details->widget,
1175           "spinbutton_port", &spinbutton_port,
1176           NULL);
1177
1178       empathy_account_widget_handle_params (self,
1179           "entry_uin", "account",
1180           "entry_password", "password",
1181           "entry_server", "server",
1182           "spinbutton_port", "port",
1183           "entry_charset", "charset",
1184           NULL);
1185
1186       self->ui_details->default_focus = g_strdup ("entry_uin");
1187       self->ui_details->add_forget = TRUE;
1188     }
1189 }
1190
1191 static void
1192 account_widget_build_aim (EmpathyAccountWidget *self,
1193     const char *filename)
1194 {
1195   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1196   GtkWidget *spinbutton_port;
1197
1198   if (priv->simple)
1199     {
1200       self->ui_details->gui = empathy_builder_get_file (filename,
1201           "vbox_aim_simple", &self->ui_details->widget,
1202           NULL);
1203
1204       empathy_account_widget_handle_params (self,
1205           "entry_screenname_simple", "account",
1206           "entry_password_simple", "password",
1207           NULL);
1208
1209       self->ui_details->default_focus = g_strdup ("entry_screenname_simple");
1210     }
1211   else
1212     {
1213       self->ui_details->gui = empathy_builder_get_file (filename,
1214           "table_common_settings", &priv->table_common_settings,
1215           "vbox_aim_settings", &self->ui_details->widget,
1216           "spinbutton_port", &spinbutton_port,
1217           NULL);
1218
1219       empathy_account_widget_handle_params (self,
1220           "entry_screenname", "account",
1221           "entry_password", "password",
1222           "entry_server", "server",
1223           "spinbutton_port", "port",
1224           NULL);
1225
1226       self->ui_details->default_focus = g_strdup ("entry_screenname");
1227       self->ui_details->add_forget = TRUE;
1228     }
1229 }
1230
1231 static void
1232 account_widget_build_yahoo (EmpathyAccountWidget *self,
1233     const char *filename)
1234 {
1235   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1236
1237   if (priv->simple)
1238     {
1239       self->ui_details->gui = empathy_builder_get_file (filename,
1240           "vbox_yahoo_simple", &self->ui_details->widget,
1241           NULL);
1242
1243       empathy_account_widget_handle_params (self,
1244           "entry_id_simple", "account",
1245           "entry_password_simple", "password",
1246           NULL);
1247
1248       self->ui_details->default_focus = g_strdup ("entry_id_simple");
1249     }
1250   else
1251     {
1252       self->ui_details->gui = empathy_builder_get_file (filename,
1253           "table_common_settings", &priv->table_common_settings,
1254           "vbox_yahoo_settings", &self->ui_details->widget,
1255           NULL);
1256
1257       empathy_account_widget_handle_params (self,
1258           "entry_id", "account",
1259           "entry_password", "password",
1260           "entry_server", "server",
1261           "entry_locale", "room-list-locale",
1262           "entry_charset", "charset",
1263           "spinbutton_port", "port",
1264           "checkbutton_yahoojp", "yahoojp",
1265           "checkbutton_ignore_invites", "ignore-invites",
1266           NULL);
1267
1268       self->ui_details->default_focus = g_strdup ("entry_id");
1269       self->ui_details->add_forget = TRUE;
1270     }
1271 }
1272
1273 static void
1274 account_widget_build_groupwise (EmpathyAccountWidget *self,
1275     const char *filename)
1276 {
1277   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1278
1279   if (priv->simple)
1280     {
1281       self->ui_details->gui = empathy_builder_get_file (filename,
1282           "vbox_groupwise_simple", &self->ui_details->widget,
1283           NULL);
1284
1285       empathy_account_widget_handle_params (self,
1286           "entry_id_simple", "account",
1287           "entry_password_simple", "password",
1288           NULL);
1289
1290       self->ui_details->default_focus = g_strdup ("entry_id_simple");
1291     }
1292   else
1293     {
1294       self->ui_details->gui = empathy_builder_get_file (filename,
1295           "table_common_groupwise_settings", &priv->table_common_settings,
1296           "vbox_groupwise_settings", &self->ui_details->widget,
1297           NULL);
1298
1299       empathy_account_widget_handle_params (self,
1300           "entry_id", "account",
1301           "entry_password", "password",
1302           "entry_server", "server",
1303           "spinbutton_port", "port",
1304           NULL);
1305
1306       self->ui_details->default_focus = g_strdup ("entry_id");
1307       self->ui_details->add_forget = TRUE;
1308     }
1309 }
1310
1311 static void
1312 account_widget_destroy_cb (GtkWidget *widget,
1313     EmpathyAccountWidget *self)
1314 {
1315   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1316   /* set the destroyed flag - workaround */
1317   priv->destroyed = TRUE;
1318
1319   g_object_unref (self);
1320 }
1321
1322 static void
1323 empathy_account_widget_enabled_cb (TpAccount *account,
1324       GParamSpec *spec,
1325       gpointer user_data)
1326 {
1327   EmpathyAccountWidget *widget = EMPATHY_ACCOUNT_WIDGET (user_data);
1328   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
1329   gboolean enabled = tp_account_is_enabled (account);
1330
1331   if (priv->enabled_checkbox != NULL)
1332     {
1333 #ifdef HAVE_MOBLIN
1334       mx_gtk_light_switch_set_active (
1335           MX_GTK_LIGHT_SWITCH (priv->enabled_checkbox),
1336           enabled);
1337 #else
1338       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->enabled_checkbox),
1339           enabled);
1340 #endif /* HAVE_MOBLIN */
1341     }
1342 }
1343
1344 static void
1345 #ifdef HAVE_MOBLIN
1346 account_widget_switch_flipped_cb (MxGtkLightSwitch *sw,
1347     gboolean state,
1348     gpointer user_data)
1349 #else
1350 account_widget_enabled_released_cb (GtkToggleButton *toggle_button,
1351     gpointer user_data)
1352 #endif /* HAVE_MOBLIN */
1353 {
1354   EmpathyAccountWidgetPriv *priv = GET_PRIV (user_data);
1355   TpAccount *account;
1356 #ifndef HAVE_MOBLIN
1357   gboolean state;
1358
1359   state = gtk_toggle_button_get_active (toggle_button);
1360 #endif
1361
1362   account = empathy_account_settings_get_account (priv->settings);
1363
1364   /* Enable the account according to the value of the "Enabled" checkbox */
1365   /* workaround to keep widget alive during async call */
1366   g_object_ref (user_data);
1367   tp_account_set_enabled_async (account, state,
1368       account_widget_account_enabled_cb, user_data);
1369 }
1370
1371 static void
1372 do_set_property (GObject *object,
1373     guint prop_id,
1374     const GValue *value,
1375     GParamSpec *pspec)
1376 {
1377   EmpathyAccountWidgetPriv *priv = GET_PRIV (object);
1378
1379   switch (prop_id)
1380     {
1381     case PROP_SETTINGS:
1382       priv->settings = g_value_dup_object (value);
1383       break;
1384     case PROP_SIMPLE:
1385       priv->simple = g_value_get_boolean (value);
1386       break;
1387     case PROP_CREATING_ACCOUNT:
1388       priv->creating_account = g_value_get_boolean (value);
1389       break;
1390     default:
1391       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1392     }
1393 }
1394
1395 static void
1396 do_get_property (GObject *object,
1397     guint prop_id,
1398     GValue *value,
1399     GParamSpec *pspec)
1400 {
1401   EmpathyAccountWidgetPriv *priv = GET_PRIV (object);
1402
1403   switch (prop_id)
1404     {
1405     case PROP_PROTOCOL:
1406       g_value_set_string (value,
1407         empathy_account_settings_get_protocol (priv->settings));
1408       break;
1409     case PROP_SETTINGS:
1410       g_value_set_object (value, priv->settings);
1411       break;
1412     case PROP_SIMPLE:
1413       g_value_set_boolean (value, priv->simple);
1414       break;
1415     case PROP_CREATING_ACCOUNT:
1416       g_value_set_boolean (value, priv->creating_account);
1417       break;
1418     default:
1419       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1420     }
1421 }
1422
1423 static void
1424 presence_changed_cb (TpAccountManager *manager,
1425     TpConnectionPresenceType state,
1426     const gchar *status,
1427     const gchar *message,
1428     EmpathyAccountWidget *self)
1429 {
1430   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1431
1432   if (priv->destroyed)
1433     return;
1434
1435   if (priv->apply_button == NULL)
1436     /* This button doesn't exist in 'simple' mode */
1437     return;
1438
1439   if (state > TP_CONNECTION_PRESENCE_TYPE_OFFLINE)
1440     {
1441       /* We are online, display a Login button */
1442       GtkWidget *image;
1443
1444       gtk_button_set_use_stock (GTK_BUTTON (priv->apply_button), FALSE);
1445       gtk_button_set_label (GTK_BUTTON (priv->apply_button), _("L_og in"));
1446
1447       image = gtk_image_new_from_stock (GTK_STOCK_CONNECT,
1448           GTK_ICON_SIZE_BUTTON);
1449       gtk_button_set_image (GTK_BUTTON (priv->apply_button), image);
1450     }
1451   else
1452     {
1453       /* We are offline, display a Save button */
1454       gtk_button_set_image (GTK_BUTTON (priv->apply_button), NULL);
1455       gtk_button_set_use_stock (GTK_BUTTON (priv->apply_button), TRUE);
1456       gtk_button_set_label (GTK_BUTTON (priv->apply_button), GTK_STOCK_SAVE);
1457     }
1458 }
1459
1460 static void
1461 account_manager_ready_cb (GObject *source_object,
1462     GAsyncResult *result,
1463     gpointer user_data)
1464 {
1465   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (user_data);
1466   TpAccountManager *account_manager = TP_ACCOUNT_MANAGER (source_object);
1467   GError *error = NULL;
1468   TpConnectionPresenceType state;
1469
1470   if (!tp_account_manager_prepare_finish (account_manager, result, &error))
1471     {
1472       DEBUG ("Failed to prepare account manager: %s", error->message);
1473       g_error_free (error);
1474       goto out;
1475     }
1476
1477   state = tp_account_manager_get_most_available_presence (account_manager, NULL,
1478       NULL);
1479
1480   /* simulate a presence change so the apply button will be changed
1481    * if needed */
1482   presence_changed_cb (account_manager, state, NULL, NULL, self);
1483
1484 out:
1485   g_object_unref (self);
1486 }
1487
1488 #define WIDGET(cm, proto) \
1489   { #cm, #proto, "empathy-account-widget-"#proto".ui", \
1490     account_widget_build_##proto }
1491
1492 static void
1493 add_enable_checkbox (EmpathyAccountWidget *self,
1494     TpAccount *account)
1495 {
1496   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1497 #ifdef HAVE_MOBLIN
1498   GtkWidget *w;
1499 #else
1500   GtkWidget *vbox = self->ui_details->widget;
1501 #endif
1502   guint nb_rows, nb_columns;
1503   gboolean is_enabled;
1504
1505   /* handle the "Enabled" checkbox. We only add it when modifying an account */
1506   if (priv->creating_account || priv->table_common_settings == NULL)
1507     return;
1508
1509   is_enabled = tp_account_is_enabled (account);
1510
1511 #ifdef HAVE_MOBLIN
1512   w = gtk_label_new (_("Account:"));
1513   gtk_misc_set_alignment (GTK_MISC (w), 0, 0.5);
1514
1515   priv->enabled_checkbox = mx_gtk_light_switch_new ();
1516
1517   mx_gtk_light_switch_set_active (
1518       MX_GTK_LIGHT_SWITCH (priv->enabled_checkbox), is_enabled);
1519
1520   gtk_widget_show (w);
1521 #else
1522   priv->enabled_checkbox =
1523       gtk_check_button_new_with_label (_("Enabled"));
1524
1525   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->enabled_checkbox),
1526       is_enabled);
1527 #endif /* HAVE_MOBLIN */
1528
1529   g_object_get (priv->table_common_settings, "n-rows", &nb_rows,
1530       "n-columns", &nb_columns, NULL);
1531
1532   gtk_table_resize (GTK_TABLE (priv->table_common_settings), ++nb_rows,
1533       nb_columns);
1534
1535 #ifdef HAVE_MOBLIN
1536   gtk_table_attach (GTK_TABLE (priv->table_common_settings),
1537       w,
1538       0, 1, nb_rows - 1, nb_rows,
1539       GTK_FILL, 0, 0, 0);
1540   gtk_table_attach (GTK_TABLE (priv->table_common_settings),
1541       priv->enabled_checkbox,
1542       1, nb_columns, nb_rows - 1, nb_rows,
1543       GTK_EXPAND | GTK_FILL, 0, 0, 0);
1544 #else
1545   gtk_box_pack_start (GTK_BOX (vbox), priv->enabled_checkbox, FALSE, FALSE, 0);
1546   gtk_box_reorder_child (GTK_BOX (vbox), priv->enabled_checkbox, 0);
1547 #endif /* HAVE_MOBLIN */
1548
1549   gtk_widget_show (priv->enabled_checkbox);
1550
1551 #ifdef HAVE_MOBLIN
1552   g_signal_connect (G_OBJECT (priv->enabled_checkbox), "switch-flipped",
1553       G_CALLBACK (account_widget_switch_flipped_cb), self);
1554 #else
1555   g_signal_connect (G_OBJECT (priv->enabled_checkbox), "released",
1556       G_CALLBACK (account_widget_enabled_released_cb), self);
1557 #endif /* HAVE_MOBLIN */
1558 }
1559
1560 #ifndef HAVE_MOBLIN
1561 /* Moblin doesn't support registration */
1562 static void
1563 add_register_buttons (EmpathyAccountWidget *self,
1564     TpAccount *account)
1565 {
1566   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1567   const TpConnectionManagerProtocol *protocol;
1568   GtkWidget *radiobutton_register;
1569   GtkWidget *vbox = self->ui_details->widget;
1570
1571   if (!priv->creating_account)
1572     return;
1573
1574   protocol = empathy_account_settings_get_tp_protocol (priv->settings);
1575   if (protocol == NULL)
1576     return;
1577
1578   if (!tp_connection_manager_protocol_can_register (protocol))
1579     return;
1580
1581   if (account_widget_is_gtalk (self) || account_widget_is_facebook (self))
1582     return;
1583
1584   if (priv->simple)
1585     return;
1586
1587   priv->radiobutton_reuse = gtk_radio_button_new_with_label (NULL,
1588       _("This account already exists on the server"));
1589   radiobutton_register = gtk_radio_button_new_with_label (
1590       gtk_radio_button_get_group (GTK_RADIO_BUTTON (priv->radiobutton_reuse)),
1591       _("Create a new account on the server"));
1592
1593   gtk_box_pack_start (GTK_BOX (vbox), priv->radiobutton_reuse, FALSE, FALSE, 0);
1594   gtk_box_pack_start (GTK_BOX (vbox), radiobutton_register, FALSE, FALSE, 0);
1595   gtk_box_reorder_child (GTK_BOX (vbox), priv->radiobutton_reuse, 0);
1596   gtk_box_reorder_child (GTK_BOX (vbox), radiobutton_register, 1);
1597   gtk_widget_show (priv->radiobutton_reuse);
1598   gtk_widget_show (radiobutton_register);
1599 }
1600 #endif
1601
1602 static void
1603 do_constructed (GObject *obj)
1604 {
1605   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
1606   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1607   TpAccount *account;
1608   const gchar *protocol, *cm_name;
1609   guint i = 0;
1610   struct {
1611     const gchar *cm_name;
1612     const gchar *protocol;
1613     const char *file;
1614     void (*func)(EmpathyAccountWidget *self, const gchar *filename);
1615   } widgets [] = {
1616     { "salut", "local-xmpp", "empathy-account-widget-local-xmpp.ui",
1617         account_widget_build_salut },
1618     WIDGET (gabble, jabber),
1619     WIDGET (butterfly, msn),
1620     WIDGET (haze, icq),
1621     WIDGET (haze, aim),
1622     WIDGET (haze, yahoo),
1623     WIDGET (haze, groupwise),
1624     WIDGET (idle, irc),
1625     WIDGET (sofiasip, sip),
1626   };
1627
1628   cm_name = empathy_account_settings_get_cm (priv->settings);
1629   protocol = empathy_account_settings_get_protocol (priv->settings);
1630
1631   for (i = 0 ; i < G_N_ELEMENTS (widgets); i++)
1632     {
1633       if (!tp_strdiff (widgets[i].cm_name, cm_name) &&
1634           !tp_strdiff (widgets[i].protocol, protocol))
1635         {
1636           gchar *filename;
1637
1638           filename = empathy_file_lookup (widgets[i].file,
1639               "libempathy-gtk");
1640           widgets[i].func (self, filename);
1641           g_free (filename);
1642
1643           break;
1644         }
1645     }
1646
1647   if (i == G_N_ELEMENTS (widgets))
1648     {
1649       gchar *filename = empathy_file_lookup (
1650           "empathy-account-widget-generic.ui", "libempathy-gtk");
1651       account_widget_build_generic (self, filename);
1652       g_free (filename);
1653     }
1654
1655   /* handle default focus */
1656   if (self->ui_details->default_focus != NULL)
1657     {
1658       GObject *default_focus_entry;
1659
1660       default_focus_entry = gtk_builder_get_object
1661         (self->ui_details->gui, self->ui_details->default_focus);
1662       g_signal_connect (default_focus_entry, "realize",
1663           G_CALLBACK (gtk_widget_grab_focus),
1664           NULL);
1665     }
1666
1667   /* handle forget button */
1668   if (self->ui_details->add_forget)
1669     {
1670       const gchar *password = NULL;
1671
1672       priv->button_forget = GTK_WIDGET (gtk_builder_get_object
1673           (self->ui_details->gui, "button_forget"));
1674       priv->entry_password = GTK_WIDGET (gtk_builder_get_object
1675           (self->ui_details->gui, "entry_password"));
1676
1677       password = empathy_account_settings_get_string (priv->settings,
1678           "password");
1679       gtk_widget_set_sensitive (priv->button_forget,
1680           !EMP_STR_EMPTY (password));
1681
1682       g_signal_connect (priv->button_forget, "clicked",
1683           G_CALLBACK (account_widget_forget_clicked_cb),
1684           self);
1685       g_signal_connect (priv->entry_password, "changed",
1686           G_CALLBACK (account_widget_password_changed_cb),
1687           self);
1688     }
1689
1690   /* dup and init the account-manager */
1691   priv->account_manager = tp_account_manager_dup ();
1692
1693   g_object_ref (self);
1694   tp_account_manager_prepare_async (priv->account_manager, NULL,
1695       account_manager_ready_cb, self);
1696
1697   /* handle apply and cancel button */
1698   if (!priv->simple)
1699     {
1700       GtkWidget *hbox = gtk_hbox_new (TRUE, 3);
1701
1702       priv->cancel_button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
1703
1704       if (priv->creating_account)
1705         {
1706           /* Assumre we are offline, display a Save button. We'll update
1707            * it once the account manager is ready if needed */
1708           priv->apply_button = gtk_button_new_from_stock (GTK_STOCK_SAVE);
1709
1710           empathy_signal_connect_weak (priv->account_manager,
1711               "most-available-presence-changed",
1712               G_CALLBACK (presence_changed_cb), obj);
1713         }
1714       else
1715         {
1716           /* We are editing an existing account, display an Apply button */
1717           priv->apply_button = gtk_button_new_from_stock (GTK_STOCK_APPLY);
1718         }
1719
1720       gtk_box_pack_end (GTK_BOX (hbox), priv->apply_button, TRUE,
1721           TRUE, 3);
1722       gtk_box_pack_end (GTK_BOX (hbox), priv->cancel_button, TRUE,
1723           TRUE, 3);
1724
1725       gtk_box_pack_end (GTK_BOX (self->ui_details->widget), hbox, FALSE,
1726           FALSE, 3);
1727
1728       g_signal_connect (priv->cancel_button, "clicked",
1729           G_CALLBACK (account_widget_cancel_clicked_cb),
1730           self);
1731       g_signal_connect (priv->apply_button, "clicked",
1732           G_CALLBACK (account_widget_apply_clicked_cb),
1733           self);
1734       gtk_widget_show_all (hbox);
1735
1736       if (priv->creating_account)
1737         /* When creating an account, the user might have nothing to enter.
1738          * That means that no control interaction might occur,
1739          * so we update the control button sensitivity manually.
1740          */
1741         account_widget_handle_control_buttons_sensitivity (self);
1742       else
1743         account_widget_set_control_buttons_sensitivity (self, FALSE);
1744     }
1745
1746   account = empathy_account_settings_get_account (priv->settings);
1747
1748   if (account != NULL)
1749     {
1750       g_signal_connect (account, "notify::enabled",
1751           G_CALLBACK (empathy_account_widget_enabled_cb), self);
1752     }
1753
1754 #ifndef HAVE_MOBLIN
1755   add_register_buttons (self, account);
1756 #endif
1757   add_enable_checkbox (self, account);
1758
1759   /* hook up to widget destruction to unref ourselves */
1760   g_signal_connect (self->ui_details->widget, "destroy",
1761       G_CALLBACK (account_widget_destroy_cb), self);
1762
1763   empathy_builder_unref_and_keep_widget (self->ui_details->gui,
1764       self->ui_details->widget);
1765   self->ui_details->gui = NULL;
1766 }
1767
1768 static void
1769 do_dispose (GObject *obj)
1770 {
1771   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
1772   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1773
1774   if (priv->dispose_run)
1775     return;
1776
1777   priv->dispose_run = TRUE;
1778
1779   empathy_account_settings_is_ready (priv->settings);
1780
1781   if (priv->settings != NULL)
1782     {
1783       TpAccount *account;
1784       account = empathy_account_settings_get_account (priv->settings);
1785
1786       if (account != NULL)
1787         {
1788           g_signal_handlers_disconnect_by_func (account,
1789               empathy_account_widget_enabled_cb, self);
1790         }
1791
1792       g_object_unref (priv->settings);
1793       priv->settings = NULL;
1794     }
1795
1796   if (priv->account_manager != NULL)
1797     {
1798       g_object_unref (priv->account_manager);
1799       priv->account_manager = NULL;
1800     }
1801
1802   if (G_OBJECT_CLASS (empathy_account_widget_parent_class)->dispose != NULL)
1803     G_OBJECT_CLASS (empathy_account_widget_parent_class)->dispose (obj);
1804 }
1805
1806 static void
1807 do_finalize (GObject *obj)
1808 {
1809   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
1810
1811   g_free (self->ui_details->default_focus);
1812   g_slice_free (EmpathyAccountWidgetUIDetails, self->ui_details);
1813
1814   if (G_OBJECT_CLASS (empathy_account_widget_parent_class)->finalize != NULL)
1815     G_OBJECT_CLASS (empathy_account_widget_parent_class)->finalize (obj);
1816 }
1817
1818 static void
1819 empathy_account_widget_class_init (EmpathyAccountWidgetClass *klass)
1820 {
1821   GObjectClass *oclass = G_OBJECT_CLASS (klass);
1822   GParamSpec *param_spec;
1823
1824   oclass->get_property = do_get_property;
1825   oclass->set_property = do_set_property;
1826   oclass->constructed = do_constructed;
1827   oclass->dispose = do_dispose;
1828   oclass->finalize = do_finalize;
1829
1830   param_spec = g_param_spec_string ("protocol",
1831       "protocol", "The protocol of the account",
1832       NULL,
1833       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
1834   g_object_class_install_property (oclass, PROP_PROTOCOL, param_spec);
1835
1836   param_spec = g_param_spec_object ("settings",
1837       "settings", "The settings of the account",
1838       EMPATHY_TYPE_ACCOUNT_SETTINGS,
1839       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
1840   g_object_class_install_property (oclass, PROP_SETTINGS, param_spec);
1841
1842   param_spec = g_param_spec_boolean ("simple",
1843       "simple", "Whether the account widget is a simple or an advanced one",
1844       FALSE,
1845       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
1846   g_object_class_install_property (oclass, PROP_SIMPLE, param_spec);
1847
1848   param_spec = g_param_spec_boolean ("creating-account",
1849       "creating-account",
1850       "TRUE if we're creating an account, FALSE if we're modifying it",
1851       FALSE,
1852       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
1853   g_object_class_install_property (oclass, PROP_CREATING_ACCOUNT, param_spec);
1854
1855   signals[HANDLE_APPLY] =
1856     g_signal_new ("handle-apply", G_TYPE_FROM_CLASS (klass),
1857         G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1858         g_cclosure_marshal_VOID__BOOLEAN,
1859         G_TYPE_NONE,
1860         1, G_TYPE_BOOLEAN);
1861
1862   /* This signal is emitted when an account has been created and enabled. */
1863   signals[ACCOUNT_CREATED] =
1864       g_signal_new ("account-created", G_TYPE_FROM_CLASS (klass),
1865           G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1866           g_cclosure_marshal_VOID__POINTER,
1867           G_TYPE_NONE,
1868           1, G_TYPE_OBJECT);
1869
1870   signals[CANCELLED] =
1871       g_signal_new ("cancelled", G_TYPE_FROM_CLASS (klass),
1872           G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1873           g_cclosure_marshal_VOID__VOID,
1874           G_TYPE_NONE,
1875           0);
1876
1877   g_type_class_add_private (klass, sizeof (EmpathyAccountWidgetPriv));
1878 }
1879
1880 static void
1881 empathy_account_widget_init (EmpathyAccountWidget *self)
1882 {
1883   EmpathyAccountWidgetPriv *priv =
1884     G_TYPE_INSTANCE_GET_PRIVATE ((self), EMPATHY_TYPE_ACCOUNT_WIDGET,
1885         EmpathyAccountWidgetPriv);
1886
1887   self->priv = priv;
1888   priv->dispose_run = FALSE;
1889
1890   self->ui_details = g_slice_new0 (EmpathyAccountWidgetUIDetails);
1891 }
1892
1893 /* public methods */
1894
1895 void
1896 empathy_account_widget_discard_pending_changes
1897     (EmpathyAccountWidget *widget)
1898 {
1899   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
1900
1901   empathy_account_settings_discard_changes (priv->settings);
1902   priv->contains_pending_changes = FALSE;
1903 }
1904
1905 gboolean
1906 empathy_account_widget_contains_pending_changes (EmpathyAccountWidget *widget)
1907 {
1908   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
1909
1910   return priv->contains_pending_changes;
1911 }
1912
1913 void
1914 empathy_account_widget_handle_params (EmpathyAccountWidget *self,
1915     const gchar *first_widget,
1916     ...)
1917 {
1918   va_list args;
1919
1920   va_start (args, first_widget);
1921   account_widget_handle_params_valist (self, first_widget, args);
1922   va_end (args);
1923 }
1924
1925 GtkWidget *
1926 empathy_account_widget_get_widget (EmpathyAccountWidget *widget)
1927 {
1928   return widget->ui_details->widget;
1929 }
1930
1931 EmpathyAccountWidget *
1932 empathy_account_widget_new_for_protocol (EmpathyAccountSettings *settings,
1933     gboolean simple)
1934 {
1935   EmpathyAccountWidget *self;
1936
1937   g_return_val_if_fail (EMPATHY_IS_ACCOUNT_SETTINGS (settings), NULL);
1938
1939   self = g_object_new
1940     (EMPATHY_TYPE_ACCOUNT_WIDGET,
1941         "settings", settings, "simple", simple,
1942         "creating-account",
1943         empathy_account_settings_get_account (settings) == NULL,
1944         NULL);
1945
1946   return self;
1947 }
1948
1949 gchar *
1950 empathy_account_widget_get_default_display_name (EmpathyAccountWidget *self)
1951 {
1952   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1953   const gchar *login_id;
1954   const gchar *protocol, *p;
1955   gchar *default_display_name;
1956
1957   login_id = empathy_account_settings_get_string (priv->settings, "account");
1958   protocol = empathy_account_settings_get_protocol (priv->settings);
1959
1960   if (login_id != NULL)
1961     {
1962       /* TODO: this should be done in empathy-account-widget-irc */
1963       if (!tp_strdiff (protocol, "irc"))
1964         {
1965           const gchar* server;
1966           server = empathy_account_settings_get_string (priv->settings,
1967               "server");
1968
1969           /* To translators: The first parameter is the login id and the
1970            * second one is the server. The resulting string will be something
1971            * like: "MyUserName on chat.freenode.net".
1972            * You should reverse the order of these arguments if the
1973            * server should come before the login id in your locale.*/
1974           default_display_name = g_strdup_printf (_("%1$s on %2$s"),
1975               login_id, server);
1976         }
1977       else if (account_widget_is_facebook (self))
1978         {
1979           gchar *tmp;
1980
1981           tmp = remove_facebook_suffix (login_id);
1982           default_display_name = g_strdup_printf ("Facebook (%s)", tmp);
1983           g_free (tmp);
1984         }
1985       else
1986         {
1987           default_display_name = g_strdup (login_id);
1988         }
1989
1990       return default_display_name;
1991     }
1992
1993   if ((p = empathy_protocol_name_to_display_name (protocol)) != NULL)
1994     protocol = p;
1995
1996   if (protocol != NULL)
1997     {
1998       /* To translators: The parameter is the protocol name. The resulting
1999        * string will be something like: "Jabber Account" */
2000       default_display_name = g_strdup_printf (_("%s Account"), protocol);
2001     }
2002   else
2003     {
2004       default_display_name = g_strdup (_("New account"));
2005     }
2006
2007   return default_display_name;
2008 }
2009
2010 /* Used by subclass to indicate that widget contains pending changes */
2011 void
2012 empathy_account_widget_changed (EmpathyAccountWidget *self)
2013 {
2014   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
2015
2016   account_widget_handle_control_buttons_sensitivity (self);
2017   priv->contains_pending_changes = TRUE;
2018 }
2019
2020 void
2021 empathy_account_widget_set_account_param (EmpathyAccountWidget *self,
2022     const gchar *account)
2023 {
2024   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
2025
2026   if (priv->param_account_widget == NULL)
2027     return;
2028
2029   gtk_entry_set_text (GTK_ENTRY (priv->param_account_widget), account);
2030 }
2031
2032 void
2033 empathy_account_widget_set_password_param (EmpathyAccountWidget *self,
2034     const gchar *account)
2035 {
2036   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
2037
2038   if (priv->param_password_widget == NULL)
2039     return;
2040
2041   gtk_entry_set_text (GTK_ENTRY (priv->param_password_widget), account);
2042 }