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