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