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