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