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