]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-account-widget.c
Access Account.I.Storage properties via TpAccount
[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_MEEGO
34 #include <mx-gtk/mx-gtk.h>
35 #endif /* HAVE_MEEGO */
36 #include <gio/gdesktopappinfo.h>
37
38 #include <libempathy/empathy-utils.h>
39
40 #include <telepathy-glib/account.h>
41 #include <telepathy-glib/account-manager.h>
42 #include <telepathy-glib/connection-manager.h>
43 #include <telepathy-glib/util.h>
44 #include <dbus/dbus-protocol.h>
45
46 #include "empathy-account-widget.h"
47 #include "empathy-account-widget-private.h"
48 #include "empathy-account-widget-sip.h"
49 #include "empathy-account-widget-irc.h"
50 #include "empathy-ui-utils.h"
51
52 #define DEBUG_FLAG EMPATHY_DEBUG_ACCOUNT
53 #include <libempathy/empathy-debug.h>
54
55 G_DEFINE_TYPE (EmpathyAccountWidget, empathy_account_widget, G_TYPE_OBJECT)
56
57 typedef struct {
58   EmpathyAccountSettings *settings;
59
60   GtkWidget *table_common_settings;
61   GtkWidget *apply_button;
62   GtkWidget *cancel_button;
63   GtkWidget *entry_password;
64   GtkWidget *spinbutton_port;
65   GtkWidget *enabled_checkbox;
66   GtkWidget *radiobutton_reuse;
67
68   gboolean simple;
69
70   gboolean contains_pending_changes;
71
72   /* An EmpathyAccountWidget can be used to either create an account or
73    * modify it. When we are creating an account, this member is set to TRUE */
74   gboolean creating_account;
75
76   /* whether there are any other real accounts. Necessary so we know whether
77    * it's safe to dismiss this widget in some cases (eg, whether the Cancel
78    * button should be sensitive) */
79   gboolean other_accounts_exist;
80
81   /* if TRUE, the GTK+ destroy signal has been fired and so the widgets
82    * embedded in this account widget can't be used any more
83    * workaround because some async callbacks can be called after the
84    * widget has been destroyed */
85   gboolean destroyed;
86
87   TpAccountManager *account_manager;
88
89   GtkWidget *param_account_widget;
90   GtkWidget *param_password_widget;
91
92   /* Used only for IRC accounts */
93   EmpathyIrcNetworkChooser *irc_network_chooser;
94
95   gboolean dispose_run;
96 } EmpathyAccountWidgetPriv;
97
98 enum {
99   PROP_PROTOCOL = 1,
100   PROP_SETTINGS,
101   PROP_SIMPLE,
102   PROP_CREATING_ACCOUNT,
103   PROP_OTHER_ACCOUNTS_EXIST,
104 };
105
106 enum {
107   HANDLE_APPLY,
108   ACCOUNT_CREATED,
109   CANCELLED,
110   LAST_SIGNAL
111 };
112
113 static void account_widget_apply_and_log_in (EmpathyAccountWidget *);
114
115 enum {
116   RESPONSE_LAUNCH
117 };
118
119 static guint signals[LAST_SIGNAL] = { 0 };
120
121 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccountWidget)
122 #define CHANGED_TIMEOUT 300
123
124 static void
125 account_widget_set_control_buttons_sensitivity (EmpathyAccountWidget *self,
126     gboolean sensitive)
127 {
128   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
129
130   if (!priv->simple)
131     {
132       /* we hit this case because of the 'other-accounts-exist' property handler
133        * being called during init (before constructed()) */
134       if (priv->apply_button == NULL || priv->cancel_button == NULL)
135         return;
136
137       gtk_widget_set_sensitive (priv->apply_button, sensitive);
138       gtk_widget_set_sensitive (priv->cancel_button,
139           (sensitive || priv->creating_account) && priv->other_accounts_exist);
140     }
141 }
142
143 static void
144 account_widget_handle_control_buttons_sensitivity (EmpathyAccountWidget *self)
145 {
146   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
147   gboolean is_valid;
148
149   is_valid = empathy_account_settings_is_valid (priv->settings);
150
151   if (!priv->simple)
152       account_widget_set_control_buttons_sensitivity (self, is_valid);
153
154   g_signal_emit (self, signals[HANDLE_APPLY], 0, is_valid);
155 }
156
157 static void
158 account_widget_entry_changed_common (EmpathyAccountWidget *self,
159     GtkEntry *entry, gboolean focus)
160 {
161   const gchar *str;
162   const gchar *param_name;
163   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
164
165   str = gtk_entry_get_text (entry);
166   param_name = g_object_get_data (G_OBJECT (entry), "param_name");
167
168   if (EMP_STR_EMPTY (str))
169     {
170       const gchar *value = NULL;
171
172       empathy_account_settings_unset (priv->settings, param_name);
173
174       if (focus)
175         {
176           value = empathy_account_settings_get_string (priv->settings,
177               param_name);
178           DEBUG ("Unset %s and restore to %s", param_name, value);
179           gtk_entry_set_text (entry, value ? value : "");
180         }
181     }
182   else
183     {
184       DEBUG ("Setting %s to %s", param_name,
185           tp_strdiff (param_name, "password") ? str : "***");
186       empathy_account_settings_set_string (priv->settings, param_name, str);
187     }
188 }
189
190 static void
191 account_widget_entry_changed_cb (GtkEditable *entry,
192     EmpathyAccountWidget *self)
193 {
194   account_widget_entry_changed_common (self, GTK_ENTRY (entry), FALSE);
195   empathy_account_widget_changed (self);
196 }
197
198 static void
199 account_widget_int_changed_cb (GtkWidget *widget,
200     EmpathyAccountWidget *self)
201 {
202   const gchar *param_name;
203   gint value;
204   const gchar *signature;
205   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
206
207   value = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
208   param_name = g_object_get_data (G_OBJECT (widget), "param_name");
209
210   signature = empathy_account_settings_get_dbus_signature (priv->settings,
211     param_name);
212   g_return_if_fail (signature != NULL);
213
214   DEBUG ("Setting %s to %d", param_name, value);
215
216   switch ((int)*signature)
217     {
218     case DBUS_TYPE_INT16:
219     case DBUS_TYPE_INT32:
220       empathy_account_settings_set_int32 (priv->settings, param_name, value);
221       break;
222     case DBUS_TYPE_INT64:
223       empathy_account_settings_set_int64 (priv->settings, param_name, value);
224       break;
225     case DBUS_TYPE_UINT16:
226     case DBUS_TYPE_UINT32:
227       empathy_account_settings_set_uint32 (priv->settings, param_name, value);
228       break;
229     case DBUS_TYPE_UINT64:
230       empathy_account_settings_set_uint64 (priv->settings, param_name, value);
231       break;
232     default:
233       g_return_if_reached ();
234     }
235
236   empathy_account_widget_changed (self);
237 }
238
239 static void
240 account_widget_checkbutton_toggled_cb (GtkWidget *widget,
241     EmpathyAccountWidget *self)
242 {
243   gboolean     value;
244   gboolean     default_value;
245   const gchar *param_name;
246   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
247
248   value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
249   param_name = g_object_get_data (G_OBJECT (widget), "param_name");
250
251   /* FIXME: This is ugly! checkbox don't have a "not-set" value so we
252    * always unset the param and set the value if different from the
253    * default value. */
254   empathy_account_settings_unset (priv->settings, param_name);
255   default_value = empathy_account_settings_get_boolean (priv->settings,
256       param_name);
257
258   if (default_value == value)
259     {
260       DEBUG ("Unset %s and restore to %d", param_name, default_value);
261     }
262   else
263     {
264       DEBUG ("Setting %s to %d", param_name, value);
265       empathy_account_settings_set_boolean (priv->settings, param_name, value);
266     }
267
268   empathy_account_widget_changed (self);
269 }
270
271 static void
272 account_widget_jabber_ssl_toggled_cb (GtkWidget *checkbutton_ssl,
273     EmpathyAccountWidget *self)
274 {
275   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
276   gboolean   value;
277   gint32       port = 0;
278
279   value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbutton_ssl));
280   port = empathy_account_settings_get_uint32 (priv->settings, "port");
281
282   if (value)
283     {
284       if (port == 5222 || port == 0)
285         port = 5223;
286     }
287   else
288     {
289       if (port == 5223 || port == 0)
290         port = 5222;
291     }
292
293   gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->spinbutton_port), port);
294
295   priv->contains_pending_changes = TRUE;
296 }
297
298 static void
299 account_widget_combobox_changed_cb (GtkWidget *widget,
300     EmpathyAccountWidget *self)
301 {
302   GtkTreeIter iter;
303   GtkTreeModel *model;
304   const gchar *value;
305   const GValue *v;
306   const gchar *default_value = NULL;
307   const gchar *param_name;
308   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
309
310   if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter))
311     return;
312
313   model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
314   /* the param value is stored in the first column */
315   gtk_tree_model_get (model, &iter, 0, &value, -1);
316
317   param_name = g_object_get_data (G_OBJECT (widget), "param_name");
318
319   v = empathy_account_settings_get_default (priv->settings, param_name);
320   if (v != NULL)
321     default_value = g_value_get_string (v);
322
323   if (!tp_strdiff (value, default_value))
324     {
325       DEBUG ("Unset %s and restore to %s", param_name, default_value);
326       empathy_account_settings_unset (priv->settings, param_name);
327     }
328   else
329     {
330       DEBUG ("Setting %s to %s", param_name, value);
331       empathy_account_settings_set_string (priv->settings, param_name, value);
332     }
333
334   empathy_account_widget_changed (self);
335 }
336
337 static void
338 clear_icon_released_cb (GtkEntry *entry,
339     GtkEntryIconPosition icon_pos,
340     GdkEvent *event,
341     EmpathyAccountWidget *self)
342 {
343   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
344   const gchar *param_name;
345
346   param_name = g_object_get_data (G_OBJECT (entry), "param_name");
347
348   DEBUG ("Unset %s", param_name);
349   empathy_account_settings_unset (priv->settings, param_name);
350   gtk_entry_set_text (entry, "");
351
352   empathy_account_widget_changed (self);
353 }
354
355 static void
356 password_entry_changed_cb (GtkEditable *entry,
357     EmpathyAccountWidget *self)
358 {
359   const gchar *str;
360
361   str = gtk_entry_get_text (GTK_ENTRY (entry));
362
363   gtk_entry_set_icon_sensitive (GTK_ENTRY (entry),
364       GTK_ENTRY_ICON_SECONDARY, !EMP_STR_EMPTY (str));
365 }
366
367 static void
368 password_entry_activated_cb (GtkEntry *entry,
369     EmpathyAccountWidget *self)
370 {
371     EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
372
373     if (gtk_widget_get_sensitive (priv->apply_button))
374         account_widget_apply_and_log_in (self);
375 }
376
377 void
378 empathy_account_widget_setup_widget (EmpathyAccountWidget *self,
379     GtkWidget *widget,
380     const gchar *param_name)
381 {
382   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
383
384   g_object_set_data_full (G_OBJECT (widget), "param_name",
385       g_strdup (param_name), g_free);
386
387   if (GTK_IS_SPIN_BUTTON (widget))
388     {
389       gint value = 0;
390       const gchar *signature;
391
392       signature = empathy_account_settings_get_dbus_signature (priv->settings,
393           param_name);
394       g_return_if_fail (signature != NULL);
395
396       switch ((int)*signature)
397         {
398           case DBUS_TYPE_INT16:
399           case DBUS_TYPE_INT32:
400             value = empathy_account_settings_get_int32 (priv->settings,
401               param_name);
402             break;
403           case DBUS_TYPE_INT64:
404             value = empathy_account_settings_get_int64 (priv->settings,
405               param_name);
406             break;
407           case DBUS_TYPE_UINT16:
408           case DBUS_TYPE_UINT32:
409             value = empathy_account_settings_get_uint32 (priv->settings,
410               param_name);
411             break;
412           case DBUS_TYPE_UINT64:
413             value = empathy_account_settings_get_uint64 (priv->settings,
414                 param_name);
415             break;
416           default:
417             g_return_if_reached ();
418         }
419
420       gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
421
422       g_signal_connect (widget, "value-changed",
423           G_CALLBACK (account_widget_int_changed_cb),
424           self);
425     }
426   else if (GTK_IS_ENTRY (widget))
427     {
428       const gchar *str = NULL;
429
430       str = empathy_account_settings_get_string (priv->settings, param_name);
431       gtk_entry_set_text (GTK_ENTRY (widget), str ? str : "");
432
433       if (!tp_strdiff (param_name, "account"))
434         priv->param_account_widget = widget;
435       else if (!tp_strdiff (param_name, "password"))
436         priv->param_password_widget = widget;
437
438       if (strstr (param_name, "password"))
439         {
440           gtk_entry_set_visibility (GTK_ENTRY (widget), FALSE);
441
442           /* Add 'clear' icon */
443           gtk_entry_set_icon_from_stock (GTK_ENTRY (widget),
444               GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
445
446           gtk_entry_set_icon_sensitive (GTK_ENTRY (widget),
447               GTK_ENTRY_ICON_SECONDARY, !EMP_STR_EMPTY (str));
448
449           g_signal_connect (widget, "icon-release",
450               G_CALLBACK (clear_icon_released_cb), self);
451           g_signal_connect (widget, "changed",
452               G_CALLBACK (password_entry_changed_cb), self);
453           g_signal_connect (widget, "activate",
454               G_CALLBACK (password_entry_activated_cb), self);
455         }
456
457       g_signal_connect (widget, "changed",
458           G_CALLBACK (account_widget_entry_changed_cb), self);
459     }
460   else if (GTK_IS_TOGGLE_BUTTON (widget))
461     {
462       gboolean value = FALSE;
463
464       value = empathy_account_settings_get_boolean (priv->settings,
465           param_name);
466       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), value);
467
468       g_signal_connect (widget, "toggled",
469           G_CALLBACK (account_widget_checkbutton_toggled_cb),
470           self);
471     }
472   else if (GTK_IS_COMBO_BOX (widget))
473     {
474       /* The combo box's model has to contain the param value in its first
475        * column (as a string) */
476       const gchar *str;
477       GtkTreeModel *model;
478       GtkTreeIter iter;
479       gboolean valid;
480
481       str = empathy_account_settings_get_string (priv->settings, param_name);
482       model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
483
484       valid = gtk_tree_model_get_iter_first (model, &iter);
485       while (valid)
486         {
487           gchar *name;
488
489           gtk_tree_model_get (model, &iter, 0, &name, -1);
490           if (!tp_strdiff (name, str))
491             {
492               gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter);
493               valid = FALSE;
494             }
495           else
496             {
497               valid = gtk_tree_model_iter_next (model, &iter);
498             }
499
500           g_free (name);
501         }
502
503       g_signal_connect (widget, "changed",
504           G_CALLBACK (account_widget_combobox_changed_cb),
505           self);
506     }
507   else
508     {
509       DEBUG ("Unknown type of widget for param %s", param_name);
510     }
511 }
512
513 static GHashTable *
514 build_translated_params (void)
515 {
516   GHashTable *hash;
517
518   hash = g_hash_table_new (g_str_hash, g_str_equal);
519   g_hash_table_insert (hash, "account", _("Account"));
520   g_hash_table_insert (hash, "password", _("Password"));
521   g_hash_table_insert (hash, "server", _("Server"));
522   g_hash_table_insert (hash, "port", _("Port"));
523
524   return hash;
525 }
526
527 static gchar *
528 account_widget_generic_format_param_name (const gchar *param_name)
529 {
530   gchar *str;
531   gchar *p;
532   static GHashTable *translated_params = NULL;
533
534   if (G_UNLIKELY (translated_params == NULL))
535     translated_params = build_translated_params ();
536
537   /* Translate most common parameters */
538   str = g_hash_table_lookup (translated_params, param_name);
539   if (str != NULL)
540     return g_strdup (str);
541
542   str = g_strdup (param_name);
543
544   if (str && g_ascii_isalpha (str[0]))
545     str[0] = g_ascii_toupper (str[0]);
546
547   while ((p = strchr (str, '-')) != NULL)
548     {
549       if (p[1] != '\0' && g_ascii_isalpha (p[1]))
550         {
551           p[0] = ' ';
552           p[1] = g_ascii_toupper (p[1]);
553         }
554
555       p++;
556     }
557
558   return str;
559 }
560
561 static void
562 accounts_widget_generic_setup (EmpathyAccountWidget *self,
563     GtkWidget *table_common_settings,
564     GtkWidget *table_advanced_settings)
565 {
566   TpConnectionManagerParam *params, *param;
567   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
568
569   params = empathy_account_settings_get_tp_params (priv->settings);
570
571   for (param = params; param != NULL && param->name != NULL; param++)
572     {
573       GtkWidget       *table_settings;
574       guint            n_rows = 0;
575       GtkWidget       *widget = NULL;
576       gchar           *param_name_formatted;
577
578       if (param->flags & TP_CONN_MGR_PARAM_FLAG_REQUIRED)
579         table_settings = table_common_settings;
580       else if (priv->simple)
581         return;
582       else
583         table_settings = table_advanced_settings;
584
585       param_name_formatted = account_widget_generic_format_param_name
586         (param->name);
587       g_object_get (table_settings, "n-rows", &n_rows, NULL);
588       gtk_table_resize (GTK_TABLE (table_settings), ++n_rows, 2);
589
590       if (param->dbus_signature[0] == 's')
591         {
592           gchar *str;
593
594           str = g_strdup_printf (_("%s:"), param_name_formatted);
595           widget = gtk_label_new (str);
596           gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
597           g_free (str);
598
599           gtk_table_attach (GTK_TABLE (table_settings),
600               widget,
601               0, 1,
602               n_rows - 1, n_rows,
603               GTK_FILL, 0,
604               0, 0);
605           gtk_widget_show (widget);
606
607           widget = gtk_entry_new ();
608           if (strcmp (param->name, "account") == 0)
609             {
610               g_signal_connect (widget, "realize",
611                   G_CALLBACK (gtk_widget_grab_focus),
612                   NULL);
613             }
614           gtk_table_attach (GTK_TABLE (table_settings),
615               widget,
616               1, 2,
617               n_rows - 1, n_rows,
618               GTK_FILL | GTK_EXPAND, 0,
619               0, 0);
620           gtk_widget_show (widget);
621         }
622       /* int types: ynqiuxt. double type is 'd' */
623       else if (param->dbus_signature[0] == 'y' ||
624           param->dbus_signature[0] == 'n' ||
625           param->dbus_signature[0] == 'q' ||
626           param->dbus_signature[0] == 'i' ||
627           param->dbus_signature[0] == 'u' ||
628           param->dbus_signature[0] == 'x' ||
629           param->dbus_signature[0] == 't' ||
630           param->dbus_signature[0] == 'd')
631         {
632           gchar   *str = NULL;
633           gdouble  minint = 0;
634           gdouble  maxint = 0;
635           gdouble  step = 1;
636
637           switch (param->dbus_signature[0])
638             {
639             case 'y': minint = G_MININT8;  maxint = G_MAXINT8;   break;
640             case 'n': minint = G_MININT16; maxint = G_MAXINT16;  break;
641             case 'q': minint = 0;          maxint = G_MAXUINT16; break;
642             case 'i': minint = G_MININT32; maxint = G_MAXINT32;  break;
643             case 'u': minint = 0;          maxint = G_MAXUINT32; break;
644             case 'x': minint = G_MININT64; maxint = G_MAXINT64;  break;
645             case 't': minint = 0;          maxint = G_MAXUINT64; break;
646             case 'd': minint = G_MININT32; maxint = G_MAXINT32;
647               step = 0.1; break;
648             default: g_assert_not_reached ();
649             }
650
651           str = g_strdup_printf (_("%s:"), param_name_formatted);
652           widget = gtk_label_new (str);
653           gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
654           g_free (str);
655
656           gtk_table_attach (GTK_TABLE (table_settings),
657               widget,
658               0, 1,
659               n_rows - 1, n_rows,
660               GTK_FILL, 0,
661               0, 0);
662           gtk_widget_show (widget);
663
664           widget = gtk_spin_button_new_with_range (minint, maxint, step);
665           gtk_table_attach (GTK_TABLE (table_settings),
666               widget,
667               1, 2,
668               n_rows - 1, n_rows,
669               GTK_FILL | GTK_EXPAND, 0,
670               0, 0);
671           gtk_widget_show (widget);
672         }
673       else if (param->dbus_signature[0] == 'b')
674         {
675           widget = gtk_check_button_new_with_label (param_name_formatted);
676           gtk_table_attach (GTK_TABLE (table_settings),
677               widget,
678               0, 2,
679               n_rows - 1, n_rows,
680               GTK_FILL | GTK_EXPAND, 0,
681               0, 0);
682           gtk_widget_show (widget);
683         }
684       else
685         {
686           DEBUG ("Unknown signature for param %s: %s",
687               param_name_formatted, param->dbus_signature);
688         }
689
690       if (widget)
691         empathy_account_widget_setup_widget (self, widget, param->name);
692
693       g_free (param_name_formatted);
694     }
695 }
696
697 static void
698 account_widget_handle_params_valist (EmpathyAccountWidget *self,
699     const gchar *first_widget,
700     va_list args)
701 {
702   GObject *object;
703   const gchar *name;
704
705   for (name = first_widget; name; name = va_arg (args, const gchar *))
706     {
707       const gchar *param_name;
708
709       param_name = va_arg (args, const gchar *);
710       object = gtk_builder_get_object (self->ui_details->gui, name);
711
712       if (!object)
713         {
714           g_warning ("Builder is missing object '%s'.", name);
715           continue;
716         }
717
718       empathy_account_widget_setup_widget (self, GTK_WIDGET (object),
719           param_name);
720     }
721 }
722
723 static void
724 account_widget_cancel_clicked_cb (GtkWidget *button,
725     EmpathyAccountWidget *self)
726 {
727   g_signal_emit (self, signals[CANCELLED], 0);
728 }
729
730 static void
731 account_widget_account_enabled_cb (GObject *source_object,
732     GAsyncResult *res,
733     gpointer user_data)
734 {
735   GError *error = NULL;
736   TpAccount *account = TP_ACCOUNT (source_object);
737   EmpathyAccountWidget *widget = EMPATHY_ACCOUNT_WIDGET (user_data);
738   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
739
740   tp_account_set_enabled_finish (account, res, &error);
741
742   if (error != NULL)
743     {
744       DEBUG ("Could not enable the account: %s", error->message);
745       g_error_free (error);
746     }
747   else
748     {
749       empathy_connect_new_account (account, priv->account_manager);
750     }
751
752   /* unref widget - part of the workaround */
753   g_object_unref (widget);
754 }
755
756 static void
757 account_widget_applied_cb (GObject *source_object,
758     GAsyncResult *res,
759     gpointer user_data)
760 {
761   GError *error = NULL;
762   TpAccount *account;
763   EmpathyAccountSettings *settings = EMPATHY_ACCOUNT_SETTINGS (source_object);
764   EmpathyAccountWidget *widget = EMPATHY_ACCOUNT_WIDGET (user_data);
765   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
766
767   empathy_account_settings_apply_finish (settings, res, &error);
768
769   if (error != NULL)
770     {
771       DEBUG ("Could not apply changes to account: %s", error->message);
772       g_error_free (error);
773       return;
774     }
775
776   account = empathy_account_settings_get_account (priv->settings);
777
778   if (account != NULL)
779     {
780       if (priv->creating_account)
781         {
782           /* By default, when an account is created, we enable it. */
783
784           /* workaround to keep widget alive during async call */
785           g_object_ref (widget);
786
787           tp_account_set_enabled_async (account, TRUE,
788               account_widget_account_enabled_cb, widget);
789           g_signal_emit (widget, signals[ACCOUNT_CREATED], 0, account);
790         }
791       else if (priv->enabled_checkbox != NULL)
792         {
793           gboolean enabled_checked;
794
795           enabled_checked =
796 #ifdef HAVE_MEEGO
797             mx_gtk_light_switch_get_active (
798                 MX_GTK_LIGHT_SWITCH (priv->enabled_checkbox));
799 #else
800             gtk_toggle_button_get_active (
801                 GTK_TOGGLE_BUTTON (priv->enabled_checkbox));
802 #endif /* HAVE_MEEGO */
803
804           if (tp_account_is_enabled (account) && enabled_checked)
805             {
806               /* After having applied changes to a user account, we
807                * automatically reconnect it. This is done so the new
808                * information entered by the user is validated on the server. */
809               tp_account_reconnect_async (account, NULL, NULL);
810             }
811         }
812     }
813
814   if (!priv->destroyed)
815     account_widget_set_control_buttons_sensitivity (widget, FALSE);
816
817   priv->contains_pending_changes = FALSE;
818
819   /* unref the widget - part of the workaround */
820   g_object_unref (widget);
821 }
822
823 static void
824 account_widget_apply_and_log_in (EmpathyAccountWidget *self)
825 {
826   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
827   gboolean display_name_overridden;
828
829   if (priv->radiobutton_reuse != NULL)
830     {
831       gboolean reuse = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
832             priv->radiobutton_reuse));
833
834       DEBUG ("Set register param: %d", !reuse);
835       empathy_account_settings_set_boolean (priv->settings, "register", !reuse);
836     }
837
838   g_object_get (priv->settings,
839       "display-name-overridden", &display_name_overridden, NULL);
840
841   if (priv->creating_account || !display_name_overridden)
842     {
843       gchar *display_name;
844
845       /* set default display name for new accounts or update if user didn't
846        * manually override it. */
847       display_name = empathy_account_widget_get_default_display_name (self);
848
849       empathy_account_settings_set_display_name_async (priv->settings,
850           display_name, NULL, NULL);
851
852       g_free (display_name);
853     }
854
855   /* workaround to keep widget alive during async call */
856   g_object_ref (self);
857   empathy_account_settings_apply_async (priv->settings,
858       account_widget_applied_cb, self);
859 }
860
861 static void
862 account_widget_apply_clicked_cb (GtkWidget *button,
863     EmpathyAccountWidget *self)
864 {
865     account_widget_apply_and_log_in (self);
866 }
867
868 static void
869 account_widget_setup_generic (EmpathyAccountWidget *self)
870 {
871   GtkWidget *table_common_settings;
872   GtkWidget *table_advanced_settings;
873
874   table_common_settings = GTK_WIDGET (gtk_builder_get_object
875       (self->ui_details->gui, "table_common_settings"));
876   table_advanced_settings = GTK_WIDGET (gtk_builder_get_object
877       (self->ui_details->gui, "table_advanced_settings"));
878
879   accounts_widget_generic_setup (self, table_common_settings,
880       table_advanced_settings);
881
882   g_object_unref (self->ui_details->gui);
883 }
884
885 static void
886 account_widget_settings_ready_cb (EmpathyAccountSettings *settings,
887     GParamSpec *pspec,
888     gpointer user_data)
889 {
890   EmpathyAccountWidget *self = user_data;
891   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
892
893   if (empathy_account_settings_is_ready (priv->settings))
894     account_widget_setup_generic (self);
895 }
896
897 static void
898 account_widget_build_generic (EmpathyAccountWidget *self,
899     const char *filename)
900 {
901   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
902   GtkWidget *expander_advanced;
903
904   self->ui_details->gui = empathy_builder_get_file (filename,
905       "table_common_settings", &priv->table_common_settings,
906       "vbox_generic_settings", &self->ui_details->widget,
907       "expander_advanced_settings", &expander_advanced,
908       NULL);
909
910   if (priv->simple)
911     gtk_widget_hide (expander_advanced);
912
913   g_object_ref (self->ui_details->gui);
914
915   if (empathy_account_settings_is_ready (priv->settings))
916     account_widget_setup_generic (self);
917   else
918     g_signal_connect (priv->settings, "notify::ready",
919         G_CALLBACK (account_widget_settings_ready_cb), self);
920 }
921
922 static void
923 account_widget_launch_external_clicked (GtkWidget *button,
924     TpAccount *account)
925 {
926   if (!tp_strdiff (tp_account_get_storage_provider (account),
927         "com.meego.libsocialweb"))
928     {
929       /* we know how to handle this external provider */
930       GDesktopAppInfo *app_info;
931       const gchar *args[3] = { NULL, };
932       GError *error = NULL;
933
934       app_info = g_desktop_app_info_new ("gnome-control-center.desktop");
935
936       if (app_info == NULL)
937         {
938           g_critical ("Could not locate 'gnome-control-center.desktop'");
939           return;
940         }
941
942       args[0] = g_app_info_get_commandline (G_APP_INFO (app_info));
943       args[1] = "bisho.desktop";
944       args[2] = NULL;
945
946       gdk_spawn_on_screen (gtk_widget_get_screen (button),
947           NULL, (gchar **) args, NULL,
948           G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error);
949       if (error != NULL)
950         {
951           g_critical ("Failed to launch editor: %s", error->message);
952           g_clear_error (&error);
953         }
954
955       g_object_unref (app_info);
956     }
957 }
958
959 static void
960 account_widget_build_external (EmpathyAccountWidget *self,
961     EmpathyAccountSettings *settings)
962 {
963   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
964   TpAccount *account = empathy_account_settings_get_account (settings);
965   GtkWidget *bar, *widget;
966   gchar *str;
967
968   self->ui_details->widget = gtk_vbox_new (FALSE, 6);
969   priv->table_common_settings = gtk_table_new (1, 2, FALSE);
970
971   if (!tp_strdiff (tp_account_get_storage_provider (account),
972         "com.meego.libsocialweb"))
973     {
974       /* we know how to handle this external provider */
975       str = g_strdup_printf (
976           _("The account %s is edited via My Web Accounts."),
977           empathy_account_settings_get_display_name (settings));
978     }
979   else
980     {
981       str = g_strdup_printf (
982           _("The account %s cannot be edited in Empathy."),
983           empathy_account_settings_get_display_name (settings));
984     }
985
986   widget = gtk_label_new (str);
987   gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
988   g_free (str);
989
990   bar = gtk_info_bar_new ();
991   gtk_info_bar_set_message_type (GTK_INFO_BAR (bar), GTK_MESSAGE_INFO);
992   gtk_container_add (
993       GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (bar))),
994       widget);
995   gtk_container_set_border_width (GTK_CONTAINER (bar), 6);
996
997   if (!tp_strdiff (tp_account_get_storage_provider (account),
998         "com.meego.libsocialweb"))
999     {
1000       /* we know how to handle this external provider */
1001       widget = gtk_info_bar_add_button (GTK_INFO_BAR (bar),
1002           _("Launch My Web Accounts"), RESPONSE_LAUNCH);
1003
1004       g_signal_connect (widget, "clicked",
1005           G_CALLBACK (account_widget_launch_external_clicked), account);
1006     }
1007
1008   gtk_box_pack_start (GTK_BOX (self->ui_details->widget), bar,
1009       FALSE, TRUE, 0);
1010   gtk_box_pack_start (GTK_BOX (self->ui_details->widget),
1011       priv->table_common_settings, FALSE, TRUE, 0);
1012
1013   gtk_widget_show_all (self->ui_details->widget);
1014 }
1015
1016 static void
1017 account_widget_build_salut (EmpathyAccountWidget *self,
1018     const char *filename)
1019 {
1020   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1021   GtkWidget *expander_advanced;
1022
1023   self->ui_details->gui = empathy_builder_get_file (filename,
1024       "table_common_settings", &priv->table_common_settings,
1025       "vbox_salut_settings", &self->ui_details->widget,
1026       "expander_advanced_settings", &expander_advanced,
1027       NULL);
1028
1029   empathy_account_widget_handle_params (self,
1030       "entry_published", "published-name",
1031       "entry_nickname", "nickname",
1032       "entry_first_name", "first-name",
1033       "entry_last_name", "last-name",
1034       "entry_email", "email",
1035       "entry_jid", "jid",
1036       NULL);
1037
1038   if (priv->simple)
1039     gtk_widget_hide (expander_advanced);
1040
1041   self->ui_details->default_focus = g_strdup ("entry_first_name");
1042 }
1043
1044 static void
1045 account_widget_build_irc (EmpathyAccountWidget *self,
1046   const char *filename)
1047 {
1048   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1049
1050   if (priv->simple)
1051     {
1052       priv->irc_network_chooser = empathy_account_widget_irc_build_simple (self,
1053           filename);
1054     }
1055   else
1056     {
1057       priv->irc_network_chooser = empathy_account_widget_irc_build (self,
1058           filename, &priv->table_common_settings);
1059     }
1060 }
1061
1062 static void
1063 account_widget_build_sip (EmpathyAccountWidget *self,
1064   const char *filename)
1065 {
1066   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1067   empathy_account_widget_sip_build (self, filename,
1068     &priv->table_common_settings);
1069 }
1070
1071 static void
1072 account_widget_build_msn (EmpathyAccountWidget *self,
1073     const char *filename)
1074 {
1075   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1076
1077   if (priv->simple)
1078     {
1079       self->ui_details->gui = empathy_builder_get_file (filename,
1080           "vbox_msn_simple", &self->ui_details->widget,
1081           NULL);
1082
1083       empathy_account_widget_handle_params (self,
1084           "entry_id_simple", "account",
1085           "entry_password_simple", "password",
1086           NULL);
1087
1088       self->ui_details->default_focus = g_strdup ("entry_id_simple");
1089     }
1090   else
1091     {
1092       self->ui_details->gui = empathy_builder_get_file (filename,
1093           "table_common_msn_settings", &priv->table_common_settings,
1094           "vbox_msn_settings", &self->ui_details->widget,
1095           NULL);
1096
1097       empathy_account_widget_handle_params (self,
1098           "entry_id", "account",
1099           "entry_password", "password",
1100           "entry_server", "server",
1101           "spinbutton_port", "port",
1102           NULL);
1103
1104       self->ui_details->default_focus = g_strdup ("entry_id");
1105     }
1106 }
1107
1108 static gboolean
1109 account_widget_is_gtalk (EmpathyAccountWidget *self)
1110 {
1111   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1112
1113   return !tp_strdiff (empathy_account_settings_get_icon_name (priv->settings),
1114       "im-google-talk");
1115 }
1116
1117 static gboolean
1118 account_widget_is_facebook (EmpathyAccountWidget *self)
1119 {
1120   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1121
1122   return !tp_strdiff (empathy_account_settings_get_icon_name (priv->settings),
1123       "im-facebook");
1124 }
1125
1126 #define FACEBOOK_SUFFIX "@chat.facebook.com"
1127
1128 static void
1129 facebook_id_widget_changed_cb (GtkWidget *entry,
1130     EmpathyAccountWidget *self)
1131 {
1132   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1133   const gchar *account;
1134
1135   account_widget_entry_changed_common (self, GTK_ENTRY (entry), FALSE);
1136
1137   account = empathy_account_settings_get_string (priv->settings, "account");
1138   if (!EMP_STR_EMPTY (account) &&
1139       !g_str_has_suffix (account, FACEBOOK_SUFFIX))
1140     {
1141       gchar *tmp;
1142
1143       tmp = g_strdup_printf ("%s%s", account, FACEBOOK_SUFFIX);
1144
1145       DEBUG ("Change account from '%s' to '%s'", account, tmp);
1146
1147       empathy_account_settings_set_string (priv->settings, "account", tmp);
1148       g_free (tmp);
1149     }
1150
1151   empathy_account_widget_changed (self);
1152 }
1153
1154 static gchar *
1155 remove_facebook_suffix (const gchar *str)
1156 {
1157   if (!g_str_has_suffix (str, FACEBOOK_SUFFIX))
1158     return g_strdup (str);
1159
1160   return g_strndup (str, strlen (str) - strlen (FACEBOOK_SUFFIX));
1161 }
1162
1163 static void
1164 setup_facebook_id_widget (EmpathyAccountWidget *self,
1165     GtkWidget *widget)
1166 {
1167   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1168   const gchar *str = NULL;
1169
1170   g_object_set_data_full (G_OBJECT (widget), "param_name",
1171       g_strdup ("account"), g_free);
1172
1173   str = empathy_account_settings_get_string (priv->settings, "account");
1174   if (str != NULL)
1175     {
1176       gchar *tmp;
1177
1178       tmp = remove_facebook_suffix (str);
1179       gtk_entry_set_text (GTK_ENTRY (widget), tmp);
1180       g_free (tmp);
1181     }
1182
1183   priv->param_account_widget = widget;
1184
1185   g_signal_connect (widget, "changed",
1186       G_CALLBACK (facebook_id_widget_changed_cb), self);
1187 }
1188
1189 static void
1190 account_widget_build_jabber (EmpathyAccountWidget *self,
1191     const char *filename)
1192 {
1193   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1194   GtkWidget *spinbutton_port;
1195   GtkWidget *checkbutton_ssl;
1196   GtkWidget *label_id, *label_password;
1197   GtkWidget *label_id_create, *label_password_create;
1198   GtkWidget *label_example_gtalk, *label_example_jabber, *label_example_fb;
1199   gboolean is_gtalk, is_facebook;
1200   GtkWidget *expander_advanced;
1201   GtkWidget *entry_id;
1202
1203   is_gtalk = account_widget_is_gtalk (self);
1204   is_facebook = account_widget_is_facebook (self);
1205
1206   if (priv->simple && !is_gtalk && !is_facebook)
1207     {
1208       /* Simple widget for XMPP */
1209       self->ui_details->gui = empathy_builder_get_file (filename,
1210           "vbox_jabber_simple", &self->ui_details->widget,
1211           "label_id_simple", &label_id,
1212           "label_id_create", &label_id_create,
1213           "label_password_simple", &label_password,
1214           "label_password_create", &label_password_create,
1215           NULL);
1216
1217       if (empathy_account_settings_get_boolean (priv->settings, "register"))
1218         {
1219           gtk_widget_hide (label_id);
1220           gtk_widget_hide (label_password);
1221           gtk_widget_show (label_id_create);
1222           gtk_widget_show (label_password_create);
1223         }
1224
1225       empathy_account_widget_handle_params (self,
1226           "entry_id_simple", "account",
1227           "entry_password_simple", "password",
1228           NULL);
1229
1230       self->ui_details->default_focus = g_strdup ("entry_id_simple");
1231     }
1232   else if (priv->simple && is_gtalk)
1233     {
1234       /* Simple widget for Google Talk */
1235       self->ui_details->gui = empathy_builder_get_file (filename,
1236           "vbox_gtalk_simple", &self->ui_details->widget,
1237           NULL);
1238
1239       empathy_account_widget_handle_params (self,
1240           "entry_id_g_simple", "account",
1241           "entry_password_g_simple", "password",
1242           NULL);
1243
1244       self->ui_details->default_focus = g_strdup ("entry_id_g_simple");
1245     }
1246   else if (priv->simple && is_facebook)
1247     {
1248       /* Simple widget for Facebook */
1249       self->ui_details->gui = empathy_builder_get_file (filename,
1250           "vbox_fb_simple", &self->ui_details->widget,
1251           "entry_id_fb_simple", &entry_id,
1252           NULL);
1253
1254       empathy_account_widget_handle_params (self,
1255           "entry_password_fb_simple", "password",
1256           NULL);
1257
1258       setup_facebook_id_widget (self, entry_id);
1259
1260       self->ui_details->default_focus = g_strdup ("entry_id_fb_simple");
1261     }
1262   else
1263     {
1264       /* Full widget for XMPP, Google Talk and Facebook*/
1265       self->ui_details->gui = empathy_builder_get_file (filename,
1266           "table_common_settings", &priv->table_common_settings,
1267           "vbox_jabber_settings", &self->ui_details->widget,
1268           "spinbutton_port", &spinbutton_port,
1269           "checkbutton_ssl", &checkbutton_ssl,
1270           "label_username_example", &label_example_jabber,
1271           "label_username_g_example", &label_example_gtalk,
1272           "label_username_f_example", &label_example_fb,
1273           "expander_advanced", &expander_advanced,
1274           "entry_id", &entry_id,
1275           "label_id", &label_id,
1276           NULL);
1277
1278       empathy_account_widget_handle_params (self,
1279           "entry_password", "password",
1280           "entry_resource", "resource",
1281           "entry_server", "server",
1282           "spinbutton_port", "port",
1283           "spinbutton_priority", "priority",
1284           "checkbutton_ssl", "old-ssl",
1285           "checkbutton_ignore_ssl_errors", "ignore-ssl-errors",
1286           "checkbutton_encryption", "require-encryption",
1287           NULL);
1288
1289       if (is_facebook)
1290         {
1291           gtk_label_set_label (GTK_LABEL (label_id), _("Username:"));
1292
1293           /* Facebook special case the entry ID widget to hide the
1294            * "@chat.facebook.com" part */
1295           setup_facebook_id_widget (self, entry_id);
1296         }
1297       else
1298         {
1299           empathy_account_widget_setup_widget (self, entry_id, "account");
1300         }
1301
1302       self->ui_details->default_focus = g_strdup ("entry_id");
1303       priv->spinbutton_port = spinbutton_port;
1304
1305       g_signal_connect (checkbutton_ssl, "toggled",
1306           G_CALLBACK (account_widget_jabber_ssl_toggled_cb),
1307           self);
1308
1309       if (is_gtalk)
1310         {
1311           gtk_widget_hide (label_example_jabber);
1312           gtk_widget_show (label_example_gtalk);
1313         }
1314       else if (is_facebook)
1315         {
1316           gtk_widget_hide (label_example_jabber);
1317           gtk_widget_show (label_example_fb);
1318           gtk_widget_hide (expander_advanced);
1319         }
1320     }
1321 }
1322
1323 static void
1324 account_widget_build_icq (EmpathyAccountWidget *self,
1325     const char *filename)
1326 {
1327   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1328   GtkWidget *spinbutton_port;
1329
1330   if (priv->simple)
1331     {
1332       self->ui_details->gui = empathy_builder_get_file (filename,
1333           "vbox_icq_simple", &self->ui_details->widget,
1334           NULL);
1335
1336       empathy_account_widget_handle_params (self,
1337           "entry_uin_simple", "account",
1338           "entry_password_simple", "password",
1339           NULL);
1340
1341       self->ui_details->default_focus = g_strdup ("entry_uin_simple");
1342     }
1343   else
1344     {
1345       self->ui_details->gui = empathy_builder_get_file (filename,
1346           "table_common_settings", &priv->table_common_settings,
1347           "vbox_icq_settings", &self->ui_details->widget,
1348           "spinbutton_port", &spinbutton_port,
1349           NULL);
1350
1351       empathy_account_widget_handle_params (self,
1352           "entry_uin", "account",
1353           "entry_password", "password",
1354           "entry_server", "server",
1355           "spinbutton_port", "port",
1356           "entry_charset", "charset",
1357           NULL);
1358
1359       self->ui_details->default_focus = g_strdup ("entry_uin");
1360     }
1361 }
1362
1363 static void
1364 account_widget_build_aim (EmpathyAccountWidget *self,
1365     const char *filename)
1366 {
1367   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1368   GtkWidget *spinbutton_port;
1369
1370   if (priv->simple)
1371     {
1372       self->ui_details->gui = empathy_builder_get_file (filename,
1373           "vbox_aim_simple", &self->ui_details->widget,
1374           NULL);
1375
1376       empathy_account_widget_handle_params (self,
1377           "entry_screenname_simple", "account",
1378           "entry_password_simple", "password",
1379           NULL);
1380
1381       self->ui_details->default_focus = g_strdup ("entry_screenname_simple");
1382     }
1383   else
1384     {
1385       self->ui_details->gui = empathy_builder_get_file (filename,
1386           "table_common_settings", &priv->table_common_settings,
1387           "vbox_aim_settings", &self->ui_details->widget,
1388           "spinbutton_port", &spinbutton_port,
1389           NULL);
1390
1391       empathy_account_widget_handle_params (self,
1392           "entry_screenname", "account",
1393           "entry_password", "password",
1394           "entry_server", "server",
1395           "spinbutton_port", "port",
1396           NULL);
1397
1398       self->ui_details->default_focus = g_strdup ("entry_screenname");
1399     }
1400 }
1401
1402 static void
1403 account_widget_build_yahoo (EmpathyAccountWidget *self,
1404     const char *filename)
1405 {
1406   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1407
1408   if (priv->simple)
1409     {
1410       self->ui_details->gui = empathy_builder_get_file (filename,
1411           "vbox_yahoo_simple", &self->ui_details->widget,
1412           NULL);
1413
1414       empathy_account_widget_handle_params (self,
1415           "entry_id_simple", "account",
1416           "entry_password_simple", "password",
1417           NULL);
1418
1419       self->ui_details->default_focus = g_strdup ("entry_id_simple");
1420     }
1421   else
1422     {
1423       self->ui_details->gui = empathy_builder_get_file (filename,
1424           "table_common_settings", &priv->table_common_settings,
1425           "vbox_yahoo_settings", &self->ui_details->widget,
1426           NULL);
1427
1428       empathy_account_widget_handle_params (self,
1429           "entry_id", "account",
1430           "entry_password", "password",
1431           "entry_server", "server",
1432           "entry_locale", "room-list-locale",
1433           "entry_charset", "charset",
1434           "spinbutton_port", "port",
1435           "checkbutton_ignore_invites", "ignore-invites",
1436           NULL);
1437
1438       self->ui_details->default_focus = g_strdup ("entry_id");
1439     }
1440 }
1441
1442 static void
1443 account_widget_build_groupwise (EmpathyAccountWidget *self,
1444     const char *filename)
1445 {
1446   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1447
1448   if (priv->simple)
1449     {
1450       self->ui_details->gui = empathy_builder_get_file (filename,
1451           "vbox_groupwise_simple", &self->ui_details->widget,
1452           NULL);
1453
1454       empathy_account_widget_handle_params (self,
1455           "entry_id_simple", "account",
1456           "entry_password_simple", "password",
1457           NULL);
1458
1459       self->ui_details->default_focus = g_strdup ("entry_id_simple");
1460     }
1461   else
1462     {
1463       self->ui_details->gui = empathy_builder_get_file (filename,
1464           "table_common_groupwise_settings", &priv->table_common_settings,
1465           "vbox_groupwise_settings", &self->ui_details->widget,
1466           NULL);
1467
1468       empathy_account_widget_handle_params (self,
1469           "entry_id", "account",
1470           "entry_password", "password",
1471           "entry_server", "server",
1472           "spinbutton_port", "port",
1473           NULL);
1474
1475       self->ui_details->default_focus = g_strdup ("entry_id");
1476     }
1477 }
1478
1479 static void
1480 account_widget_destroy_cb (GtkWidget *widget,
1481     EmpathyAccountWidget *self)
1482 {
1483   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1484   /* set the destroyed flag - workaround */
1485   priv->destroyed = TRUE;
1486
1487   g_object_unref (self);
1488 }
1489
1490 static void
1491 empathy_account_widget_enabled_cb (TpAccount *account,
1492       GParamSpec *spec,
1493       gpointer user_data)
1494 {
1495   EmpathyAccountWidget *widget = EMPATHY_ACCOUNT_WIDGET (user_data);
1496   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
1497   gboolean enabled = tp_account_is_enabled (account);
1498
1499   if (priv->enabled_checkbox != NULL)
1500     {
1501 #ifdef HAVE_MEEGO
1502       mx_gtk_light_switch_set_active (
1503           MX_GTK_LIGHT_SWITCH (priv->enabled_checkbox),
1504           enabled);
1505 #else
1506       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->enabled_checkbox),
1507           enabled);
1508 #endif /* HAVE_MEEGO */
1509     }
1510 }
1511
1512 static void
1513 #ifdef HAVE_MEEGO
1514 account_widget_switch_flipped_cb (MxGtkLightSwitch *sw,
1515     gboolean state,
1516     gpointer user_data)
1517 #else
1518 account_widget_enabled_toggled_cb (GtkToggleButton *toggle_button,
1519     gpointer user_data)
1520 #endif /* HAVE_MEEGO */
1521 {
1522   EmpathyAccountWidgetPriv *priv = GET_PRIV (user_data);
1523   TpAccount *account;
1524 #ifndef HAVE_MEEGO
1525   gboolean state;
1526
1527   state = gtk_toggle_button_get_active (toggle_button);
1528 #endif /* HAVE_MEEGO */
1529
1530   account = empathy_account_settings_get_account (priv->settings);
1531
1532   /* Enable the account according to the value of the "Enabled" checkbox */
1533   /* workaround to keep widget alive during async call */
1534   g_object_ref (user_data);
1535   tp_account_set_enabled_async (account, state,
1536       account_widget_account_enabled_cb, user_data);
1537 }
1538
1539 void
1540 empathy_account_widget_set_other_accounts_exist (EmpathyAccountWidget *self,
1541     gboolean others_exist)
1542 {
1543   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1544
1545   priv->other_accounts_exist = others_exist;
1546
1547   if (priv->creating_account)
1548     account_widget_handle_control_buttons_sensitivity (self);
1549 }
1550
1551 static void
1552 do_set_property (GObject *object,
1553     guint prop_id,
1554     const GValue *value,
1555     GParamSpec *pspec)
1556 {
1557   EmpathyAccountWidgetPriv *priv = GET_PRIV (object);
1558
1559   switch (prop_id)
1560     {
1561     case PROP_SETTINGS:
1562       priv->settings = g_value_dup_object (value);
1563       break;
1564     case PROP_SIMPLE:
1565       priv->simple = g_value_get_boolean (value);
1566       break;
1567     case PROP_CREATING_ACCOUNT:
1568       priv->creating_account = g_value_get_boolean (value);
1569       break;
1570     case PROP_OTHER_ACCOUNTS_EXIST:
1571       empathy_account_widget_set_other_accounts_exist (
1572           EMPATHY_ACCOUNT_WIDGET (object), g_value_get_boolean (value));
1573       break;
1574     default:
1575       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1576     }
1577 }
1578
1579 static void
1580 do_get_property (GObject *object,
1581     guint prop_id,
1582     GValue *value,
1583     GParamSpec *pspec)
1584 {
1585   EmpathyAccountWidgetPriv *priv = GET_PRIV (object);
1586
1587   switch (prop_id)
1588     {
1589     case PROP_PROTOCOL:
1590       g_value_set_string (value,
1591         empathy_account_settings_get_protocol (priv->settings));
1592       break;
1593     case PROP_SETTINGS:
1594       g_value_set_object (value, priv->settings);
1595       break;
1596     case PROP_SIMPLE:
1597       g_value_set_boolean (value, priv->simple);
1598       break;
1599     case PROP_CREATING_ACCOUNT:
1600       g_value_set_boolean (value, priv->creating_account);
1601       break;
1602     case PROP_OTHER_ACCOUNTS_EXIST:
1603       g_value_set_boolean (value, priv->other_accounts_exist);
1604       break;
1605     default:
1606       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1607     }
1608 }
1609
1610 static void
1611 set_apply_button (EmpathyAccountWidget *self)
1612 {
1613   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1614   GtkWidget *image;
1615
1616   /* We can't use the stock button as its accelerator ('A') clashes with the
1617    * Add button. */
1618   gtk_button_set_use_stock (GTK_BUTTON (priv->apply_button), FALSE);
1619
1620   gtk_button_set_label (GTK_BUTTON (priv->apply_button), _("A_pply"));
1621   gtk_button_set_use_underline (GTK_BUTTON (priv->apply_button), TRUE);
1622
1623   image = gtk_image_new_from_stock (GTK_STOCK_APPLY, GTK_ICON_SIZE_BUTTON);
1624   gtk_button_set_image (GTK_BUTTON (priv->apply_button), image);
1625 }
1626
1627 static void
1628 presence_changed_cb (TpAccountManager *manager,
1629     TpConnectionPresenceType state,
1630     const gchar *status,
1631     const gchar *message,
1632     EmpathyAccountWidget *self)
1633 {
1634   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1635
1636   if (priv->destroyed)
1637     return;
1638
1639   if (priv->apply_button == NULL)
1640     /* This button doesn't exist in 'simple' mode */
1641     return;
1642
1643   if (state > TP_CONNECTION_PRESENCE_TYPE_OFFLINE &&
1644       priv->creating_account)
1645     {
1646       /* We are online and creating a new account, display a Login button */
1647       GtkWidget *image;
1648
1649       gtk_button_set_use_stock (GTK_BUTTON (priv->apply_button), FALSE);
1650       gtk_button_set_label (GTK_BUTTON (priv->apply_button), _("L_og in"));
1651
1652       image = gtk_image_new_from_stock (GTK_STOCK_CONNECT,
1653           GTK_ICON_SIZE_BUTTON);
1654       gtk_button_set_image (GTK_BUTTON (priv->apply_button), image);
1655     }
1656   else
1657     {
1658       /* We are offline or modifying an existing account, display
1659        * a Save button */
1660       set_apply_button (self);
1661     }
1662 }
1663
1664 static void
1665 account_manager_ready_cb (GObject *source_object,
1666     GAsyncResult *result,
1667     gpointer user_data)
1668 {
1669   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (user_data);
1670   TpAccountManager *account_manager = TP_ACCOUNT_MANAGER (source_object);
1671   GError *error = NULL;
1672   TpConnectionPresenceType state;
1673
1674   if (!tp_account_manager_prepare_finish (account_manager, result, &error))
1675     {
1676       DEBUG ("Failed to prepare account manager: %s", error->message);
1677       g_error_free (error);
1678       goto out;
1679     }
1680
1681   state = tp_account_manager_get_most_available_presence (account_manager, NULL,
1682       NULL);
1683
1684   /* simulate a presence change so the apply button will be changed
1685    * if needed */
1686   presence_changed_cb (account_manager, state, NULL, NULL, self);
1687
1688 out:
1689   g_object_unref (self);
1690 }
1691
1692 #define WIDGET(cm, proto) \
1693   { #cm, #proto, "empathy-account-widget-"#proto".ui", \
1694     account_widget_build_##proto }
1695
1696 static void
1697 add_enable_checkbox (EmpathyAccountWidget *self,
1698     TpAccount *account)
1699 {
1700   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1701 #ifdef HAVE_MEEGO
1702   GtkWidget *w;
1703 #else
1704   GtkWidget *vbox = self->ui_details->widget;
1705 #endif /* HAVE_MEEGO */
1706   guint nb_rows, nb_columns;
1707   gboolean is_enabled;
1708
1709   /* handle the "Enabled" checkbox. We only add it when modifying an account */
1710   if (priv->creating_account || priv->table_common_settings == NULL)
1711     return;
1712
1713   is_enabled = tp_account_is_enabled (account);
1714
1715 #ifdef HAVE_MEEGO
1716   w = gtk_label_new (_("Account:"));
1717   gtk_misc_set_alignment (GTK_MISC (w), 0, 0.5);
1718
1719   priv->enabled_checkbox = mx_gtk_light_switch_new ();
1720
1721   mx_gtk_light_switch_set_active (
1722       MX_GTK_LIGHT_SWITCH (priv->enabled_checkbox), is_enabled);
1723
1724   gtk_widget_show (w);
1725 #else
1726   priv->enabled_checkbox =
1727       gtk_check_button_new_with_mnemonic (_("_Enabled"));
1728
1729   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->enabled_checkbox),
1730       is_enabled);
1731 #endif /* HAVE_MEEGO */
1732
1733   g_object_get (priv->table_common_settings, "n-rows", &nb_rows,
1734       "n-columns", &nb_columns, NULL);
1735
1736   gtk_table_resize (GTK_TABLE (priv->table_common_settings), ++nb_rows,
1737       nb_columns);
1738
1739 #ifdef HAVE_MEEGO
1740   gtk_table_attach (GTK_TABLE (priv->table_common_settings),
1741       w,
1742       0, 1, nb_rows - 1, nb_rows,
1743       GTK_FILL, 0, 0, 0);
1744   gtk_table_attach (GTK_TABLE (priv->table_common_settings),
1745       priv->enabled_checkbox,
1746       1, nb_columns, nb_rows - 1, nb_rows,
1747       GTK_EXPAND | GTK_FILL, 0, 0, 0);
1748 #else
1749   gtk_box_pack_start (GTK_BOX (vbox), priv->enabled_checkbox, FALSE, FALSE, 0);
1750   gtk_box_reorder_child (GTK_BOX (vbox), priv->enabled_checkbox, 0);
1751 #endif /* HAVE_MEEGO */
1752
1753   gtk_widget_show (priv->enabled_checkbox);
1754
1755 #ifdef HAVE_MEEGO
1756   g_signal_connect (G_OBJECT (priv->enabled_checkbox), "switch-flipped",
1757       G_CALLBACK (account_widget_switch_flipped_cb), self);
1758 #else
1759   g_signal_connect (G_OBJECT (priv->enabled_checkbox), "toggled",
1760       G_CALLBACK (account_widget_enabled_toggled_cb), self);
1761 #endif /* HAVE_MEEGO */
1762 }
1763
1764 #ifndef HAVE_MEEGO
1765 /* Meego doesn't support registration */
1766 static void
1767 add_register_buttons (EmpathyAccountWidget *self,
1768     TpAccount *account)
1769 {
1770   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1771   const TpConnectionManagerProtocol *protocol;
1772   GtkWidget *radiobutton_register;
1773   GtkWidget *vbox = self->ui_details->widget;
1774
1775   if (!priv->creating_account)
1776     return;
1777
1778   protocol = empathy_account_settings_get_tp_protocol (priv->settings);
1779   if (protocol == NULL)
1780     return;
1781
1782   if (!tp_connection_manager_protocol_can_register (protocol))
1783     return;
1784
1785   if (account_widget_is_gtalk (self) || account_widget_is_facebook (self))
1786     return;
1787
1788   if (priv->simple)
1789     return;
1790
1791   priv->radiobutton_reuse = gtk_radio_button_new_with_label (NULL,
1792       _("This account already exists on the server"));
1793   radiobutton_register = gtk_radio_button_new_with_label (
1794       gtk_radio_button_get_group (GTK_RADIO_BUTTON (priv->radiobutton_reuse)),
1795       _("Create a new account on the server"));
1796
1797   gtk_box_pack_start (GTK_BOX (vbox), priv->radiobutton_reuse, FALSE, FALSE, 0);
1798   gtk_box_pack_start (GTK_BOX (vbox), radiobutton_register, FALSE, FALSE, 0);
1799   gtk_box_reorder_child (GTK_BOX (vbox), priv->radiobutton_reuse, 0);
1800   gtk_box_reorder_child (GTK_BOX (vbox), radiobutton_register, 1);
1801   gtk_widget_show (priv->radiobutton_reuse);
1802   gtk_widget_show (radiobutton_register);
1803 }
1804 #endif /* HAVE_MEEGO */
1805
1806 static void
1807 do_constructed (GObject *obj)
1808 {
1809   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
1810   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1811   TpAccount *account;
1812   const gchar *display_name, *default_display_name;
1813   guint i = 0;
1814   struct {
1815     const gchar *cm_name;
1816     const gchar *protocol;
1817     const char *file;
1818     void (*func)(EmpathyAccountWidget *self, const gchar *filename);
1819   } widgets [] = {
1820     { "salut", "local-xmpp", "empathy-account-widget-local-xmpp.ui",
1821         account_widget_build_salut },
1822     WIDGET (gabble, jabber),
1823     WIDGET (butterfly, msn),
1824     WIDGET (haze, icq),
1825     WIDGET (haze, aim),
1826     WIDGET (haze, yahoo),
1827     WIDGET (haze, groupwise),
1828     WIDGET (idle, irc),
1829     WIDGET (sofiasip, sip),
1830   };
1831
1832   account = empathy_account_settings_get_account (priv->settings);
1833
1834   /* Empathy can only edit accounts without the Cannot_Set_Parameters flag */
1835   if (tp_account_get_storage_restrictions (account) &
1836       TP_STORAGE_RESTRICTION_FLAG_CANNOT_SET_PARAMETERS)
1837     {
1838       DEBUG ("Account is provided by an external storage provider");
1839
1840       account_widget_build_external (self, priv->settings);
1841     }
1842   else
1843     {
1844       const gchar *protocol, *cm_name;
1845
1846       cm_name = empathy_account_settings_get_cm (priv->settings);
1847       protocol = empathy_account_settings_get_protocol (priv->settings);
1848
1849       for (i = 0 ; i < G_N_ELEMENTS (widgets); i++)
1850         {
1851           if (!tp_strdiff (widgets[i].cm_name, cm_name) &&
1852               !tp_strdiff (widgets[i].protocol, protocol))
1853             {
1854               gchar *filename;
1855
1856               filename = empathy_file_lookup (widgets[i].file,
1857                   "libempathy-gtk");
1858               widgets[i].func (self, filename);
1859               g_free (filename);
1860
1861               break;
1862             }
1863         }
1864
1865       if (i == G_N_ELEMENTS (widgets))
1866         {
1867           gchar *filename = empathy_file_lookup (
1868               "empathy-account-widget-generic.ui", "libempathy-gtk");
1869           account_widget_build_generic (self, filename);
1870           g_free (filename);
1871         }
1872     }
1873
1874   /* handle default focus */
1875   if (self->ui_details->default_focus != NULL)
1876     {
1877       GObject *default_focus_entry;
1878
1879       default_focus_entry = gtk_builder_get_object
1880         (self->ui_details->gui, self->ui_details->default_focus);
1881       g_signal_connect (default_focus_entry, "realize",
1882           G_CALLBACK (gtk_widget_grab_focus),
1883           NULL);
1884     }
1885
1886   /* dup and init the account-manager */
1887   priv->account_manager = tp_account_manager_dup ();
1888
1889   g_object_ref (self);
1890   tp_account_manager_prepare_async (priv->account_manager, NULL,
1891       account_manager_ready_cb, self);
1892
1893   /* handle apply and cancel button */
1894   if (!priv->simple &&
1895       !(tp_account_get_storage_restrictions (account) &
1896         TP_STORAGE_RESTRICTION_FLAG_CANNOT_SET_PARAMETERS))
1897     {
1898       GtkWidget *hbox = gtk_hbox_new (TRUE, 3);
1899       GtkWidget *image;
1900
1901       /*  We can't use the stock button as its accelerator ('C') clashes with
1902        *  the Close button. */
1903       priv->cancel_button = gtk_button_new ();
1904       gtk_button_set_label (GTK_BUTTON (priv->cancel_button), _("Ca_ncel"));
1905       gtk_button_set_use_underline (GTK_BUTTON (priv->cancel_button), TRUE);
1906
1907       image = gtk_image_new_from_stock (GTK_STOCK_CANCEL, GTK_ICON_SIZE_BUTTON);
1908       gtk_button_set_image (GTK_BUTTON (priv->cancel_button), image);
1909
1910       priv->apply_button = gtk_button_new ();
1911       set_apply_button (self);
1912
1913       /* We'll change this button to a "Log in" one if we are creating a new
1914        * account and are connected. */
1915       tp_g_signal_connect_object (priv->account_manager,
1916           "most-available-presence-changed",
1917           G_CALLBACK (presence_changed_cb), obj, 0);
1918
1919       gtk_box_pack_end (GTK_BOX (hbox), priv->apply_button, TRUE,
1920           TRUE, 3);
1921       gtk_box_pack_end (GTK_BOX (hbox), priv->cancel_button, TRUE,
1922           TRUE, 3);
1923
1924       gtk_box_pack_end (GTK_BOX (self->ui_details->widget), hbox, FALSE,
1925           FALSE, 3);
1926
1927       g_signal_connect (priv->cancel_button, "clicked",
1928           G_CALLBACK (account_widget_cancel_clicked_cb),
1929           self);
1930       g_signal_connect (priv->apply_button, "clicked",
1931           G_CALLBACK (account_widget_apply_clicked_cb),
1932           self);
1933       gtk_widget_show_all (hbox);
1934
1935       if (priv->creating_account)
1936         /* When creating an account, the user might have nothing to enter.
1937          * That means that no control interaction might occur,
1938          * so we update the control button sensitivity manually.
1939          */
1940         account_widget_handle_control_buttons_sensitivity (self);
1941       else
1942         account_widget_set_control_buttons_sensitivity (self, FALSE);
1943     }
1944
1945   if (account != NULL)
1946     {
1947       g_signal_connect (account, "notify::enabled",
1948           G_CALLBACK (empathy_account_widget_enabled_cb), self);
1949     }
1950
1951 #ifndef HAVE_MEEGO
1952   add_register_buttons (self, account);
1953 #endif /* HAVE_MEEGO */
1954
1955   /* add the Enable checkbox to accounts that support it */
1956   if (!(tp_account_get_storage_restrictions (account) &
1957       TP_STORAGE_RESTRICTION_FLAG_CANNOT_SET_ENABLED))
1958     add_enable_checkbox (self, account);
1959
1960   /* hook up to widget destruction to unref ourselves */
1961   g_signal_connect (self->ui_details->widget, "destroy",
1962       G_CALLBACK (account_widget_destroy_cb), self);
1963
1964   if (self->ui_details->gui != NULL)
1965     {
1966       empathy_builder_unref_and_keep_widget (self->ui_details->gui,
1967           self->ui_details->widget);
1968       self->ui_details->gui = NULL;
1969     }
1970
1971   display_name = empathy_account_settings_get_display_name (priv->settings);
1972   default_display_name = empathy_account_widget_get_default_display_name (self);
1973
1974   if (tp_strdiff (display_name, default_display_name) &&
1975       !priv->creating_account)
1976     {
1977       /* The display name of the account is not the one that we'd assign by
1978        * default; assume that the user changed it manually */
1979       g_object_set (priv->settings, "display-name-overridden", TRUE, NULL);
1980     }
1981 }
1982
1983 static void
1984 do_dispose (GObject *obj)
1985 {
1986   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
1987   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1988
1989   if (priv->dispose_run)
1990     return;
1991
1992   priv->dispose_run = TRUE;
1993
1994   if (priv->settings != NULL)
1995     {
1996       TpAccount *account;
1997       account = empathy_account_settings_get_account (priv->settings);
1998
1999       if (account != NULL)
2000         {
2001           g_signal_handlers_disconnect_by_func (account,
2002               empathy_account_widget_enabled_cb, self);
2003         }
2004
2005       g_object_unref (priv->settings);
2006       priv->settings = NULL;
2007     }
2008
2009   if (priv->account_manager != NULL)
2010     {
2011       g_object_unref (priv->account_manager);
2012       priv->account_manager = NULL;
2013     }
2014
2015   if (G_OBJECT_CLASS (empathy_account_widget_parent_class)->dispose != NULL)
2016     G_OBJECT_CLASS (empathy_account_widget_parent_class)->dispose (obj);
2017 }
2018
2019 static void
2020 do_finalize (GObject *obj)
2021 {
2022   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
2023
2024   g_free (self->ui_details->default_focus);
2025   g_slice_free (EmpathyAccountWidgetUIDetails, self->ui_details);
2026
2027   if (G_OBJECT_CLASS (empathy_account_widget_parent_class)->finalize != NULL)
2028     G_OBJECT_CLASS (empathy_account_widget_parent_class)->finalize (obj);
2029 }
2030
2031 static void
2032 empathy_account_widget_class_init (EmpathyAccountWidgetClass *klass)
2033 {
2034   GObjectClass *oclass = G_OBJECT_CLASS (klass);
2035   GParamSpec *param_spec;
2036
2037   oclass->get_property = do_get_property;
2038   oclass->set_property = do_set_property;
2039   oclass->constructed = do_constructed;
2040   oclass->dispose = do_dispose;
2041   oclass->finalize = do_finalize;
2042
2043   param_spec = g_param_spec_string ("protocol",
2044       "protocol", "The protocol of the account",
2045       NULL,
2046       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
2047   g_object_class_install_property (oclass, PROP_PROTOCOL, param_spec);
2048
2049   param_spec = g_param_spec_object ("settings",
2050       "settings", "The settings of the account",
2051       EMPATHY_TYPE_ACCOUNT_SETTINGS,
2052       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
2053   g_object_class_install_property (oclass, PROP_SETTINGS, param_spec);
2054
2055   param_spec = g_param_spec_boolean ("simple",
2056       "simple", "Whether the account widget is a simple or an advanced one",
2057       FALSE,
2058       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
2059   g_object_class_install_property (oclass, PROP_SIMPLE, param_spec);
2060
2061   param_spec = g_param_spec_boolean ("creating-account",
2062       "creating-account",
2063       "TRUE if we're creating an account, FALSE if we're modifying it",
2064       FALSE,
2065       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
2066   g_object_class_install_property (oclass, PROP_CREATING_ACCOUNT, param_spec);
2067
2068   param_spec = g_param_spec_boolean ("other-accounts-exist",
2069       "other-accounts-exist",
2070       "TRUE if there are any other accounts (even if this isn't yet saved)",
2071       FALSE,
2072       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
2073   g_object_class_install_property (oclass, PROP_OTHER_ACCOUNTS_EXIST,
2074                   param_spec);
2075
2076   signals[HANDLE_APPLY] =
2077     g_signal_new ("handle-apply", G_TYPE_FROM_CLASS (klass),
2078         G_SIGNAL_RUN_LAST, 0, NULL, NULL,
2079         g_cclosure_marshal_VOID__BOOLEAN,
2080         G_TYPE_NONE,
2081         1, G_TYPE_BOOLEAN);
2082
2083   /* This signal is emitted when an account has been created and enabled. */
2084   signals[ACCOUNT_CREATED] =
2085       g_signal_new ("account-created", G_TYPE_FROM_CLASS (klass),
2086           G_SIGNAL_RUN_LAST, 0, NULL, NULL,
2087           g_cclosure_marshal_VOID__OBJECT,
2088           G_TYPE_NONE,
2089           1, G_TYPE_OBJECT);
2090
2091   signals[CANCELLED] =
2092       g_signal_new ("cancelled", G_TYPE_FROM_CLASS (klass),
2093           G_SIGNAL_RUN_LAST, 0, NULL, NULL,
2094           g_cclosure_marshal_VOID__VOID,
2095           G_TYPE_NONE,
2096           0);
2097
2098   g_type_class_add_private (klass, sizeof (EmpathyAccountWidgetPriv));
2099 }
2100
2101 static void
2102 empathy_account_widget_init (EmpathyAccountWidget *self)
2103 {
2104   EmpathyAccountWidgetPriv *priv =
2105     G_TYPE_INSTANCE_GET_PRIVATE ((self), EMPATHY_TYPE_ACCOUNT_WIDGET,
2106         EmpathyAccountWidgetPriv);
2107
2108   self->priv = priv;
2109   priv->dispose_run = FALSE;
2110
2111   self->ui_details = g_slice_new0 (EmpathyAccountWidgetUIDetails);
2112 }
2113
2114 /* public methods */
2115
2116 void
2117 empathy_account_widget_discard_pending_changes
2118     (EmpathyAccountWidget *widget)
2119 {
2120   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
2121
2122   empathy_account_settings_discard_changes (priv->settings);
2123   priv->contains_pending_changes = FALSE;
2124 }
2125
2126 gboolean
2127 empathy_account_widget_contains_pending_changes (EmpathyAccountWidget *widget)
2128 {
2129   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
2130
2131   return priv->contains_pending_changes;
2132 }
2133
2134 void
2135 empathy_account_widget_handle_params (EmpathyAccountWidget *self,
2136     const gchar *first_widget,
2137     ...)
2138 {
2139   va_list args;
2140
2141   va_start (args, first_widget);
2142   account_widget_handle_params_valist (self, first_widget, args);
2143   va_end (args);
2144 }
2145
2146 GtkWidget *
2147 empathy_account_widget_get_widget (EmpathyAccountWidget *widget)
2148 {
2149   return widget->ui_details->widget;
2150 }
2151
2152 EmpathyAccountWidget *
2153 empathy_account_widget_new_for_protocol (EmpathyAccountSettings *settings,
2154     gboolean simple)
2155 {
2156   EmpathyAccountWidget *self;
2157
2158   g_return_val_if_fail (EMPATHY_IS_ACCOUNT_SETTINGS (settings), NULL);
2159
2160   self = g_object_new
2161     (EMPATHY_TYPE_ACCOUNT_WIDGET,
2162         "settings", settings, "simple", simple,
2163         "creating-account",
2164         empathy_account_settings_get_account (settings) == NULL,
2165         NULL);
2166
2167   return self;
2168 }
2169
2170 gchar *
2171 empathy_account_widget_get_default_display_name (EmpathyAccountWidget *self)
2172 {
2173   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
2174   const gchar *login_id;
2175   const gchar *protocol, *p;
2176   gchar *default_display_name;
2177
2178   login_id = empathy_account_settings_get_string (priv->settings, "account");
2179   protocol = empathy_account_settings_get_protocol (priv->settings);
2180
2181   if (login_id != NULL)
2182     {
2183       /* TODO: this should be done in empathy-account-widget-irc */
2184       if (!tp_strdiff (protocol, "irc"))
2185         {
2186           EmpathyIrcNetwork *network;
2187
2188           network = empathy_irc_network_chooser_get_network (
2189               priv->irc_network_chooser);
2190           g_assert (network != NULL);
2191
2192           /* To translators: The first parameter is the login id and the
2193            * second one is the network. The resulting string will be something
2194            * like: "MyUserName on freenode".
2195            * You should reverse the order of these arguments if the
2196            * server should come before the login id in your locale.*/
2197           default_display_name = g_strdup_printf (_("%1$s on %2$s"),
2198               login_id, empathy_irc_network_get_name (network));
2199         }
2200       else if (account_widget_is_facebook (self))
2201         {
2202           gchar *tmp;
2203
2204           tmp = remove_facebook_suffix (login_id);
2205           default_display_name = g_strdup_printf ("Facebook (%s)", tmp);
2206           g_free (tmp);
2207         }
2208       else
2209         {
2210           default_display_name = g_strdup (login_id);
2211         }
2212
2213       return default_display_name;
2214     }
2215
2216   if ((p = empathy_protocol_name_to_display_name (protocol)) != NULL)
2217     protocol = p;
2218
2219   if (protocol != NULL)
2220     {
2221       /* To translators: The parameter is the protocol name. The resulting
2222        * string will be something like: "Jabber Account" */
2223       default_display_name = g_strdup_printf (_("%s Account"), protocol);
2224     }
2225   else
2226     {
2227       default_display_name = g_strdup (_("New account"));
2228     }
2229
2230   return default_display_name;
2231 }
2232
2233 /* Used by subclass to indicate that widget contains pending changes */
2234 void
2235 empathy_account_widget_changed (EmpathyAccountWidget *self)
2236 {
2237   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
2238
2239   account_widget_handle_control_buttons_sensitivity (self);
2240   priv->contains_pending_changes = TRUE;
2241 }
2242
2243 void
2244 empathy_account_widget_set_account_param (EmpathyAccountWidget *self,
2245     const gchar *account)
2246 {
2247   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
2248
2249   if (priv->param_account_widget == NULL)
2250     return;
2251
2252   gtk_entry_set_text (GTK_ENTRY (priv->param_account_widget), account);
2253 }
2254
2255 void
2256 empathy_account_widget_set_password_param (EmpathyAccountWidget *self,
2257     const gchar *account)
2258 {
2259   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
2260
2261   if (priv->param_password_widget == NULL)
2262     return;
2263
2264   gtk_entry_set_text (GTK_ENTRY (priv->param_password_widget), account);
2265 }