]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-account-widget.c
hide the advanced options for Facebook accounts
[empathy.git] / libempathy-gtk / empathy-account-widget.c
1 /*
2  * Copyright (C) 2006-2007 Imendio AB
3  * Copyright (C) 2007-2009 Collabora Ltd.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA  02110-1301  USA
19  *
20  * Authors: Xavier Claessens <xclaesse@gmail.com>
21  *          Martyn Russell <martyn@imendio.com>
22  *          Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
23  *          Jonathan Tellier <jonathan.tellier@gmail.com>
24  */
25
26 #include <config.h>
27
28 #include <string.h>
29
30 #include <gtk/gtk.h>
31 #include <glib/gi18n-lib.h>
32
33 #ifdef HAVE_MOBLIN
34 #include <nbtk/nbtk-gtk.h>
35 #endif
36
37 #include <libempathy/empathy-utils.h>
38
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             nbtk_gtk_light_switch_get_active (
750                 NBTK_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 static void
953 account_widget_build_jabber (EmpathyAccountWidget *self,
954     const char *filename)
955 {
956   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
957   GtkWidget *spinbutton_port;
958   GtkWidget *checkbutton_ssl;
959   GtkWidget *label_id, *label_password;
960   GtkWidget *label_id_create, *label_password_create;
961   GtkWidget *label_example_gtalk, *label_example_jabber, *label_example_fb;
962   gboolean is_gtalk, is_facebook;
963   GtkWidget *expander_advanced;
964
965   is_gtalk = account_widget_is_gtalk (self);
966   is_facebook = account_widget_is_facebook (self);
967
968   if (priv->simple && !is_gtalk && !is_facebook)
969     {
970       /* Simple widget for XMPP */
971       self->ui_details->gui = empathy_builder_get_file (filename,
972           "vbox_jabber_simple", &self->ui_details->widget,
973           "label_id_simple", &label_id,
974           "label_id_create", &label_id_create,
975           "label_password_simple", &label_password,
976           "label_password_create", &label_password_create,
977           NULL);
978
979       if (empathy_account_settings_get_boolean (priv->settings, "register"))
980         {
981           gtk_widget_hide (label_id);
982           gtk_widget_hide (label_password);
983           gtk_widget_show (label_id_create);
984           gtk_widget_show (label_password_create);
985         }
986
987       empathy_account_widget_handle_params (self,
988           "entry_id_simple", "account",
989           "entry_password_simple", "password",
990           NULL);
991
992       self->ui_details->default_focus = g_strdup ("entry_id_simple");
993     }
994   else if (priv->simple && is_gtalk)
995     {
996       /* Simple widget for Google Talk */
997       self->ui_details->gui = empathy_builder_get_file (filename,
998           "vbox_gtalk_simple", &self->ui_details->widget,
999           NULL);
1000
1001       empathy_account_widget_handle_params (self,
1002           "entry_id_g_simple", "account",
1003           "entry_password_g_simple", "password",
1004           NULL);
1005
1006       self->ui_details->default_focus = g_strdup ("entry_id_g_simple");
1007     }
1008   /* TODO: Simple widget for Facebook */
1009   else
1010     {
1011       /* Full widget for XMPP, Google Talk and Facebook*/
1012       self->ui_details->gui = empathy_builder_get_file (filename,
1013           "table_common_settings", &priv->table_common_settings,
1014           "vbox_jabber_settings", &self->ui_details->widget,
1015           "spinbutton_port", &spinbutton_port,
1016           "checkbutton_ssl", &checkbutton_ssl,
1017           "label_username_example", &label_example_jabber,
1018           "label_username_g_example", &label_example_gtalk,
1019           "label_username_f_example", &label_example_fb,
1020           "expander_advanced", &expander_advanced,
1021           NULL);
1022
1023       empathy_account_widget_handle_params (self,
1024           "entry_id", "account",
1025           "entry_password", "password",
1026           "entry_resource", "resource",
1027           "entry_server", "server",
1028           "spinbutton_port", "port",
1029           "spinbutton_priority", "priority",
1030           "checkbutton_ssl", "old-ssl",
1031           "checkbutton_ignore_ssl_errors", "ignore-ssl-errors",
1032           "checkbutton_encryption", "require-encryption",
1033           NULL);
1034
1035       self->ui_details->default_focus = g_strdup ("entry_id");
1036       self->ui_details->add_forget = TRUE;
1037       priv->spinbutton_port = spinbutton_port;
1038
1039       g_signal_connect (checkbutton_ssl, "toggled",
1040           G_CALLBACK (account_widget_jabber_ssl_toggled_cb),
1041           self);
1042
1043       if (is_gtalk)
1044         {
1045           gtk_widget_hide (label_example_jabber);
1046           gtk_widget_show (label_example_gtalk);
1047         }
1048       else if (is_facebook)
1049         {
1050           gtk_widget_hide (label_example_jabber);
1051           gtk_widget_show (label_example_fb);
1052           gtk_widget_hide (expander_advanced);
1053         }
1054     }
1055 }
1056
1057 static void
1058 account_widget_build_icq (EmpathyAccountWidget *self,
1059     const char *filename)
1060 {
1061   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1062   GtkWidget *spinbutton_port;
1063
1064   if (priv->simple)
1065     {
1066       self->ui_details->gui = empathy_builder_get_file (filename,
1067           "vbox_icq_simple", &self->ui_details->widget,
1068           NULL);
1069
1070       empathy_account_widget_handle_params (self,
1071           "entry_uin_simple", "account",
1072           "entry_password_simple", "password",
1073           NULL);
1074
1075       self->ui_details->default_focus = g_strdup ("entry_uin_simple");
1076     }
1077   else
1078     {
1079       self->ui_details->gui = empathy_builder_get_file (filename,
1080           "table_common_settings", &priv->table_common_settings,
1081           "vbox_icq_settings", &self->ui_details->widget,
1082           "spinbutton_port", &spinbutton_port,
1083           NULL);
1084
1085       empathy_account_widget_handle_params (self,
1086           "entry_uin", "account",
1087           "entry_password", "password",
1088           "entry_server", "server",
1089           "spinbutton_port", "port",
1090           "entry_charset", "charset",
1091           NULL);
1092
1093       self->ui_details->default_focus = g_strdup ("entry_uin");
1094       self->ui_details->add_forget = TRUE;
1095     }
1096 }
1097
1098 static void
1099 account_widget_build_aim (EmpathyAccountWidget *self,
1100     const char *filename)
1101 {
1102   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1103   GtkWidget *spinbutton_port;
1104
1105   if (priv->simple)
1106     {
1107       self->ui_details->gui = empathy_builder_get_file (filename,
1108           "vbox_aim_simple", &self->ui_details->widget,
1109           NULL);
1110
1111       empathy_account_widget_handle_params (self,
1112           "entry_screenname_simple", "account",
1113           "entry_password_simple", "password",
1114           NULL);
1115
1116       self->ui_details->default_focus = g_strdup ("entry_screenname_simple");
1117     }
1118   else
1119     {
1120       self->ui_details->gui = empathy_builder_get_file (filename,
1121           "table_common_settings", &priv->table_common_settings,
1122           "vbox_aim_settings", &self->ui_details->widget,
1123           "spinbutton_port", &spinbutton_port,
1124           NULL);
1125
1126       empathy_account_widget_handle_params (self,
1127           "entry_screenname", "account",
1128           "entry_password", "password",
1129           "entry_server", "server",
1130           "spinbutton_port", "port",
1131           NULL);
1132
1133       self->ui_details->default_focus = g_strdup ("entry_screenname");
1134       self->ui_details->add_forget = TRUE;
1135     }
1136 }
1137
1138 static void
1139 account_widget_build_yahoo (EmpathyAccountWidget *self,
1140     const char *filename)
1141 {
1142   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1143
1144   if (priv->simple)
1145     {
1146       self->ui_details->gui = empathy_builder_get_file (filename,
1147           "vbox_yahoo_simple", &self->ui_details->widget,
1148           NULL);
1149
1150       empathy_account_widget_handle_params (self,
1151           "entry_id_simple", "account",
1152           "entry_password_simple", "password",
1153           NULL);
1154
1155       self->ui_details->default_focus = g_strdup ("entry_id_simple");
1156     }
1157   else
1158     {
1159       self->ui_details->gui = empathy_builder_get_file (filename,
1160           "table_common_settings", &priv->table_common_settings,
1161           "vbox_yahoo_settings", &self->ui_details->widget,
1162           NULL);
1163
1164       empathy_account_widget_handle_params (self,
1165           "entry_id", "account",
1166           "entry_password", "password",
1167           "entry_server", "server",
1168           "entry_locale", "room-list-locale",
1169           "entry_charset", "charset",
1170           "spinbutton_port", "port",
1171           "checkbutton_yahoojp", "yahoojp",
1172           "checkbutton_ignore_invites", "ignore-invites",
1173           NULL);
1174
1175       self->ui_details->default_focus = g_strdup ("entry_id");
1176       self->ui_details->add_forget = TRUE;
1177     }
1178 }
1179
1180 static void
1181 account_widget_build_groupwise (EmpathyAccountWidget *self,
1182     const char *filename)
1183 {
1184   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1185
1186   if (priv->simple)
1187     {
1188       self->ui_details->gui = empathy_builder_get_file (filename,
1189           "vbox_groupwise_simple", &self->ui_details->widget,
1190           NULL);
1191
1192       empathy_account_widget_handle_params (self,
1193           "entry_id_simple", "account",
1194           "entry_password_simple", "password",
1195           NULL);
1196
1197       self->ui_details->default_focus = g_strdup ("entry_id_simple");
1198     }
1199   else
1200     {
1201       self->ui_details->gui = empathy_builder_get_file (filename,
1202           "table_common_groupwise_settings", &priv->table_common_settings,
1203           "vbox_groupwise_settings", &self->ui_details->widget,
1204           NULL);
1205
1206       empathy_account_widget_handle_params (self,
1207           "entry_id", "account",
1208           "entry_password", "password",
1209           "entry_server", "server",
1210           "spinbutton_port", "port",
1211           NULL);
1212
1213       self->ui_details->default_focus = g_strdup ("entry_id");
1214       self->ui_details->add_forget = TRUE;
1215     }
1216 }
1217
1218 static void
1219 account_widget_destroy_cb (GtkWidget *widget,
1220     EmpathyAccountWidget *self)
1221 {
1222   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1223   /* set the destroyed flag - workaround */
1224   priv->destroyed = TRUE;
1225
1226   g_object_unref (self);
1227 }
1228
1229 static void
1230 empathy_account_widget_enabled_cb (TpAccount *account,
1231       GParamSpec *spec,
1232       gpointer user_data)
1233 {
1234   EmpathyAccountWidget *widget = EMPATHY_ACCOUNT_WIDGET (user_data);
1235   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
1236   gboolean enabled = tp_account_is_enabled (account);
1237
1238   if (priv->enabled_checkbox != NULL)
1239     {
1240 #ifdef HAVE_MOBLIN
1241       nbtk_gtk_light_switch_set_active (
1242           NBTK_GTK_LIGHT_SWITCH (priv->enabled_checkbox),
1243           enabled);
1244 #else
1245       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->enabled_checkbox),
1246           enabled);
1247 #endif /* HAVE_MOBLIN */
1248     }
1249 }
1250
1251 static void
1252 #ifdef HAVE_MOBLIN
1253 account_widget_switch_flipped_cb (NbtkGtkLightSwitch *sw,
1254     gboolean state,
1255     gpointer user_data)
1256 #else
1257 account_widget_enabled_released_cb (GtkToggleButton *toggle_button,
1258     gpointer user_data)
1259 #endif /* HAVE_MOBLIN */
1260 {
1261   EmpathyAccountWidgetPriv *priv = GET_PRIV (user_data);
1262   TpAccount *account;
1263 #ifndef HAVE_MOBLIN
1264   gboolean state;
1265
1266   state = gtk_toggle_button_get_active (toggle_button);
1267 #endif
1268
1269   account = empathy_account_settings_get_account (priv->settings);
1270
1271   /* Enable the account according to the value of the "Enabled" checkbox */
1272   /* workaround to keep widget alive during async call */
1273   g_object_ref (user_data);
1274   tp_account_set_enabled_async (account, state,
1275       account_widget_account_enabled_cb, user_data);
1276 }
1277
1278 static void
1279 do_set_property (GObject *object,
1280     guint prop_id,
1281     const GValue *value,
1282     GParamSpec *pspec)
1283 {
1284   EmpathyAccountWidgetPriv *priv = GET_PRIV (object);
1285
1286   switch (prop_id)
1287     {
1288     case PROP_SETTINGS:
1289       priv->settings = g_value_dup_object (value);
1290       break;
1291     case PROP_SIMPLE:
1292       priv->simple = g_value_get_boolean (value);
1293       break;
1294     case PROP_CREATING_ACCOUNT:
1295       priv->creating_account = g_value_get_boolean (value);
1296       break;
1297     default:
1298       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1299     }
1300 }
1301
1302 static void
1303 do_get_property (GObject *object,
1304     guint prop_id,
1305     GValue *value,
1306     GParamSpec *pspec)
1307 {
1308   EmpathyAccountWidgetPriv *priv = GET_PRIV (object);
1309
1310   switch (prop_id)
1311     {
1312     case PROP_PROTOCOL:
1313       g_value_set_string (value,
1314         empathy_account_settings_get_protocol (priv->settings));
1315       break;
1316     case PROP_SETTINGS:
1317       g_value_set_object (value, priv->settings);
1318       break;
1319     case PROP_SIMPLE:
1320       g_value_set_boolean (value, priv->simple);
1321       break;
1322     case PROP_CREATING_ACCOUNT:
1323       g_value_set_boolean (value, priv->creating_account);
1324       break;
1325     default:
1326       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1327     }
1328 }
1329
1330 static void
1331 presence_changed_cb (TpAccountManager *manager,
1332     TpConnectionPresenceType state,
1333     const gchar *status,
1334     const gchar *message,
1335     EmpathyAccountWidget *self)
1336 {
1337   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1338
1339   if (priv->destroyed)
1340     return;
1341
1342   if (priv->apply_button == NULL)
1343     /* This button doesn't exist in 'simple' mode */
1344     return;
1345
1346   if (state > TP_CONNECTION_PRESENCE_TYPE_OFFLINE)
1347     {
1348       /* We are online, display a Login button */
1349       GtkWidget *image;
1350
1351       gtk_button_set_use_stock (GTK_BUTTON (priv->apply_button), FALSE);
1352       gtk_button_set_label (GTK_BUTTON (priv->apply_button), _("L_og in"));
1353
1354       image = gtk_image_new_from_stock (GTK_STOCK_CONNECT,
1355           GTK_ICON_SIZE_BUTTON);
1356       gtk_button_set_image (GTK_BUTTON (priv->apply_button), image);
1357     }
1358   else
1359     {
1360       /* We are offline, display a Save button */
1361       gtk_button_set_image (GTK_BUTTON (priv->apply_button), NULL);
1362       gtk_button_set_use_stock (GTK_BUTTON (priv->apply_button), TRUE);
1363       gtk_button_set_label (GTK_BUTTON (priv->apply_button), GTK_STOCK_SAVE);
1364     }
1365 }
1366
1367 static void
1368 account_manager_ready_cb (GObject *source_object,
1369     GAsyncResult *result,
1370     gpointer user_data)
1371 {
1372   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (user_data);
1373   TpAccountManager *account_manager = TP_ACCOUNT_MANAGER (source_object);
1374   GError *error = NULL;
1375   TpConnectionPresenceType state;
1376
1377   if (!tp_account_manager_prepare_finish (account_manager, result, &error))
1378     {
1379       DEBUG ("Failed to prepare account manager: %s", error->message);
1380       g_error_free (error);
1381       goto out;
1382     }
1383
1384   state = tp_account_manager_get_most_available_presence (account_manager, NULL,
1385       NULL);
1386
1387   /* simulate a presence change so the apply button will be changed
1388    * if needed */
1389   presence_changed_cb (account_manager, state, NULL, NULL, self);
1390
1391 out:
1392   g_object_unref (self);
1393 }
1394
1395 #define WIDGET(cm, proto) \
1396   { #cm, #proto, "empathy-account-widget-"#proto".ui", \
1397     account_widget_build_##proto }
1398
1399 static void
1400 add_enable_checkbox (EmpathyAccountWidget *self,
1401     TpAccount *account)
1402 {
1403   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1404 #ifdef HAVE_MOBLIN
1405   GtkWidget *w;
1406 #else
1407   GtkWidget *vbox = self->ui_details->widget;
1408 #endif
1409   guint nb_rows, nb_columns;
1410   gboolean is_enabled;
1411
1412   /* handle the "Enabled" checkbox. We only add it when modifying an account */
1413   if (priv->creating_account || priv->table_common_settings == NULL)
1414     return;
1415
1416   is_enabled = tp_account_is_enabled (account);
1417
1418 #ifdef HAVE_MOBLIN
1419   w = gtk_label_new (_("Account:"));
1420   gtk_misc_set_alignment (GTK_MISC (w), 0, 0.5);
1421
1422   priv->enabled_checkbox = nbtk_gtk_light_switch_new ();
1423
1424   nbtk_gtk_light_switch_set_active (
1425       NBTK_GTK_LIGHT_SWITCH (priv->enabled_checkbox), is_enabled);
1426
1427   gtk_widget_show (w);
1428 #else
1429   priv->enabled_checkbox =
1430       gtk_check_button_new_with_label (_("Enabled"));
1431
1432   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->enabled_checkbox),
1433       is_enabled);
1434 #endif /* HAVE_MOBLIN */
1435
1436   g_object_get (priv->table_common_settings, "n-rows", &nb_rows,
1437       "n-columns", &nb_columns, NULL);
1438
1439   gtk_table_resize (GTK_TABLE (priv->table_common_settings), ++nb_rows,
1440       nb_columns);
1441
1442 #ifdef HAVE_MOBLIN
1443   gtk_table_attach (GTK_TABLE (priv->table_common_settings),
1444       w,
1445       0, 1, nb_rows - 1, nb_rows,
1446       GTK_FILL, 0, 0, 0);
1447   gtk_table_attach (GTK_TABLE (priv->table_common_settings),
1448       priv->enabled_checkbox,
1449       1, nb_columns, nb_rows - 1, nb_rows,
1450       GTK_EXPAND | GTK_FILL, 0, 0, 0);
1451 #else
1452   gtk_box_pack_start (GTK_BOX (vbox), priv->enabled_checkbox, FALSE, FALSE, 0);
1453   gtk_box_reorder_child (GTK_BOX (vbox), priv->enabled_checkbox, 0);
1454 #endif /* HAVE_MOBLIN */
1455
1456   gtk_widget_show (priv->enabled_checkbox);
1457
1458 #ifdef HAVE_MOBLIN
1459   g_signal_connect (G_OBJECT (priv->enabled_checkbox), "switch-flipped",
1460       G_CALLBACK (account_widget_switch_flipped_cb), self);
1461 #else
1462   g_signal_connect (G_OBJECT (priv->enabled_checkbox), "released",
1463       G_CALLBACK (account_widget_enabled_released_cb), self);
1464 #endif /* HAVE_MOBLIN */
1465 }
1466
1467 #ifndef HAVE_MOBLIN
1468 /* Moblin doesn't support registration */
1469 static void
1470 add_register_buttons (EmpathyAccountWidget *self,
1471     TpAccount *account)
1472 {
1473   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1474   const TpConnectionManagerProtocol *protocol;
1475   GtkWidget *radiobutton_register;
1476   GtkWidget *vbox = self->ui_details->widget;
1477
1478   if (!priv->creating_account)
1479     return;
1480
1481   protocol = empathy_account_settings_get_tp_protocol (priv->settings);
1482   if (protocol == NULL)
1483     return;
1484
1485   if (!tp_connection_manager_protocol_can_register (protocol))
1486     return;
1487
1488   if (account_widget_is_gtalk (self) || account_widget_is_facebook (self))
1489     return;
1490
1491   if (priv->simple)
1492     return;
1493
1494   priv->radiobutton_reuse = gtk_radio_button_new_with_label (NULL,
1495       _("This account already exists on the server"));
1496   radiobutton_register = gtk_radio_button_new_with_label (
1497       gtk_radio_button_get_group (GTK_RADIO_BUTTON (priv->radiobutton_reuse)),
1498       _("Create a new account on the server"));
1499
1500   gtk_box_pack_start (GTK_BOX (vbox), priv->radiobutton_reuse, FALSE, FALSE, 0);
1501   gtk_box_pack_start (GTK_BOX (vbox), radiobutton_register, FALSE, FALSE, 0);
1502   gtk_box_reorder_child (GTK_BOX (vbox), priv->radiobutton_reuse, 0);
1503   gtk_box_reorder_child (GTK_BOX (vbox), radiobutton_register, 1);
1504   gtk_widget_show (priv->radiobutton_reuse);
1505   gtk_widget_show (radiobutton_register);
1506 }
1507 #endif
1508
1509 static void
1510 do_constructed (GObject *obj)
1511 {
1512   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
1513   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1514   TpAccount *account;
1515   const gchar *protocol, *cm_name;
1516   guint i = 0;
1517   struct {
1518     const gchar *cm_name;
1519     const gchar *protocol;
1520     const char *file;
1521     void (*func)(EmpathyAccountWidget *self, const gchar *filename);
1522   } widgets [] = {
1523     { "salut", "local-xmpp", "empathy-account-widget-local-xmpp.ui",
1524         account_widget_build_salut },
1525     WIDGET (gabble, jabber),
1526     WIDGET (butterfly, msn),
1527     WIDGET (haze, icq),
1528     WIDGET (haze, aim),
1529     WIDGET (haze, yahoo),
1530     WIDGET (haze, groupwise),
1531     WIDGET (idle, irc),
1532     WIDGET (sofiasip, sip),
1533   };
1534
1535   cm_name = empathy_account_settings_get_cm (priv->settings);
1536   protocol = empathy_account_settings_get_protocol (priv->settings);
1537
1538   for (i = 0 ; i < G_N_ELEMENTS (widgets); i++)
1539     {
1540       if (!tp_strdiff (widgets[i].cm_name, cm_name) &&
1541           !tp_strdiff (widgets[i].protocol, protocol))
1542         {
1543           gchar *filename;
1544
1545           filename = empathy_file_lookup (widgets[i].file,
1546               "libempathy-gtk");
1547           widgets[i].func (self, filename);
1548           g_free (filename);
1549
1550           break;
1551         }
1552     }
1553
1554   if (i == G_N_ELEMENTS (widgets))
1555     {
1556       gchar *filename = empathy_file_lookup (
1557           "empathy-account-widget-generic.ui", "libempathy-gtk");
1558       account_widget_build_generic (self, filename);
1559       g_free (filename);
1560     }
1561
1562   /* handle default focus */
1563   if (self->ui_details->default_focus != NULL)
1564     {
1565       GObject *default_focus_entry;
1566
1567       default_focus_entry = gtk_builder_get_object
1568         (self->ui_details->gui, self->ui_details->default_focus);
1569       g_signal_connect (default_focus_entry, "realize",
1570           G_CALLBACK (gtk_widget_grab_focus),
1571           NULL);
1572     }
1573
1574   /* handle forget button */
1575   if (self->ui_details->add_forget)
1576     {
1577       const gchar *password = NULL;
1578
1579       priv->button_forget = GTK_WIDGET (gtk_builder_get_object
1580           (self->ui_details->gui, "button_forget"));
1581       priv->entry_password = GTK_WIDGET (gtk_builder_get_object
1582           (self->ui_details->gui, "entry_password"));
1583
1584       password = empathy_account_settings_get_string (priv->settings,
1585           "password");
1586       gtk_widget_set_sensitive (priv->button_forget,
1587           !EMP_STR_EMPTY (password));
1588
1589       g_signal_connect (priv->button_forget, "clicked",
1590           G_CALLBACK (account_widget_forget_clicked_cb),
1591           self);
1592       g_signal_connect (priv->entry_password, "changed",
1593           G_CALLBACK (account_widget_password_changed_cb),
1594           self);
1595     }
1596
1597   /* dup and init the account-manager */
1598   priv->account_manager = tp_account_manager_dup ();
1599
1600   g_object_ref (self);
1601   tp_account_manager_prepare_async (priv->account_manager, NULL,
1602       account_manager_ready_cb, self);
1603
1604   /* handle apply and cancel button */
1605   if (!priv->simple)
1606     {
1607       GtkWidget *hbox = gtk_hbox_new (TRUE, 3);
1608
1609       priv->cancel_button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
1610
1611       if (priv->creating_account)
1612         {
1613           /* Assumre we are offline, display a Save button. We'll update
1614            * it once the account manager is ready if needed */
1615           priv->apply_button = gtk_button_new_from_stock (GTK_STOCK_SAVE);
1616
1617           empathy_signal_connect_weak (priv->account_manager,
1618               "most-available-presence-changed",
1619               G_CALLBACK (presence_changed_cb), obj);
1620         }
1621       else
1622         {
1623           /* We are editing an existing account, display an Apply button */
1624           priv->apply_button = gtk_button_new_from_stock (GTK_STOCK_APPLY);
1625         }
1626
1627       gtk_box_pack_end (GTK_BOX (hbox), priv->apply_button, TRUE,
1628           TRUE, 3);
1629       gtk_box_pack_end (GTK_BOX (hbox), priv->cancel_button, TRUE,
1630           TRUE, 3);
1631
1632       gtk_box_pack_end (GTK_BOX (self->ui_details->widget), hbox, FALSE,
1633           FALSE, 3);
1634
1635       g_signal_connect (priv->cancel_button, "clicked",
1636           G_CALLBACK (account_widget_cancel_clicked_cb),
1637           self);
1638       g_signal_connect (priv->apply_button, "clicked",
1639           G_CALLBACK (account_widget_apply_clicked_cb),
1640           self);
1641       gtk_widget_show_all (hbox);
1642
1643       if (priv->creating_account)
1644         /* When creating an account, the user might have nothing to enter.
1645          * That means that no control interaction might occur,
1646          * so we update the control button sensitivity manually.
1647          */
1648         account_widget_handle_control_buttons_sensitivity (self);
1649       else
1650         account_widget_set_control_buttons_sensitivity (self, FALSE);
1651     }
1652
1653   account = empathy_account_settings_get_account (priv->settings);
1654
1655   if (account != NULL)
1656     {
1657       g_signal_connect (account, "notify::enabled",
1658           G_CALLBACK (empathy_account_widget_enabled_cb), self);
1659     }
1660
1661 #ifndef HAVE_MOBLIN
1662   add_register_buttons (self, account);
1663 #endif
1664   add_enable_checkbox (self, account);
1665
1666   /* hook up to widget destruction to unref ourselves */
1667   g_signal_connect (self->ui_details->widget, "destroy",
1668       G_CALLBACK (account_widget_destroy_cb), self);
1669
1670   empathy_builder_unref_and_keep_widget (self->ui_details->gui,
1671       self->ui_details->widget);
1672   self->ui_details->gui = NULL;
1673 }
1674
1675 static void
1676 do_dispose (GObject *obj)
1677 {
1678   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
1679   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1680
1681   if (priv->dispose_run)
1682     return;
1683
1684   priv->dispose_run = TRUE;
1685
1686   empathy_account_settings_is_ready (priv->settings);
1687
1688   if (priv->settings != NULL)
1689     {
1690       TpAccount *account;
1691       account = empathy_account_settings_get_account (priv->settings);
1692
1693       if (account != NULL)
1694         {
1695           g_signal_handlers_disconnect_by_func (account,
1696               empathy_account_widget_enabled_cb, self);
1697         }
1698
1699       g_object_unref (priv->settings);
1700       priv->settings = NULL;
1701     }
1702
1703   if (priv->account_manager != NULL)
1704     {
1705       g_object_unref (priv->account_manager);
1706       priv->account_manager = NULL;
1707     }
1708
1709   if (G_OBJECT_CLASS (empathy_account_widget_parent_class)->dispose != NULL)
1710     G_OBJECT_CLASS (empathy_account_widget_parent_class)->dispose (obj);
1711 }
1712
1713 static void
1714 do_finalize (GObject *obj)
1715 {
1716   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
1717
1718   g_free (self->ui_details->default_focus);
1719   g_slice_free (EmpathyAccountWidgetUIDetails, self->ui_details);
1720
1721   if (G_OBJECT_CLASS (empathy_account_widget_parent_class)->finalize != NULL)
1722     G_OBJECT_CLASS (empathy_account_widget_parent_class)->finalize (obj);
1723 }
1724
1725 static void
1726 empathy_account_widget_class_init (EmpathyAccountWidgetClass *klass)
1727 {
1728   GObjectClass *oclass = G_OBJECT_CLASS (klass);
1729   GParamSpec *param_spec;
1730
1731   oclass->get_property = do_get_property;
1732   oclass->set_property = do_set_property;
1733   oclass->constructed = do_constructed;
1734   oclass->dispose = do_dispose;
1735   oclass->finalize = do_finalize;
1736
1737   param_spec = g_param_spec_string ("protocol",
1738       "protocol", "The protocol of the account",
1739       NULL,
1740       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
1741   g_object_class_install_property (oclass, PROP_PROTOCOL, param_spec);
1742
1743   param_spec = g_param_spec_object ("settings",
1744       "settings", "The settings of the account",
1745       EMPATHY_TYPE_ACCOUNT_SETTINGS,
1746       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
1747   g_object_class_install_property (oclass, PROP_SETTINGS, param_spec);
1748
1749   param_spec = g_param_spec_boolean ("simple",
1750       "simple", "Whether the account widget is a simple or an advanced one",
1751       FALSE,
1752       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
1753   g_object_class_install_property (oclass, PROP_SIMPLE, param_spec);
1754
1755   param_spec = g_param_spec_boolean ("creating-account",
1756       "creating-account",
1757       "TRUE if we're creating an account, FALSE if we're modifying it",
1758       FALSE,
1759       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
1760   g_object_class_install_property (oclass, PROP_CREATING_ACCOUNT, param_spec);
1761
1762   signals[HANDLE_APPLY] =
1763     g_signal_new ("handle-apply", G_TYPE_FROM_CLASS (klass),
1764         G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1765         g_cclosure_marshal_VOID__BOOLEAN,
1766         G_TYPE_NONE,
1767         1, G_TYPE_BOOLEAN);
1768
1769   /* This signal is emitted when an account has been created and enabled. */
1770   signals[ACCOUNT_CREATED] =
1771       g_signal_new ("account-created", G_TYPE_FROM_CLASS (klass),
1772           G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1773           g_cclosure_marshal_VOID__POINTER,
1774           G_TYPE_NONE,
1775           1, G_TYPE_OBJECT);
1776
1777   signals[CANCELLED] =
1778       g_signal_new ("cancelled", G_TYPE_FROM_CLASS (klass),
1779           G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1780           g_cclosure_marshal_VOID__VOID,
1781           G_TYPE_NONE,
1782           0);
1783
1784   g_type_class_add_private (klass, sizeof (EmpathyAccountWidgetPriv));
1785 }
1786
1787 static void
1788 empathy_account_widget_init (EmpathyAccountWidget *self)
1789 {
1790   EmpathyAccountWidgetPriv *priv =
1791     G_TYPE_INSTANCE_GET_PRIVATE ((self), EMPATHY_TYPE_ACCOUNT_WIDGET,
1792         EmpathyAccountWidgetPriv);
1793
1794   self->priv = priv;
1795   priv->dispose_run = FALSE;
1796
1797   self->ui_details = g_slice_new0 (EmpathyAccountWidgetUIDetails);
1798 }
1799
1800 /* public methods */
1801
1802 void
1803 empathy_account_widget_discard_pending_changes
1804     (EmpathyAccountWidget *widget)
1805 {
1806   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
1807
1808   empathy_account_settings_discard_changes (priv->settings);
1809   priv->contains_pending_changes = FALSE;
1810 }
1811
1812 gboolean
1813 empathy_account_widget_contains_pending_changes (EmpathyAccountWidget *widget)
1814 {
1815   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
1816
1817   return priv->contains_pending_changes;
1818 }
1819
1820 void
1821 empathy_account_widget_handle_params (EmpathyAccountWidget *self,
1822     const gchar *first_widget,
1823     ...)
1824 {
1825   va_list args;
1826
1827   va_start (args, first_widget);
1828   account_widget_handle_params_valist (self, first_widget, args);
1829   va_end (args);
1830 }
1831
1832 GtkWidget *
1833 empathy_account_widget_get_widget (EmpathyAccountWidget *widget)
1834 {
1835   return widget->ui_details->widget;
1836 }
1837
1838 EmpathyAccountWidget *
1839 empathy_account_widget_new_for_protocol (EmpathyAccountSettings *settings,
1840     gboolean simple)
1841 {
1842   EmpathyAccountWidget *self;
1843
1844   g_return_val_if_fail (EMPATHY_IS_ACCOUNT_SETTINGS (settings), NULL);
1845
1846   self = g_object_new
1847     (EMPATHY_TYPE_ACCOUNT_WIDGET,
1848         "settings", settings, "simple", simple,
1849         "creating-account",
1850         empathy_account_settings_get_account (settings) == NULL,
1851         NULL);
1852
1853   return self;
1854 }
1855
1856 gchar *
1857 empathy_account_widget_get_default_display_name (EmpathyAccountWidget *self)
1858 {
1859   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1860   const gchar *login_id;
1861   const gchar *protocol, *p;
1862   gchar *default_display_name;
1863
1864   login_id = empathy_account_settings_get_string (priv->settings, "account");
1865   protocol = empathy_account_settings_get_protocol (priv->settings);
1866
1867   if (login_id != NULL)
1868     {
1869       /* TODO: this should be done in empathy-account-widget-irc */
1870       if (!tp_strdiff (protocol, "irc"))
1871         {
1872           const gchar* server;
1873           server = empathy_account_settings_get_string (priv->settings,
1874               "server");
1875
1876           /* To translators: The first parameter is the login id and the
1877            * second one is the server. The resulting string will be something
1878            * like: "MyUserName on chat.freenode.net".
1879            * You should reverse the order of these arguments if the
1880            * server should come before the login id in your locale.*/
1881           default_display_name = g_strdup_printf (_("%1$s on %2$s"),
1882               login_id, server);
1883         }
1884       else
1885         {
1886           default_display_name = g_strdup (login_id);
1887         }
1888
1889       return default_display_name;
1890     }
1891
1892   if ((p = empathy_protocol_name_to_display_name (protocol)) != NULL)
1893     protocol = p;
1894
1895   if (protocol != NULL)
1896     {
1897       /* To translators: The parameter is the protocol name. The resulting
1898        * string will be something like: "Jabber Account" */
1899       default_display_name = g_strdup_printf (_("%s Account"), protocol);
1900     }
1901   else
1902     {
1903       default_display_name = g_strdup (_("New account"));
1904     }
1905
1906   return default_display_name;
1907 }
1908
1909 /* Used by subclass to indicate that widget contains pending changes */
1910 void
1911 empathy_account_widget_changed (EmpathyAccountWidget *self)
1912 {
1913   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1914
1915   account_widget_handle_control_buttons_sensitivity (self);
1916   priv->contains_pending_changes = TRUE;
1917 }
1918
1919 void
1920 empathy_account_widget_set_account_param (EmpathyAccountWidget *self,
1921     const gchar *account)
1922 {
1923   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1924
1925   if (priv->param_account_widget == NULL)
1926     return;
1927
1928   gtk_entry_set_text (GTK_ENTRY (priv->param_account_widget), account);
1929 }
1930
1931 void
1932 empathy_account_widget_set_password_param (EmpathyAccountWidget *self,
1933     const gchar *account)
1934 {
1935   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1936
1937   if (priv->param_password_widget == NULL)
1938     return;
1939
1940   gtk_entry_set_text (GTK_ENTRY (priv->param_password_widget), account);
1941 }