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