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