]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-account-widget.c
account-widget: use empathy_account_widget_changed
[empathy.git] / libempathy-gtk / empathy-account-widget.c
1 /*
2  * Copyright (C) 2006-2007 Imendio AB
3  * Copyright (C) 2007-2009 Collabora Ltd.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA  02110-1301  USA
19  *
20  * Authors: Xavier Claessens <xclaesse@gmail.com>
21  *          Martyn Russell <martyn@imendio.com>
22  *          Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
23  *          Jonathan Tellier <jonathan.tellier@gmail.com>
24  */
25
26 #include <config.h>
27
28 #include <string.h>
29
30 #include <gtk/gtk.h>
31 #include <glib/gi18n-lib.h>
32
33 #ifdef HAVE_MOBLIN
34 #include <nbtk/nbtk-gtk.h>
35 #endif
36
37 #include <libempathy/empathy-utils.h>
38
39 #include <telepathy-glib/account.h>
40 #include <telepathy-glib/account-manager.h>
41 #include <telepathy-glib/connection-manager.h>
42 #include <telepathy-glib/util.h>
43 #include <dbus/dbus-protocol.h>
44
45 #include "empathy-account-widget.h"
46 #include "empathy-account-widget-private.h"
47 #include "empathy-account-widget-sip.h"
48 #include "empathy-account-widget-irc.h"
49 #include "empathy-ui-utils.h"
50
51 #define DEBUG_FLAG EMPATHY_DEBUG_ACCOUNT
52 #include <libempathy/empathy-debug.h>
53
54 G_DEFINE_TYPE (EmpathyAccountWidget, empathy_account_widget, G_TYPE_OBJECT)
55
56 typedef struct {
57   EmpathyAccountSettings *settings;
58
59   GtkWidget *table_common_settings;
60   GtkWidget *apply_button;
61   GtkWidget *cancel_button;
62   GtkWidget *entry_password;
63   GtkWidget *button_forget;
64   GtkWidget *spinbutton_port;
65   GtkWidget *enabled_checkbox;
66   GtkWidget *radiobutton_reuse;
67
68   gboolean simple;
69
70   gboolean contains_pending_changes;
71
72   /* An EmpathyAccountWidget can be used to either create an account or
73    * modify it. When we are creating an account, this member is set to TRUE */
74   gboolean creating_account;
75
76   /* if TRUE, the GTK+ destroy signal has been fired and so the widgets
77    * embedded in this account widget can't be used any more
78    * workaround because some async callbacks can be called after the
79    * widget has been destroyed */
80   gboolean destroyed;
81
82   TpAccountManager *account_manager;
83
84   gboolean dispose_run;
85 } EmpathyAccountWidgetPriv;
86
87 enum {
88   PROP_PROTOCOL = 1,
89   PROP_SETTINGS,
90   PROP_SIMPLE,
91   PROP_CREATING_ACCOUNT
92 };
93
94 enum {
95   HANDLE_APPLY,
96   ACCOUNT_CREATED,
97   CANCELLED,
98   LAST_SIGNAL
99 };
100
101 static guint signals[LAST_SIGNAL] = { 0 };
102
103 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccountWidget)
104 #define CHANGED_TIMEOUT 300
105
106 static void
107 account_widget_set_control_buttons_sensitivity (EmpathyAccountWidget *self,
108     gboolean sensitive)
109 {
110   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
111
112   if (!priv->simple)
113     {
114       gtk_widget_set_sensitive (priv->apply_button, sensitive);
115       gtk_widget_set_sensitive (
116           priv->cancel_button, sensitive || priv->creating_account);
117     }
118 }
119
120 static void
121 account_widget_handle_control_buttons_sensitivity (EmpathyAccountWidget *self)
122 {
123   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
124   gboolean is_valid;
125
126   is_valid = empathy_account_settings_is_valid (priv->settings);
127
128   if (!priv->simple)
129       account_widget_set_control_buttons_sensitivity (self, is_valid);
130
131   g_signal_emit (self, signals[HANDLE_APPLY], 0, is_valid);
132 }
133
134 static void
135 account_widget_entry_changed_common (EmpathyAccountWidget *self,
136     GtkEntry *entry, gboolean focus)
137 {
138   const gchar *str;
139   const gchar *param_name;
140   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
141
142   str = gtk_entry_get_text (entry);
143   param_name = g_object_get_data (G_OBJECT (entry), "param_name");
144
145   if (EMP_STR_EMPTY (str))
146     {
147       const gchar *value = NULL;
148
149       empathy_account_settings_unset (priv->settings, param_name);
150
151       if (focus)
152         {
153           value = empathy_account_settings_get_string (priv->settings,
154               param_name);
155           DEBUG ("Unset %s and restore to %s", param_name, value);
156           gtk_entry_set_text (entry, value ? value : "");
157         }
158     }
159   else
160     {
161       DEBUG ("Setting %s to %s", param_name,
162           tp_strdiff (param_name, "password") ? str : "***");
163       empathy_account_settings_set_string (priv->settings, param_name, str);
164     }
165 }
166
167 static void
168 account_widget_entry_changed_cb (GtkEditable *entry,
169     EmpathyAccountWidget *self)
170 {
171   account_widget_entry_changed_common (self, GTK_ENTRY (entry), FALSE);
172   empathy_account_widget_changed (self);
173 }
174
175 static void
176 account_widget_int_changed_cb (GtkWidget *widget,
177     EmpathyAccountWidget *self)
178 {
179   const gchar *param_name;
180   gint value;
181   const gchar *signature;
182   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
183
184   value = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
185   param_name = g_object_get_data (G_OBJECT (widget), "param_name");
186
187   signature = empathy_account_settings_get_dbus_signature (priv->settings,
188     param_name);
189   g_return_if_fail (signature != NULL);
190
191   DEBUG ("Setting %s to %d", param_name, value);
192
193   switch ((int)*signature)
194     {
195     case DBUS_TYPE_INT16:
196     case DBUS_TYPE_INT32:
197       empathy_account_settings_set_int32 (priv->settings, param_name, value);
198       break;
199     case DBUS_TYPE_INT64:
200       empathy_account_settings_set_int64 (priv->settings, param_name, value);
201       break;
202     case DBUS_TYPE_UINT16:
203     case DBUS_TYPE_UINT32:
204       empathy_account_settings_set_uint32 (priv->settings, param_name, value);
205       break;
206     case DBUS_TYPE_UINT64:
207       empathy_account_settings_set_uint64 (priv->settings, param_name, value);
208       break;
209     default:
210       g_return_if_reached ();
211     }
212
213   empathy_account_widget_changed (self);
214 }
215
216 static void
217 account_widget_checkbutton_toggled_cb (GtkWidget *widget,
218     EmpathyAccountWidget *self)
219 {
220   gboolean     value;
221   gboolean     default_value;
222   const gchar *param_name;
223   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
224
225   value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
226   param_name = g_object_get_data (G_OBJECT (widget), "param_name");
227
228   /* FIXME: This is ugly! checkbox don't have a "not-set" value so we
229    * always unset the param and set the value if different from the
230    * default value. */
231   empathy_account_settings_unset (priv->settings, param_name);
232   default_value = empathy_account_settings_get_boolean (priv->settings,
233       param_name);
234
235   if (default_value == value)
236     {
237       DEBUG ("Unset %s and restore to %d", param_name, default_value);
238     }
239   else
240     {
241       DEBUG ("Setting %s to %d", param_name, value);
242       empathy_account_settings_set_boolean (priv->settings, param_name, value);
243     }
244
245   empathy_account_widget_changed (self);
246 }
247
248 static void
249 account_widget_forget_clicked_cb (GtkWidget *button,
250     EmpathyAccountWidget *self)
251 {
252   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
253   const gchar *param_name;
254
255   param_name = g_object_get_data (G_OBJECT (priv->entry_password),
256       "param_name");
257
258   DEBUG ("Unset %s", param_name);
259   empathy_account_settings_unset (priv->settings, param_name);
260   gtk_entry_set_text (GTK_ENTRY (priv->entry_password), "");
261
262   empathy_account_widget_changed (self);
263 }
264
265 static void
266 account_widget_password_changed_cb (GtkWidget *entry,
267     EmpathyAccountWidget *self)
268 {
269   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
270   const gchar *str;
271
272   str = gtk_entry_get_text (GTK_ENTRY (entry));
273   gtk_widget_set_sensitive (priv->button_forget, !EMP_STR_EMPTY (str));
274
275   priv->contains_pending_changes = TRUE;
276 }
277
278 static void
279 account_widget_jabber_ssl_toggled_cb (GtkWidget *checkbutton_ssl,
280     EmpathyAccountWidget *self)
281 {
282   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
283   gboolean   value;
284   gint32       port = 0;
285
286   value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbutton_ssl));
287   port = empathy_account_settings_get_uint32 (priv->settings, "port");
288
289   if (value)
290     {
291       if (port == 5222 || port == 0)
292         port = 5223;
293     }
294   else
295     {
296       if (port == 5223 || port == 0)
297         port = 5222;
298     }
299
300   gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->spinbutton_port), port);
301
302   priv->contains_pending_changes = TRUE;
303 }
304
305 static void
306 account_widget_combobox_changed_cb (GtkWidget *widget,
307     EmpathyAccountWidget *self)
308 {
309   GtkTreeIter iter;
310   GtkTreeModel *model;
311   const gchar *value;
312   const GValue *v;
313   const gchar *default_value = NULL;
314   const gchar *param_name;
315   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
316
317   if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter))
318     return;
319
320   model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
321   /* the param value is stored in the first column */
322   gtk_tree_model_get (model, &iter, 0, &value, -1);
323
324   param_name = g_object_get_data (G_OBJECT (widget), "param_name");
325
326   v = empathy_account_settings_get_default (priv->settings, param_name);
327   if (v != NULL)
328     default_value = g_value_get_string (v);
329
330   if (!tp_strdiff (value, default_value))
331     {
332       DEBUG ("Unset %s and restore to %s", param_name, default_value);
333       empathy_account_settings_unset (priv->settings, param_name);
334     }
335   else
336     {
337       DEBUG ("Setting %s to %s", param_name, value);
338       empathy_account_settings_set_string (priv->settings, param_name, value);
339     }
340
341   empathy_account_widget_changed (self);
342 }
343
344 void
345 empathy_account_widget_setup_widget (EmpathyAccountWidget *self,
346     GtkWidget *widget,
347     const gchar *param_name)
348 {
349   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
350
351   g_object_set_data_full (G_OBJECT (widget), "param_name",
352       g_strdup (param_name), g_free);
353
354   if (GTK_IS_SPIN_BUTTON (widget))
355     {
356       gint value = 0;
357       const gchar *signature;
358
359       signature = empathy_account_settings_get_dbus_signature (priv->settings,
360           param_name);
361       g_return_if_fail (signature != NULL);
362
363       switch ((int)*signature)
364         {
365           case DBUS_TYPE_INT16:
366           case DBUS_TYPE_INT32:
367             value = empathy_account_settings_get_int32 (priv->settings,
368               param_name);
369             break;
370           case DBUS_TYPE_INT64:
371             value = empathy_account_settings_get_int64 (priv->settings,
372               param_name);
373             break;
374           case DBUS_TYPE_UINT16:
375           case DBUS_TYPE_UINT32:
376             value = empathy_account_settings_get_uint32 (priv->settings,
377               param_name);
378             break;
379           case DBUS_TYPE_UINT64:
380             value = empathy_account_settings_get_uint64 (priv->settings,
381                 param_name);
382             break;
383           default:
384             g_return_if_reached ();
385         }
386
387       gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
388
389       g_signal_connect (widget, "value-changed",
390           G_CALLBACK (account_widget_int_changed_cb),
391           self);
392     }
393   else if (GTK_IS_ENTRY (widget))
394     {
395       const gchar *str = NULL;
396
397       str = empathy_account_settings_get_string (priv->settings, param_name);
398       gtk_entry_set_text (GTK_ENTRY (widget), str ? str : "");
399
400       if (strstr (param_name, "password"))
401         {
402           gtk_entry_set_visibility (GTK_ENTRY (widget), FALSE);
403         }
404
405       g_signal_connect (widget, "changed",
406           G_CALLBACK (account_widget_entry_changed_cb), self);
407     }
408   else if (GTK_IS_TOGGLE_BUTTON (widget))
409     {
410       gboolean value = FALSE;
411
412       value = empathy_account_settings_get_boolean (priv->settings,
413           param_name);
414       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), value);
415
416       g_signal_connect (widget, "toggled",
417           G_CALLBACK (account_widget_checkbutton_toggled_cb),
418           self);
419     }
420   else if (GTK_IS_COMBO_BOX (widget))
421     {
422       /* The combo box's model has to contain the param value in its first
423        * column (as a string) */
424       const gchar *str;
425       GtkTreeModel *model;
426       GtkTreeIter iter;
427       gboolean valid;
428
429       str = empathy_account_settings_get_string (priv->settings, param_name);
430       model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
431
432       valid = gtk_tree_model_get_iter_first (model, &iter);
433       while (valid)
434         {
435           gchar *name;
436
437           gtk_tree_model_get (model, &iter, 0, &name, -1);
438           if (!tp_strdiff (name, str))
439             {
440               gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter);
441               valid = FALSE;
442             }
443           else
444             {
445               valid = gtk_tree_model_iter_next (model, &iter);
446             }
447
448           g_free (name);
449         }
450
451       g_signal_connect (widget, "changed",
452           G_CALLBACK (account_widget_combobox_changed_cb),
453           self);
454     }
455   else
456     {
457       DEBUG ("Unknown type of widget for param %s", param_name);
458     }
459 }
460
461 static gchar *
462 account_widget_generic_format_param_name (const gchar *param_name)
463 {
464   gchar *str;
465   gchar *p;
466
467   str = g_strdup (param_name);
468
469   if (str && g_ascii_isalpha (str[0]))
470     str[0] = g_ascii_toupper (str[0]);
471
472   while ((p = strchr (str, '-')) != NULL)
473     {
474       if (p[1] != '\0' && g_ascii_isalpha (p[1]))
475         {
476           p[0] = ' ';
477           p[1] = g_ascii_toupper (p[1]);
478         }
479
480       p++;
481     }
482
483   return str;
484 }
485
486 static void
487 accounts_widget_generic_setup (EmpathyAccountWidget *self,
488     GtkWidget *table_common_settings,
489     GtkWidget *table_advanced_settings)
490 {
491   TpConnectionManagerParam *params, *param;
492   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
493
494   params = empathy_account_settings_get_tp_params (priv->settings);
495
496   for (param = params; param != NULL && param->name != NULL; param++)
497     {
498       GtkWidget       *table_settings;
499       guint            n_rows = 0;
500       GtkWidget       *widget = NULL;
501       gchar           *param_name_formatted;
502
503       if (param->flags & TP_CONN_MGR_PARAM_FLAG_REQUIRED)
504         table_settings = table_common_settings;
505       else if (priv->simple)
506         return;
507       else
508         table_settings = table_advanced_settings;
509
510       param_name_formatted = account_widget_generic_format_param_name
511         (param->name);
512       g_object_get (table_settings, "n-rows", &n_rows, NULL);
513       gtk_table_resize (GTK_TABLE (table_settings), ++n_rows, 2);
514
515       if (param->dbus_signature[0] == 's')
516         {
517           gchar *str;
518
519           str = g_strdup_printf (_("%s:"), param_name_formatted);
520           widget = gtk_label_new (str);
521           gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
522           g_free (str);
523
524           gtk_table_attach (GTK_TABLE (table_settings),
525               widget,
526               0, 1,
527               n_rows - 1, n_rows,
528               GTK_FILL, 0,
529               0, 0);
530           gtk_widget_show (widget);
531
532           widget = gtk_entry_new ();
533           if (strcmp (param->name, "account") == 0)
534             {
535               g_signal_connect (widget, "realize",
536                   G_CALLBACK (gtk_widget_grab_focus),
537                   NULL);
538             }
539           gtk_table_attach (GTK_TABLE (table_settings),
540               widget,
541               1, 2,
542               n_rows - 1, n_rows,
543               GTK_FILL | GTK_EXPAND, 0,
544               0, 0);
545           gtk_widget_show (widget);
546         }
547       /* int types: ynqiuxt. double type is 'd' */
548       else if (param->dbus_signature[0] == 'y' ||
549           param->dbus_signature[0] == 'n' ||
550           param->dbus_signature[0] == 'q' ||
551           param->dbus_signature[0] == 'i' ||
552           param->dbus_signature[0] == 'u' ||
553           param->dbus_signature[0] == 'x' ||
554           param->dbus_signature[0] == 't' ||
555           param->dbus_signature[0] == 'd')
556         {
557           gchar   *str = NULL;
558           gdouble  minint = 0;
559           gdouble  maxint = 0;
560           gdouble  step = 1;
561
562           switch (param->dbus_signature[0])
563             {
564             case 'y': minint = G_MININT8;  maxint = G_MAXINT8;   break;
565             case 'n': minint = G_MININT16; maxint = G_MAXINT16;  break;
566             case 'q': minint = 0;          maxint = G_MAXUINT16; break;
567             case 'i': minint = G_MININT32; maxint = G_MAXINT32;  break;
568             case 'u': minint = 0;          maxint = G_MAXUINT32; break;
569             case 'x': minint = G_MININT64; maxint = G_MAXINT64;  break;
570             case 't': minint = 0;          maxint = G_MAXUINT64; break;
571             case 'd': minint = G_MININT32; maxint = G_MAXINT32;
572               step = 0.1; break;
573             }
574
575           str = g_strdup_printf (_("%s:"), param_name_formatted);
576           widget = gtk_label_new (str);
577           gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
578           g_free (str);
579
580           gtk_table_attach (GTK_TABLE (table_settings),
581               widget,
582               0, 1,
583               n_rows - 1, n_rows,
584               GTK_FILL, 0,
585               0, 0);
586           gtk_widget_show (widget);
587
588           widget = gtk_spin_button_new_with_range (minint, maxint, step);
589           gtk_table_attach (GTK_TABLE (table_settings),
590               widget,
591               1, 2,
592               n_rows - 1, n_rows,
593               GTK_FILL | GTK_EXPAND, 0,
594               0, 0);
595           gtk_widget_show (widget);
596         }
597       else if (param->dbus_signature[0] == 'b')
598         {
599           widget = gtk_check_button_new_with_label (param_name_formatted);
600           gtk_table_attach (GTK_TABLE (table_settings),
601               widget,
602               0, 2,
603               n_rows - 1, n_rows,
604               GTK_FILL | GTK_EXPAND, 0,
605               0, 0);
606           gtk_widget_show (widget);
607         }
608       else
609         {
610           DEBUG ("Unknown signature for param %s: %s",
611               param_name_formatted, param->dbus_signature);
612         }
613
614       if (widget)
615         empathy_account_widget_setup_widget (self, widget, param->name);
616
617       g_free (param_name_formatted);
618     }
619 }
620
621 static void
622 account_widget_handle_params_valist (EmpathyAccountWidget *self,
623     const gchar *first_widget,
624     va_list args)
625 {
626   GObject *object;
627   const gchar *name;
628
629   for (name = first_widget; name; name = va_arg (args, const gchar *))
630     {
631       const gchar *param_name;
632
633       param_name = va_arg (args, const gchar *);
634       object = gtk_builder_get_object (self->ui_details->gui, name);
635
636       if (!object)
637         {
638           g_warning ("Builder is missing object '%s'.", name);
639           continue;
640         }
641
642       empathy_account_widget_setup_widget (self, GTK_WIDGET (object),
643           param_name);
644     }
645 }
646
647 static void
648 account_widget_cancel_clicked_cb (GtkWidget *button,
649     EmpathyAccountWidget *self)
650 {
651   g_signal_emit (self, signals[CANCELLED], 0);
652 }
653
654 static void
655 account_widget_account_enabled_cb (GObject *source_object,
656     GAsyncResult *res,
657     gpointer user_data)
658 {
659   GError *error = NULL;
660   TpAccount *account = TP_ACCOUNT (source_object);
661   EmpathyAccountWidget *widget = EMPATHY_ACCOUNT_WIDGET (user_data);
662   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
663   TpConnectionPresenceType presence;
664   gchar *message = NULL;
665   gchar *status = NULL;
666
667   tp_account_set_enabled_finish (account, res, &error);
668
669   if (error != NULL)
670     {
671       DEBUG ("Could not enable the account: %s", error->message);
672       g_error_free (error);
673     }
674   else
675     {
676       /* only force presence if presence was offline, unknown or unset */
677       presence = tp_account_get_requested_presence (account, NULL, NULL);
678       switch (presence)
679         {
680         case TP_CONNECTION_PRESENCE_TYPE_OFFLINE:
681         case TP_CONNECTION_PRESENCE_TYPE_UNKNOWN:
682         case TP_CONNECTION_PRESENCE_TYPE_UNSET:
683           presence = tp_account_manager_get_most_available_presence (
684               priv->account_manager, &status, &message);
685           tp_account_request_presence_async (account, presence,
686               status, NULL, NULL, NULL);
687           break;
688         default:
689           /* do nothing if the presence is not offline */
690           break;
691         }
692     }
693
694   /* unref widget - part of the workaround */
695   g_object_unref (widget);
696   g_free (message);
697   g_free (status);
698 }
699
700 static void
701 account_widget_applied_cb (GObject *source_object,
702     GAsyncResult *res,
703     gpointer user_data)
704 {
705   GError *error = NULL;
706   TpAccount *account;
707   EmpathyAccountSettings *settings = EMPATHY_ACCOUNT_SETTINGS (source_object);
708   EmpathyAccountWidget *widget = EMPATHY_ACCOUNT_WIDGET (user_data);
709   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
710
711   empathy_account_settings_apply_finish (settings, res, &error);
712
713   if (error != NULL)
714     {
715       DEBUG ("Could not apply changes to account: %s", error->message);
716       g_error_free (error);
717       return;
718     }
719
720   account = empathy_account_settings_get_account (priv->settings);
721
722   if (account != NULL)
723     {
724       if (priv->creating_account)
725         {
726           /* By default, when an account is created, we enable it. */
727
728           /* workaround to keep widget alive during async call */
729           g_object_ref (widget);
730
731           tp_account_set_enabled_async (account, TRUE,
732               account_widget_account_enabled_cb, widget);
733           g_signal_emit (widget, signals[ACCOUNT_CREATED], 0, account);
734         }
735       else if (priv->enabled_checkbox != NULL)
736         {
737           gboolean enabled_checked;
738
739           enabled_checked =
740 #ifdef HAVE_MOBLIN
741             nbtk_gtk_light_switch_get_active (
742                 NBTK_GTK_LIGHT_SWITCH (priv->enabled_checkbox));
743 #else
744             gtk_toggle_button_get_active (
745                 GTK_TOGGLE_BUTTON (priv->enabled_checkbox));
746 #endif
747
748           if (tp_account_is_enabled (account) && enabled_checked)
749             {
750               /* After having applied changes to a user account, we
751                * automatically reconnect it. This is done so the new
752                * information entered by the user is validated on the server. */
753               tp_account_reconnect_async (account, NULL, NULL);
754             }
755         }
756     }
757
758   if (!priv->destroyed)
759     account_widget_set_control_buttons_sensitivity (widget, FALSE);
760
761   priv->contains_pending_changes = FALSE;
762
763   /* unref the widget - part of the workaround */
764   g_object_unref (widget);
765 }
766
767 static void
768 account_widget_apply_clicked_cb (GtkWidget *button,
769     EmpathyAccountWidget *self)
770 {
771   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
772
773   if (priv->radiobutton_reuse != NULL)
774     {
775       gboolean reuse = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
776             priv->radiobutton_reuse));
777
778       DEBUG ("Set register param: %d", !reuse);
779       empathy_account_settings_set_boolean (priv->settings, "register", !reuse);
780     }
781
782   /* workaround to keep widget alive during async call */
783   g_object_ref (self);
784   empathy_account_settings_apply_async (priv->settings,
785       account_widget_applied_cb, self);
786 }
787
788 static void
789 account_widget_setup_generic (EmpathyAccountWidget *self)
790 {
791   GtkWidget *table_common_settings;
792   GtkWidget *table_advanced_settings;
793
794   table_common_settings = GTK_WIDGET (gtk_builder_get_object
795       (self->ui_details->gui, "table_common_settings"));
796   table_advanced_settings = GTK_WIDGET (gtk_builder_get_object
797       (self->ui_details->gui, "table_advanced_settings"));
798
799   accounts_widget_generic_setup (self, table_common_settings,
800       table_advanced_settings);
801
802   g_object_unref (self->ui_details->gui);
803 }
804
805 static void
806 account_widget_settings_ready_cb (EmpathyAccountSettings *settings,
807     GParamSpec *pspec,
808     gpointer user_data)
809 {
810   EmpathyAccountWidget *self = user_data;
811   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
812
813   if (empathy_account_settings_is_ready (priv->settings))
814     account_widget_setup_generic (self);
815 }
816
817 static void
818 account_widget_build_generic (EmpathyAccountWidget *self,
819     const char *filename)
820 {
821   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
822   GtkWidget *expander_advanced;
823
824   self->ui_details->gui = empathy_builder_get_file (filename,
825       "table_common_settings", &priv->table_common_settings,
826       "vbox_generic_settings", &self->ui_details->widget,
827       "expander_advanced_settings", &expander_advanced,
828       NULL);
829
830   if (priv->simple)
831     gtk_widget_hide (expander_advanced);
832
833   g_object_ref (self->ui_details->gui);
834
835   if (empathy_account_settings_is_ready (priv->settings))
836     account_widget_setup_generic (self);
837   else
838     g_signal_connect (priv->settings, "notify::ready",
839         G_CALLBACK (account_widget_settings_ready_cb), self);
840 }
841
842 static void
843 account_widget_build_salut (EmpathyAccountWidget *self,
844     const char *filename)
845 {
846   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
847
848   self->ui_details->gui = empathy_builder_get_file (filename,
849       "table_common_settings", &priv->table_common_settings,
850       "vbox_salut_settings", &self->ui_details->widget,
851       NULL);
852
853   empathy_account_widget_handle_params (self,
854       "entry_published", "published-name",
855       "entry_nickname", "nickname",
856       "entry_first_name", "first-name",
857       "entry_last_name", "last-name",
858       "entry_email", "email",
859       "entry_jid", "jid",
860       NULL);
861
862   self->ui_details->default_focus = g_strdup ("entry_first_name");
863 }
864
865 static void
866 account_widget_build_irc (EmpathyAccountWidget *self,
867   const char *filename)
868 {
869   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
870   empathy_account_widget_irc_build (self, filename,
871     &priv->table_common_settings);
872 }
873
874 static void
875 account_widget_build_sip (EmpathyAccountWidget *self,
876   const char *filename)
877 {
878   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
879   empathy_account_widget_sip_build (self, filename,
880     &priv->table_common_settings);
881 }
882
883 static void
884 account_widget_build_msn (EmpathyAccountWidget *self,
885     const char *filename)
886 {
887   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
888
889   if (priv->simple)
890     {
891       self->ui_details->gui = empathy_builder_get_file (filename,
892           "vbox_msn_simple", &self->ui_details->widget,
893           NULL);
894
895       empathy_account_widget_handle_params (self,
896           "entry_id_simple", "account",
897           "entry_password_simple", "password",
898           NULL);
899
900       self->ui_details->default_focus = g_strdup ("entry_id_simple");
901     }
902   else
903     {
904       self->ui_details->gui = empathy_builder_get_file (filename,
905           "table_common_msn_settings", &priv->table_common_settings,
906           "vbox_msn_settings", &self->ui_details->widget,
907           NULL);
908
909       empathy_account_widget_handle_params (self,
910           "entry_id", "account",
911           "entry_password", "password",
912           "entry_server", "server",
913           "spinbutton_port", "port",
914           NULL);
915
916       self->ui_details->default_focus = g_strdup ("entry_id");
917       self->ui_details->add_forget = TRUE;
918     }
919 }
920
921 static gboolean
922 account_widget_is_gtalk (EmpathyAccountWidget *self)
923 {
924   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
925
926   return !tp_strdiff (empathy_account_settings_get_icon_name (priv->settings),
927       "im-google-talk");
928 }
929
930 static void
931 account_widget_build_jabber (EmpathyAccountWidget *self,
932     const char *filename)
933 {
934   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
935   GtkWidget *spinbutton_port;
936   GtkWidget *checkbutton_ssl;
937   GtkWidget *label_id, *label_password;
938   GtkWidget *label_id_create, *label_password_create;
939   GtkWidget *label_example_gtalk, *label_example_jabber;
940   gboolean is_gtalk;
941
942   is_gtalk = account_widget_is_gtalk (self);
943
944   if (priv->simple && !is_gtalk)
945     {
946       self->ui_details->gui = empathy_builder_get_file (filename,
947           "vbox_jabber_simple", &self->ui_details->widget,
948           "label_id_simple", &label_id,
949           "label_id_create", &label_id_create,
950           "label_password_simple", &label_password,
951           "label_password_create", &label_password_create,
952           NULL);
953
954       if (empathy_account_settings_get_boolean (priv->settings, "register"))
955         {
956           gtk_widget_hide (label_id);
957           gtk_widget_hide (label_password);
958           gtk_widget_show (label_id_create);
959           gtk_widget_show (label_password_create);
960         }
961
962       empathy_account_widget_handle_params (self,
963           "entry_id_simple", "account",
964           "entry_password_simple", "password",
965           NULL);
966
967       self->ui_details->default_focus = g_strdup ("entry_id_simple");
968     }
969   else if (priv->simple && is_gtalk)
970     {
971       self->ui_details->gui = empathy_builder_get_file (filename,
972           "vbox_gtalk_simple", &self->ui_details->widget,
973           NULL);
974
975       empathy_account_widget_handle_params (self,
976           "entry_id_g_simple", "account",
977           "entry_password_g_simple", "password",
978           NULL);
979
980       self->ui_details->default_focus = g_strdup ("entry_id_g_simple");
981     }
982   else
983     {
984       self->ui_details->gui = empathy_builder_get_file (filename,
985           "table_common_settings", &priv->table_common_settings,
986           "vbox_jabber_settings", &self->ui_details->widget,
987           "spinbutton_port", &spinbutton_port,
988           "checkbutton_ssl", &checkbutton_ssl,
989           "label_username_example", &label_example_jabber,
990           "label_username_g_example", &label_example_gtalk,
991           NULL);
992
993       empathy_account_widget_handle_params (self,
994           "entry_id", "account",
995           "entry_password", "password",
996           "entry_resource", "resource",
997           "entry_server", "server",
998           "spinbutton_port", "port",
999           "spinbutton_priority", "priority",
1000           "checkbutton_ssl", "old-ssl",
1001           "checkbutton_ignore_ssl_errors", "ignore-ssl-errors",
1002           "checkbutton_encryption", "require-encryption",
1003           NULL);
1004
1005       self->ui_details->default_focus = g_strdup ("entry_id");
1006       self->ui_details->add_forget = TRUE;
1007       priv->spinbutton_port = spinbutton_port;
1008
1009       g_signal_connect (checkbutton_ssl, "toggled",
1010           G_CALLBACK (account_widget_jabber_ssl_toggled_cb),
1011           self);
1012
1013       if (is_gtalk)
1014         {
1015           gtk_widget_hide (label_example_jabber);
1016           gtk_widget_show (label_example_gtalk);
1017         }
1018     }
1019 }
1020
1021 static void
1022 account_widget_build_icq (EmpathyAccountWidget *self,
1023     const char *filename)
1024 {
1025   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1026   GtkWidget *spinbutton_port;
1027
1028   if (priv->simple)
1029     {
1030       self->ui_details->gui = empathy_builder_get_file (filename,
1031           "vbox_icq_simple", &self->ui_details->widget,
1032           NULL);
1033
1034       empathy_account_widget_handle_params (self,
1035           "entry_uin_simple", "account",
1036           "entry_password_simple", "password",
1037           NULL);
1038
1039       self->ui_details->default_focus = g_strdup ("entry_uin_simple");
1040     }
1041   else
1042     {
1043       self->ui_details->gui = empathy_builder_get_file (filename,
1044           "table_common_settings", &priv->table_common_settings,
1045           "vbox_icq_settings", &self->ui_details->widget,
1046           "spinbutton_port", &spinbutton_port,
1047           NULL);
1048
1049       empathy_account_widget_handle_params (self,
1050           "entry_uin", "account",
1051           "entry_password", "password",
1052           "entry_server", "server",
1053           "spinbutton_port", "port",
1054           "entry_charset", "charset",
1055           NULL);
1056
1057       self->ui_details->default_focus = g_strdup ("entry_uin");
1058       self->ui_details->add_forget = TRUE;
1059     }
1060 }
1061
1062 static void
1063 account_widget_build_aim (EmpathyAccountWidget *self,
1064     const char *filename)
1065 {
1066   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1067   GtkWidget *spinbutton_port;
1068
1069   if (priv->simple)
1070     {
1071       self->ui_details->gui = empathy_builder_get_file (filename,
1072           "vbox_aim_simple", &self->ui_details->widget,
1073           NULL);
1074
1075       empathy_account_widget_handle_params (self,
1076           "entry_screenname_simple", "account",
1077           "entry_password_simple", "password",
1078           NULL);
1079
1080       self->ui_details->default_focus = g_strdup ("entry_screenname_simple");
1081     }
1082   else
1083     {
1084       self->ui_details->gui = empathy_builder_get_file (filename,
1085           "table_common_settings", &priv->table_common_settings,
1086           "vbox_aim_settings", &self->ui_details->widget,
1087           "spinbutton_port", &spinbutton_port,
1088           NULL);
1089
1090       empathy_account_widget_handle_params (self,
1091           "entry_screenname", "account",
1092           "entry_password", "password",
1093           "entry_server", "server",
1094           "spinbutton_port", "port",
1095           NULL);
1096
1097       self->ui_details->default_focus = g_strdup ("entry_screenname");
1098       self->ui_details->add_forget = TRUE;
1099     }
1100 }
1101
1102 static void
1103 account_widget_build_yahoo (EmpathyAccountWidget *self,
1104     const char *filename)
1105 {
1106   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1107
1108   if (priv->simple)
1109     {
1110       self->ui_details->gui = empathy_builder_get_file (filename,
1111           "vbox_yahoo_simple", &self->ui_details->widget,
1112           NULL);
1113
1114       empathy_account_widget_handle_params (self,
1115           "entry_id_simple", "account",
1116           "entry_password_simple", "password",
1117           NULL);
1118
1119       self->ui_details->default_focus = g_strdup ("entry_id_simple");
1120     }
1121   else
1122     {
1123       self->ui_details->gui = empathy_builder_get_file (filename,
1124           "table_common_settings", &priv->table_common_settings,
1125           "vbox_yahoo_settings", &self->ui_details->widget,
1126           NULL);
1127
1128       empathy_account_widget_handle_params (self,
1129           "entry_id", "account",
1130           "entry_password", "password",
1131           "entry_server", "server",
1132           "entry_locale", "room-list-locale",
1133           "entry_charset", "charset",
1134           "spinbutton_port", "port",
1135           "checkbutton_yahoojp", "yahoojp",
1136           "checkbutton_ignore_invites", "ignore-invites",
1137           NULL);
1138
1139       self->ui_details->default_focus = g_strdup ("entry_id");
1140       self->ui_details->add_forget = TRUE;
1141     }
1142 }
1143
1144 static void
1145 account_widget_build_groupwise (EmpathyAccountWidget *self,
1146     const char *filename)
1147 {
1148   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1149
1150   if (priv->simple)
1151     {
1152       self->ui_details->gui = empathy_builder_get_file (filename,
1153           "vbox_groupwise_simple", &self->ui_details->widget,
1154           NULL);
1155
1156       empathy_account_widget_handle_params (self,
1157           "entry_id_simple", "account",
1158           "entry_password_simple", "password",
1159           NULL);
1160
1161       self->ui_details->default_focus = g_strdup ("entry_id_simple");
1162     }
1163   else
1164     {
1165       self->ui_details->gui = empathy_builder_get_file (filename,
1166           "table_common_groupwise_settings", &priv->table_common_settings,
1167           "vbox_groupwise_settings", &self->ui_details->widget,
1168           NULL);
1169
1170       empathy_account_widget_handle_params (self,
1171           "entry_id", "account",
1172           "entry_password", "password",
1173           "entry_server", "server",
1174           "spinbutton_port", "port",
1175           NULL);
1176
1177       self->ui_details->default_focus = g_strdup ("entry_id");
1178       self->ui_details->add_forget = TRUE;
1179     }
1180 }
1181
1182 static void
1183 account_widget_destroy_cb (GtkWidget *widget,
1184     EmpathyAccountWidget *self)
1185 {
1186   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1187   /* set the destroyed flag - workaround */
1188   priv->destroyed = TRUE;
1189
1190   g_object_unref (self);
1191 }
1192
1193 static void
1194 empathy_account_widget_enabled_cb (TpAccount *account,
1195       GParamSpec *spec,
1196       gpointer user_data)
1197 {
1198   EmpathyAccountWidget *widget = EMPATHY_ACCOUNT_WIDGET (user_data);
1199   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
1200   gboolean enabled = tp_account_is_enabled (account);
1201
1202   if (priv->enabled_checkbox != NULL)
1203     {
1204 #ifdef HAVE_MOBLIN
1205       nbtk_gtk_light_switch_set_active (
1206           NBTK_GTK_LIGHT_SWITCH (priv->enabled_checkbox),
1207           enabled);
1208 #else
1209       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->enabled_checkbox),
1210           enabled);
1211 #endif /* HAVE_MOBLIN */
1212     }
1213 }
1214
1215 static void
1216 #ifdef HAVE_MOBLIN
1217 account_widget_switch_flipped_cb (NbtkGtkLightSwitch *sw,
1218     gboolean state,
1219     gpointer user_data)
1220 #else
1221 account_widget_enabled_released_cb (GtkToggleButton *toggle_button,
1222     gpointer user_data)
1223 #endif /* HAVE_MOBLIN */
1224 {
1225   EmpathyAccountWidgetPriv *priv = GET_PRIV (user_data);
1226   TpAccount *account;
1227 #ifndef HAVE_MOBLIN
1228   gboolean state;
1229
1230   state = gtk_toggle_button_get_active (toggle_button);
1231 #endif
1232
1233   account = empathy_account_settings_get_account (priv->settings);
1234
1235   /* Enable the account according to the value of the "Enabled" checkbox */
1236   /* workaround to keep widget alive during async call */
1237   g_object_ref (user_data);
1238   tp_account_set_enabled_async (account, state,
1239       account_widget_account_enabled_cb, user_data);
1240 }
1241
1242 static void
1243 do_set_property (GObject *object,
1244     guint prop_id,
1245     const GValue *value,
1246     GParamSpec *pspec)
1247 {
1248   EmpathyAccountWidgetPriv *priv = GET_PRIV (object);
1249
1250   switch (prop_id)
1251     {
1252     case PROP_SETTINGS:
1253       priv->settings = g_value_dup_object (value);
1254       break;
1255     case PROP_SIMPLE:
1256       priv->simple = g_value_get_boolean (value);
1257       break;
1258     case PROP_CREATING_ACCOUNT:
1259       priv->creating_account = g_value_get_boolean (value);
1260       break;
1261     default:
1262       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1263     }
1264 }
1265
1266 static void
1267 do_get_property (GObject *object,
1268     guint prop_id,
1269     GValue *value,
1270     GParamSpec *pspec)
1271 {
1272   EmpathyAccountWidgetPriv *priv = GET_PRIV (object);
1273
1274   switch (prop_id)
1275     {
1276     case PROP_PROTOCOL:
1277       g_value_set_string (value,
1278         empathy_account_settings_get_protocol (priv->settings));
1279       break;
1280     case PROP_SETTINGS:
1281       g_value_set_object (value, priv->settings);
1282       break;
1283     case PROP_SIMPLE:
1284       g_value_set_boolean (value, priv->simple);
1285       break;
1286     case PROP_CREATING_ACCOUNT:
1287       g_value_set_boolean (value, priv->creating_account);
1288       break;
1289     default:
1290       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1291     }
1292 }
1293
1294 static void
1295 presence_changed_cb (TpAccountManager *manager,
1296     TpConnectionPresenceType state,
1297     const gchar *status,
1298     const gchar *message,
1299     EmpathyAccountWidget *self)
1300 {
1301   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1302
1303   if (priv->destroyed)
1304     return;
1305
1306   if (state > TP_CONNECTION_PRESENCE_TYPE_OFFLINE)
1307     {
1308       /* We are online, display a Login button */
1309       GtkWidget *image;
1310
1311       gtk_button_set_use_stock (GTK_BUTTON (priv->apply_button), FALSE);
1312       gtk_button_set_label (GTK_BUTTON (priv->apply_button), _("L_og in"));
1313
1314       image = gtk_image_new_from_stock (GTK_STOCK_CONNECT,
1315           GTK_ICON_SIZE_BUTTON);
1316       gtk_button_set_image (GTK_BUTTON (priv->apply_button), image);
1317     }
1318   else
1319     {
1320       /* We are offline, display a Save button */
1321       gtk_button_set_image (GTK_BUTTON (priv->apply_button), NULL);
1322       gtk_button_set_use_stock (GTK_BUTTON (priv->apply_button), TRUE);
1323       gtk_button_set_label (GTK_BUTTON (priv->apply_button), GTK_STOCK_SAVE);
1324     }
1325 }
1326
1327 static void
1328 account_manager_ready_cb (GObject *source_object,
1329     GAsyncResult *result,
1330     gpointer user_data)
1331 {
1332   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (user_data);
1333   TpAccountManager *account_manager = TP_ACCOUNT_MANAGER (source_object);
1334   GError *error = NULL;
1335   TpConnectionPresenceType state;
1336
1337   if (!tp_account_manager_prepare_finish (account_manager, result, &error))
1338     {
1339       DEBUG ("Failed to prepare account manager: %s", error->message);
1340       g_error_free (error);
1341       goto out;
1342     }
1343
1344   state = tp_account_manager_get_most_available_presence (account_manager, NULL,
1345       NULL);
1346
1347   /* simulate a presence change so the apply button will be changed
1348    * if needed */
1349   presence_changed_cb (account_manager, state, NULL, NULL, self);
1350
1351 out:
1352   g_object_unref (self);
1353 }
1354
1355 #define WIDGET(cm, proto) \
1356   { #cm, #proto, "empathy-account-widget-"#proto".ui", \
1357     account_widget_build_##proto }
1358
1359 static void
1360 add_enable_checkbox (EmpathyAccountWidget *self,
1361     TpAccount *account)
1362 {
1363   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1364 #ifdef HAVE_MOBLIN
1365   GtkWidget *w;
1366 #else
1367   GtkWidget *vbox = self->ui_details->widget;
1368 #endif
1369   guint nb_rows, nb_columns;
1370   gboolean is_enabled;
1371
1372   /* handle the "Enabled" checkbox. We only add it when modifying an account */
1373   if (priv->creating_account || priv->table_common_settings == NULL)
1374     return;
1375
1376   is_enabled = tp_account_is_enabled (account);
1377
1378 #ifdef HAVE_MOBLIN
1379   w = gtk_label_new (_("Account:"));
1380   gtk_misc_set_alignment (GTK_MISC (w), 0, 0.5);
1381
1382   priv->enabled_checkbox = nbtk_gtk_light_switch_new ();
1383
1384   nbtk_gtk_light_switch_set_active (
1385       NBTK_GTK_LIGHT_SWITCH (priv->enabled_checkbox), is_enabled);
1386
1387   gtk_widget_show (w);
1388 #else
1389   priv->enabled_checkbox =
1390       gtk_check_button_new_with_label (_("Enabled"));
1391
1392   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->enabled_checkbox),
1393       is_enabled);
1394 #endif /* HAVE_MOBLIN */
1395
1396   g_object_get (priv->table_common_settings, "n-rows", &nb_rows,
1397       "n-columns", &nb_columns, NULL);
1398
1399   gtk_table_resize (GTK_TABLE (priv->table_common_settings), ++nb_rows,
1400       nb_columns);
1401
1402 #ifdef HAVE_MOBLIN
1403   gtk_table_attach (GTK_TABLE (priv->table_common_settings),
1404       w,
1405       0, 1, nb_rows - 1, nb_rows,
1406       GTK_FILL, 0, 0, 0);
1407   gtk_table_attach (GTK_TABLE (priv->table_common_settings),
1408       priv->enabled_checkbox,
1409       1, nb_columns, nb_rows - 1, nb_rows,
1410       GTK_EXPAND | GTK_FILL, 0, 0, 0);
1411 #else
1412   gtk_box_pack_start (GTK_BOX (vbox), priv->enabled_checkbox, FALSE, FALSE, 0);
1413   gtk_box_reorder_child (GTK_BOX (vbox), priv->enabled_checkbox, 0);
1414 #endif /* HAVE_MOBLIN */
1415
1416   gtk_widget_show (priv->enabled_checkbox);
1417
1418 #ifdef HAVE_MOBLIN
1419   g_signal_connect (G_OBJECT (priv->enabled_checkbox), "switch-flipped",
1420       G_CALLBACK (account_widget_switch_flipped_cb), self);
1421 #else
1422   g_signal_connect (G_OBJECT (priv->enabled_checkbox), "released",
1423       G_CALLBACK (account_widget_enabled_released_cb), self);
1424 #endif /* HAVE_MOBLIN */
1425 }
1426
1427 #ifndef HAVE_MOBLIN
1428 /* Moblin doesn't support registration */
1429 static void
1430 add_register_buttons (EmpathyAccountWidget *self,
1431     TpAccount *account)
1432 {
1433   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1434   const TpConnectionManagerProtocol *protocol;
1435   GtkWidget *radiobutton_register;
1436   GtkWidget *vbox = self->ui_details->widget;
1437
1438   if (!priv->creating_account)
1439     return;
1440
1441   protocol = empathy_account_settings_get_tp_protocol (priv->settings);
1442   if (protocol == NULL)
1443     return;
1444
1445   if (!tp_connection_manager_protocol_can_register (protocol))
1446     return;
1447
1448   if (account_widget_is_gtalk (self))
1449     return;
1450
1451   priv->radiobutton_reuse = gtk_radio_button_new_with_label (NULL,
1452       _("This account already exists on the server"));
1453   radiobutton_register = gtk_radio_button_new_with_label (
1454       gtk_radio_button_get_group (GTK_RADIO_BUTTON (priv->radiobutton_reuse)),
1455       _("Create a new account on the server"));
1456
1457   gtk_box_pack_start (GTK_BOX (vbox), priv->radiobutton_reuse, FALSE, FALSE, 0);
1458   gtk_box_pack_start (GTK_BOX (vbox), radiobutton_register, FALSE, FALSE, 0);
1459   gtk_box_reorder_child (GTK_BOX (vbox), priv->radiobutton_reuse, 0);
1460   gtk_box_reorder_child (GTK_BOX (vbox), radiobutton_register, 1);
1461   gtk_widget_show (priv->radiobutton_reuse);
1462   gtk_widget_show (radiobutton_register);
1463 }
1464 #endif
1465
1466 static void
1467 do_constructed (GObject *obj)
1468 {
1469   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
1470   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1471   TpAccount *account;
1472   const gchar *protocol, *cm_name;
1473   guint i = 0;
1474   struct {
1475     const gchar *cm_name;
1476     const gchar *protocol;
1477     const char *file;
1478     void (*func)(EmpathyAccountWidget *self, const gchar *filename);
1479   } widgets [] = {
1480     { "salut", "local-xmpp", "empathy-account-widget-local-xmpp.ui",
1481         account_widget_build_salut },
1482     WIDGET (gabble, jabber),
1483     WIDGET (butterfly, msn),
1484     WIDGET (haze, icq),
1485     WIDGET (haze, aim),
1486     WIDGET (haze, yahoo),
1487     WIDGET (haze, groupwise),
1488     WIDGET (idle, irc),
1489     WIDGET (sofiasip, sip),
1490   };
1491
1492   cm_name = empathy_account_settings_get_cm (priv->settings);
1493   protocol = empathy_account_settings_get_protocol (priv->settings);
1494
1495   for (i = 0 ; i < G_N_ELEMENTS (widgets); i++)
1496     {
1497       if (!tp_strdiff (widgets[i].cm_name, cm_name) &&
1498           !tp_strdiff (widgets[i].protocol, protocol))
1499         {
1500           gchar *filename;
1501
1502           filename = empathy_file_lookup (widgets[i].file,
1503               "libempathy-gtk");
1504           widgets[i].func (self, filename);
1505           g_free (filename);
1506
1507           break;
1508         }
1509     }
1510
1511   if (i == G_N_ELEMENTS (widgets))
1512     {
1513       gchar *filename = empathy_file_lookup (
1514           "empathy-account-widget-generic.ui", "libempathy-gtk");
1515       account_widget_build_generic (self, filename);
1516       g_free (filename);
1517     }
1518
1519   /* handle default focus */
1520   if (self->ui_details->default_focus != NULL)
1521     {
1522       GObject *default_focus_entry;
1523
1524       default_focus_entry = gtk_builder_get_object
1525         (self->ui_details->gui, self->ui_details->default_focus);
1526       g_signal_connect (default_focus_entry, "realize",
1527           G_CALLBACK (gtk_widget_grab_focus),
1528           NULL);
1529     }
1530
1531   /* handle forget button */
1532   if (self->ui_details->add_forget)
1533     {
1534       const gchar *password = NULL;
1535
1536       priv->button_forget = GTK_WIDGET (gtk_builder_get_object
1537           (self->ui_details->gui, "button_forget"));
1538       priv->entry_password = GTK_WIDGET (gtk_builder_get_object
1539           (self->ui_details->gui, "entry_password"));
1540
1541       password = empathy_account_settings_get_string (priv->settings,
1542           "password");
1543       gtk_widget_set_sensitive (priv->button_forget,
1544           !EMP_STR_EMPTY (password));
1545
1546       g_signal_connect (priv->button_forget, "clicked",
1547           G_CALLBACK (account_widget_forget_clicked_cb),
1548           self);
1549       g_signal_connect (priv->entry_password, "changed",
1550           G_CALLBACK (account_widget_password_changed_cb),
1551           self);
1552     }
1553
1554   /* dup and init the account-manager */
1555   priv->account_manager = tp_account_manager_dup ();
1556
1557   g_object_ref (self);
1558   tp_account_manager_prepare_async (priv->account_manager, NULL,
1559       account_manager_ready_cb, self);
1560
1561   /* handle apply and cancel button */
1562   if (!priv->simple)
1563     {
1564       GtkWidget *hbox = gtk_hbox_new (TRUE, 3);
1565
1566       priv->cancel_button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
1567
1568       if (priv->creating_account)
1569         {
1570           /* Assumre we are offline, display a Save button. We'll update
1571            * it once the account manager is ready if needed */
1572           priv->apply_button = gtk_button_new_from_stock (GTK_STOCK_SAVE);
1573
1574           empathy_signal_connect_weak (priv->account_manager,
1575               "most-available-presence-changed",
1576               G_CALLBACK (presence_changed_cb), obj);
1577         }
1578       else
1579         {
1580           /* We are editing an existing account, display an Apply button */
1581           priv->apply_button = gtk_button_new_from_stock (GTK_STOCK_APPLY);
1582         }
1583
1584       gtk_box_pack_end (GTK_BOX (hbox), priv->apply_button, TRUE,
1585           TRUE, 3);
1586       gtk_box_pack_end (GTK_BOX (hbox), priv->cancel_button, TRUE,
1587           TRUE, 3);
1588
1589       gtk_box_pack_end (GTK_BOX (self->ui_details->widget), hbox, FALSE,
1590           FALSE, 3);
1591
1592       g_signal_connect (priv->cancel_button, "clicked",
1593           G_CALLBACK (account_widget_cancel_clicked_cb),
1594           self);
1595       g_signal_connect (priv->apply_button, "clicked",
1596           G_CALLBACK (account_widget_apply_clicked_cb),
1597           self);
1598       gtk_widget_show_all (hbox);
1599
1600       if (priv->creating_account)
1601         /* When creating an account, the user might have nothing to enter.
1602          * That means that no control interaction might occur,
1603          * so we update the control button sensitivity manually.
1604          */
1605         account_widget_handle_control_buttons_sensitivity (self);
1606       else
1607         account_widget_set_control_buttons_sensitivity (self, FALSE);
1608     }
1609
1610   account = empathy_account_settings_get_account (priv->settings);
1611
1612   if (account != NULL)
1613     {
1614       g_signal_connect (account, "notify::enabled",
1615           G_CALLBACK (empathy_account_widget_enabled_cb), self);
1616     }
1617
1618 #ifndef HAVE_MOBLIN
1619   add_register_buttons (self, account);
1620 #endif
1621   add_enable_checkbox (self, account);
1622
1623   /* hook up to widget destruction to unref ourselves */
1624   g_signal_connect (self->ui_details->widget, "destroy",
1625       G_CALLBACK (account_widget_destroy_cb), self);
1626
1627   empathy_builder_unref_and_keep_widget (self->ui_details->gui,
1628       self->ui_details->widget);
1629   self->ui_details->gui = NULL;
1630 }
1631
1632 static void
1633 do_dispose (GObject *obj)
1634 {
1635   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
1636   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1637
1638   if (priv->dispose_run)
1639     return;
1640
1641   priv->dispose_run = TRUE;
1642
1643   empathy_account_settings_is_ready (priv->settings);
1644
1645   if (priv->settings != NULL)
1646     {
1647       TpAccount *account;
1648       account = empathy_account_settings_get_account (priv->settings);
1649
1650       if (account != NULL)
1651         {
1652           g_signal_handlers_disconnect_by_func (account,
1653               empathy_account_widget_enabled_cb, self);
1654         }
1655
1656       g_object_unref (priv->settings);
1657       priv->settings = NULL;
1658     }
1659
1660   if (priv->account_manager != NULL)
1661     {
1662       g_object_unref (priv->account_manager);
1663       priv->account_manager = NULL;
1664     }
1665
1666   if (G_OBJECT_CLASS (empathy_account_widget_parent_class)->dispose != NULL)
1667     G_OBJECT_CLASS (empathy_account_widget_parent_class)->dispose (obj);
1668 }
1669
1670 static void
1671 do_finalize (GObject *obj)
1672 {
1673   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
1674
1675   g_free (self->ui_details->default_focus);
1676   g_slice_free (EmpathyAccountWidgetUIDetails, self->ui_details);
1677
1678   if (G_OBJECT_CLASS (empathy_account_widget_parent_class)->finalize != NULL)
1679     G_OBJECT_CLASS (empathy_account_widget_parent_class)->finalize (obj);
1680 }
1681
1682 static void
1683 empathy_account_widget_class_init (EmpathyAccountWidgetClass *klass)
1684 {
1685   GObjectClass *oclass = G_OBJECT_CLASS (klass);
1686   GParamSpec *param_spec;
1687
1688   oclass->get_property = do_get_property;
1689   oclass->set_property = do_set_property;
1690   oclass->constructed = do_constructed;
1691   oclass->dispose = do_dispose;
1692   oclass->finalize = do_finalize;
1693
1694   param_spec = g_param_spec_string ("protocol",
1695       "protocol", "The protocol of the account",
1696       NULL,
1697       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
1698   g_object_class_install_property (oclass, PROP_PROTOCOL, param_spec);
1699
1700   param_spec = g_param_spec_object ("settings",
1701       "settings", "The settings of the account",
1702       EMPATHY_TYPE_ACCOUNT_SETTINGS,
1703       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
1704   g_object_class_install_property (oclass, PROP_SETTINGS, param_spec);
1705
1706   param_spec = g_param_spec_boolean ("simple",
1707       "simple", "Whether the account widget is a simple or an advanced one",
1708       FALSE,
1709       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
1710   g_object_class_install_property (oclass, PROP_SIMPLE, param_spec);
1711
1712   param_spec = g_param_spec_boolean ("creating-account",
1713       "creating-account",
1714       "TRUE if we're creating an account, FALSE if we're modifying it",
1715       FALSE,
1716       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
1717   g_object_class_install_property (oclass, PROP_CREATING_ACCOUNT, param_spec);
1718
1719   signals[HANDLE_APPLY] =
1720     g_signal_new ("handle-apply", G_TYPE_FROM_CLASS (klass),
1721         G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1722         g_cclosure_marshal_VOID__BOOLEAN,
1723         G_TYPE_NONE,
1724         1, G_TYPE_BOOLEAN);
1725
1726   /* This signal is emitted when an account has been created and enabled. */
1727   signals[ACCOUNT_CREATED] =
1728       g_signal_new ("account-created", G_TYPE_FROM_CLASS (klass),
1729           G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1730           g_cclosure_marshal_VOID__POINTER,
1731           G_TYPE_NONE,
1732           1, G_TYPE_OBJECT);
1733
1734   signals[CANCELLED] =
1735       g_signal_new ("cancelled", G_TYPE_FROM_CLASS (klass),
1736           G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1737           g_cclosure_marshal_VOID__VOID,
1738           G_TYPE_NONE,
1739           0);
1740
1741   g_type_class_add_private (klass, sizeof (EmpathyAccountWidgetPriv));
1742 }
1743
1744 static void
1745 empathy_account_widget_init (EmpathyAccountWidget *self)
1746 {
1747   EmpathyAccountWidgetPriv *priv =
1748     G_TYPE_INSTANCE_GET_PRIVATE ((self), EMPATHY_TYPE_ACCOUNT_WIDGET,
1749         EmpathyAccountWidgetPriv);
1750
1751   self->priv = priv;
1752   priv->dispose_run = FALSE;
1753
1754   self->ui_details = g_slice_new0 (EmpathyAccountWidgetUIDetails);
1755 }
1756
1757 /* public methods */
1758
1759 void
1760 empathy_account_widget_discard_pending_changes
1761     (EmpathyAccountWidget *widget)
1762 {
1763   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
1764
1765   empathy_account_settings_discard_changes (priv->settings);
1766   priv->contains_pending_changes = FALSE;
1767 }
1768
1769 gboolean
1770 empathy_account_widget_contains_pending_changes (EmpathyAccountWidget *widget)
1771 {
1772   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
1773
1774   return priv->contains_pending_changes;
1775 }
1776
1777 void
1778 empathy_account_widget_handle_params (EmpathyAccountWidget *self,
1779     const gchar *first_widget,
1780     ...)
1781 {
1782   va_list args;
1783
1784   va_start (args, first_widget);
1785   account_widget_handle_params_valist (self, first_widget, args);
1786   va_end (args);
1787 }
1788
1789 GtkWidget *
1790 empathy_account_widget_get_widget (EmpathyAccountWidget *widget)
1791 {
1792   return widget->ui_details->widget;
1793 }
1794
1795 EmpathyAccountWidget *
1796 empathy_account_widget_new_for_protocol (EmpathyAccountSettings *settings,
1797     gboolean simple)
1798 {
1799   EmpathyAccountWidget *self;
1800
1801   g_return_val_if_fail (EMPATHY_IS_ACCOUNT_SETTINGS (settings), NULL);
1802
1803   self = g_object_new
1804     (EMPATHY_TYPE_ACCOUNT_WIDGET,
1805         "settings", settings, "simple", simple,
1806         "creating-account",
1807         empathy_account_settings_get_account (settings) == NULL,
1808         NULL);
1809
1810   return self;
1811 }
1812
1813 gchar *
1814 empathy_account_widget_get_default_display_name (EmpathyAccountWidget *self)
1815 {
1816   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1817   const gchar *login_id;
1818   const gchar *protocol, *p;
1819   gchar *default_display_name;
1820
1821   login_id = empathy_account_settings_get_string (priv->settings, "account");
1822   protocol = empathy_account_settings_get_protocol (priv->settings);
1823
1824   if (login_id != NULL)
1825     {
1826       /* TODO: this should be done in empathy-account-widget-irc */
1827       if (!tp_strdiff (protocol, "irc"))
1828         {
1829           const gchar* server;
1830           server = empathy_account_settings_get_string (priv->settings,
1831               "server");
1832
1833           /* To translators: The first parameter is the login id and the
1834            * second one is the server. The resulting string will be something
1835            * like: "MyUserName on chat.freenode.net".
1836            * You should reverse the order of these arguments if the
1837            * server should come before the login id in your locale.*/
1838           default_display_name = g_strdup_printf (_("%1$s on %2$s"),
1839               login_id, server);
1840         }
1841       else
1842         {
1843           default_display_name = g_strdup (login_id);
1844         }
1845
1846       return default_display_name;
1847     }
1848
1849   if ((p = empathy_protocol_name_to_display_name (protocol)) != NULL)
1850     protocol = p;
1851
1852   if (protocol != NULL)
1853     {
1854       /* To translators: The parameter is the protocol name. The resulting
1855        * string will be something like: "Jabber Account" */
1856       default_display_name = g_strdup_printf (_("%s Account"), protocol);
1857     }
1858   else
1859     {
1860       default_display_name = g_strdup (_("New account"));
1861     }
1862
1863   return default_display_name;
1864 }
1865
1866 /* Used by subclass to indicate that widget contains pending changes */
1867 void
1868 empathy_account_widget_changed (EmpathyAccountWidget *self)
1869 {
1870   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1871
1872   account_widget_handle_control_buttons_sensitivity (self);
1873   priv->contains_pending_changes = TRUE;
1874 }