]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-account-widget.c
added destroyed flag
[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   /* if TRUE, the GTK+ destroy signal has been fired and so the widgets
79    * embedded in this account widget can't be used any more
80    * workaround because some async callbacks can be called after the
81    * widget has been destroyed */
82   gboolean destroyed;
83
84   TpAccountManager *account_manager;
85
86   gboolean dispose_run;
87 } EmpathyAccountWidgetPriv;
88
89 enum {
90   PROP_PROTOCOL = 1,
91   PROP_SETTINGS,
92   PROP_SIMPLE,
93   PROP_CREATING_ACCOUNT
94 };
95
96 enum {
97   HANDLE_APPLY,
98   ACCOUNT_CREATED,
99   CANCELLED,
100   LAST_SIGNAL
101 };
102
103 static guint signals[LAST_SIGNAL] = { 0 };
104
105 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccountWidget)
106 #define CHANGED_TIMEOUT 300
107
108 static void
109 account_widget_set_control_buttons_sensitivity (EmpathyAccountWidget *self,
110     gboolean sensitive)
111 {
112   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
113
114   if (!priv->simple)
115     {
116       gtk_widget_set_sensitive (priv->apply_button, sensitive);
117       gtk_widget_set_sensitive (
118           priv->cancel_button, sensitive || priv->creating_account);
119
120       priv->contains_pending_changes = sensitive;
121     }
122 }
123
124 static void
125 account_widget_handle_control_buttons_sensitivity (EmpathyAccountWidget *self)
126 {
127   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
128   gboolean is_valid;
129
130   is_valid = empathy_account_settings_is_valid (priv->settings);
131
132   if (!priv->simple)
133       account_widget_set_control_buttons_sensitivity (self, is_valid);
134
135   g_signal_emit (self, signals[HANDLE_APPLY], 0, is_valid);
136 }
137
138 static void
139 account_widget_entry_changed_common (EmpathyAccountWidget *self,
140     GtkEntry *entry, gboolean focus)
141 {
142   const gchar *str;
143   const gchar *param_name;
144   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
145
146   str = gtk_entry_get_text (entry);
147   param_name = g_object_get_data (G_OBJECT (entry), "param_name");
148
149   if (EMP_STR_EMPTY (str))
150     {
151       const gchar *value = NULL;
152
153       empathy_account_settings_unset (priv->settings, param_name);
154
155       if (focus)
156         {
157           value = empathy_account_settings_get_string (priv->settings,
158               param_name);
159           DEBUG ("Unset %s and restore to %s", param_name, value);
160           gtk_entry_set_text (entry, value ? value : "");
161         }
162     }
163   else
164     {
165       DEBUG ("Setting %s to %s", param_name,
166           tp_strdiff (param_name, "password") ? str : "***");
167       empathy_account_settings_set_string (priv->settings, param_name, str);
168     }
169 }
170
171 static void
172 account_widget_entry_changed_cb (GtkEditable *entry,
173     EmpathyAccountWidget *self)
174 {
175   account_widget_entry_changed_common (self, GTK_ENTRY (entry), FALSE);
176   account_widget_handle_control_buttons_sensitivity (self);
177 }
178
179 static void
180 account_widget_int_changed_cb (GtkWidget *widget,
181     EmpathyAccountWidget *self)
182 {
183   const gchar *param_name;
184   gint value;
185   const gchar *signature;
186   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
187
188   value = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
189   param_name = g_object_get_data (G_OBJECT (widget), "param_name");
190
191   signature = empathy_account_settings_get_dbus_signature (priv->settings,
192     param_name);
193   g_return_if_fail (signature != NULL);
194
195   DEBUG ("Setting %s to %d", param_name, value);
196
197   switch ((int)*signature)
198     {
199     case DBUS_TYPE_INT16:
200     case DBUS_TYPE_INT32:
201       empathy_account_settings_set_int32 (priv->settings, param_name, value);
202       break;
203     case DBUS_TYPE_INT64:
204       empathy_account_settings_set_int64 (priv->settings, param_name, value);
205       break;
206     case DBUS_TYPE_UINT16:
207     case DBUS_TYPE_UINT32:
208       empathy_account_settings_set_uint32 (priv->settings, param_name, value);
209       break;
210     case DBUS_TYPE_UINT64:
211       empathy_account_settings_set_uint64 (priv->settings, param_name, value);
212       break;
213     default:
214       g_return_if_reached ();
215     }
216
217   account_widget_handle_control_buttons_sensitivity (self);
218 }
219
220 static void
221 account_widget_checkbutton_toggled_cb (GtkWidget *widget,
222     EmpathyAccountWidget *self)
223 {
224   gboolean     value;
225   gboolean     default_value;
226   const gchar *param_name;
227   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
228
229   value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
230   param_name = g_object_get_data (G_OBJECT (widget), "param_name");
231
232   /* FIXME: This is ugly! checkbox don't have a "not-set" value so we
233    * always unset the param and set the value if different from the
234    * default value. */
235   empathy_account_settings_unset (priv->settings, param_name);
236   default_value = empathy_account_settings_get_boolean (priv->settings,
237       param_name);
238
239   if (default_value == value)
240     {
241       DEBUG ("Unset %s and restore to %d", param_name, default_value);
242     }
243   else
244     {
245       DEBUG ("Setting %s to %d", param_name, value);
246       empathy_account_settings_set_boolean (priv->settings, param_name, value);
247     }
248
249   account_widget_handle_control_buttons_sensitivity (self);
250 }
251
252 static void
253 account_widget_forget_clicked_cb (GtkWidget *button,
254     EmpathyAccountWidget *self)
255 {
256   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
257   const gchar *param_name;
258
259   param_name = g_object_get_data (G_OBJECT (priv->entry_password),
260       "param_name");
261
262   DEBUG ("Unset %s", param_name);
263   empathy_account_settings_unset (priv->settings, param_name);
264   gtk_entry_set_text (GTK_ENTRY (priv->entry_password), "");
265
266   account_widget_handle_control_buttons_sensitivity (self);
267 }
268
269 static void
270 account_widget_password_changed_cb (GtkWidget *entry,
271     EmpathyAccountWidget *self)
272 {
273   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
274   const gchar *str;
275
276   str = gtk_entry_get_text (GTK_ENTRY (entry));
277   gtk_widget_set_sensitive (priv->button_forget, !EMP_STR_EMPTY (str));
278 }
279
280 static void
281 account_widget_jabber_ssl_toggled_cb (GtkWidget *checkbutton_ssl,
282     EmpathyAccountWidget *self)
283 {
284   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
285   gboolean   value;
286   gint32       port = 0;
287
288   value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbutton_ssl));
289   port = empathy_account_settings_get_uint32 (priv->settings, "port");
290
291   if (value)
292     {
293       if (port == 5222 || port == 0)
294         port = 5223;
295     }
296   else
297     {
298       if (port == 5223 || port == 0)
299         port = 5222;
300     }
301
302   gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->spinbutton_port), port);
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   account_widget_handle_control_buttons_sensitivity (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           priv->account_created = TRUE;
734           g_signal_emit (widget, signals[ACCOUNT_CREATED], 0);
735         }
736       else if (priv->enabled_checkbox != NULL)
737         {
738           gboolean enabled_checked;
739
740           enabled_checked =
741 #ifndef HAVE_MOBLIN
742             gtk_toggle_button_get_active (
743                 GTK_TOGGLE_BUTTON (priv->enabled_checkbox));
744 #else
745             nbtk_gtk_light_switch_get_active (
746                 NBTK_GTK_LIGHT_SWITCH (priv->enabled_checkbox));
747 #endif
748
749           if (tp_account_is_enabled (account) && enabled_checked)
750             {
751               /* After having applied changes to a user account, we
752                * automatically reconnect it. This is done so the new
753                * information entered by the user is validated on the server. */
754               tp_account_reconnect_async (account, NULL, NULL);
755             }
756         }
757     }
758
759   if (!priv->destroyed)
760     account_widget_set_control_buttons_sensitivity (widget, FALSE);
761
762   /* unref the widget - part of the workaround */
763   g_object_unref (widget);
764 }
765
766 static void
767 account_widget_apply_clicked_cb (GtkWidget *button,
768     EmpathyAccountWidget *self)
769 {
770   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
771
772   /* workaround to keep widget alive during async call */
773   g_object_ref (self);
774   empathy_account_settings_apply_async (priv->settings,
775       account_widget_applied_cb, self);
776 }
777
778 static void
779 account_widget_setup_generic (EmpathyAccountWidget *self)
780 {
781   GtkWidget *table_common_settings;
782   GtkWidget *table_advanced_settings;
783
784   table_common_settings = GTK_WIDGET (gtk_builder_get_object
785       (self->ui_details->gui, "table_common_settings"));
786   table_advanced_settings = GTK_WIDGET (gtk_builder_get_object
787       (self->ui_details->gui, "table_advanced_settings"));
788
789   accounts_widget_generic_setup (self, table_common_settings,
790       table_advanced_settings);
791
792   g_object_unref (self->ui_details->gui);
793 }
794
795 static void
796 account_widget_settings_ready_cb (EmpathyAccountSettings *settings,
797     GParamSpec *pspec,
798     gpointer user_data)
799 {
800   EmpathyAccountWidget *self = user_data;
801   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
802
803   if (empathy_account_settings_is_ready (priv->settings))
804     account_widget_setup_generic (self);
805 }
806
807 static void
808 account_widget_build_generic (EmpathyAccountWidget *self,
809     const char *filename)
810 {
811   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
812   GtkWidget *expander_advanced;
813
814   self->ui_details->gui = empathy_builder_get_file (filename,
815       "table_common_settings", &priv->table_common_settings,
816       "vbox_generic_settings", &self->ui_details->widget,
817       "expander_advanced_settings", &expander_advanced,
818       NULL);
819
820   if (priv->simple)
821     gtk_widget_hide (expander_advanced);
822
823   g_object_ref (self->ui_details->gui);
824
825   if (empathy_account_settings_is_ready (priv->settings))
826     account_widget_setup_generic (self);
827   else
828     g_signal_connect (priv->settings, "notify::ready",
829         G_CALLBACK (account_widget_settings_ready_cb), self);
830 }
831
832 static void
833 account_widget_build_salut (EmpathyAccountWidget *self,
834     const char *filename)
835 {
836   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
837
838   self->ui_details->gui = empathy_builder_get_file (filename,
839       "table_common_settings", &priv->table_common_settings,
840       "vbox_salut_settings", &self->ui_details->widget,
841       NULL);
842
843   empathy_account_widget_handle_params (self,
844       "entry_published", "published-name",
845       "entry_nickname", "nickname",
846       "entry_first_name", "first-name",
847       "entry_last_name", "last-name",
848       "entry_email", "email",
849       "entry_jid", "jid",
850       NULL);
851
852   self->ui_details->default_focus = g_strdup ("entry_first_name");
853 }
854
855 static void
856 account_widget_build_irc (EmpathyAccountWidget *self,
857   const char *filename)
858 {
859   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
860   empathy_account_widget_irc_build (self, filename,
861     &priv->table_common_settings);
862 }
863
864 static void
865 account_widget_build_sip (EmpathyAccountWidget *self,
866   const char *filename)
867 {
868   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
869   empathy_account_widget_sip_build (self, filename,
870     &priv->table_common_settings);
871 }
872
873 static void
874 account_widget_build_msn (EmpathyAccountWidget *self,
875     const char *filename)
876 {
877   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
878
879   if (priv->simple)
880     {
881       self->ui_details->gui = empathy_builder_get_file (filename,
882           "vbox_msn_simple", &self->ui_details->widget,
883           NULL);
884
885       empathy_account_widget_handle_params (self,
886           "entry_id_simple", "account",
887           "entry_password_simple", "password",
888           NULL);
889
890       self->ui_details->default_focus = g_strdup ("entry_id_simple");
891     }
892   else
893     {
894       self->ui_details->gui = empathy_builder_get_file (filename,
895           "table_common_msn_settings", &priv->table_common_settings,
896           "vbox_msn_settings", &self->ui_details->widget,
897           NULL);
898
899       empathy_account_widget_handle_params (self,
900           "entry_id", "account",
901           "entry_password", "password",
902           "entry_server", "server",
903           "spinbutton_port", "port",
904           NULL);
905
906       self->ui_details->default_focus = g_strdup ("entry_id");
907       self->ui_details->add_forget = TRUE;
908     }
909 }
910
911 static void
912 account_widget_build_jabber (EmpathyAccountWidget *self,
913     const char *filename)
914 {
915   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
916   GtkWidget *spinbutton_port;
917   GtkWidget *checkbutton_ssl;
918   GtkWidget *label_id, *label_password;
919   GtkWidget *label_id_create, *label_password_create;
920   GtkWidget *label_example_gtalk, *label_example_jabber;
921   gboolean is_gtalk;
922
923   is_gtalk = !tp_strdiff (
924       empathy_account_settings_get_icon_name (priv->settings),
925       "im-google-talk");
926
927   if (priv->simple && !is_gtalk)
928     {
929       self->ui_details->gui = empathy_builder_get_file (filename,
930           "vbox_jabber_simple", &self->ui_details->widget,
931           "label_id_simple", &label_id,
932           "label_id_create", &label_id_create,
933           "label_password_simple", &label_password,
934           "label_password_create", &label_password_create,
935           NULL);
936
937       if (empathy_account_settings_get_boolean (priv->settings, "register"))
938         {
939           gtk_widget_hide (label_id);
940           gtk_widget_hide (label_password);
941           gtk_widget_show (label_id_create);
942           gtk_widget_show (label_password_create);
943         }
944
945       empathy_account_widget_handle_params (self,
946           "entry_id_simple", "account",
947           "entry_password_simple", "password",
948           NULL);
949
950       self->ui_details->default_focus = g_strdup ("entry_id_simple");
951     }
952   else if (priv->simple && is_gtalk)
953     {
954       self->ui_details->gui = empathy_builder_get_file (filename,
955           "vbox_gtalk_simple", &self->ui_details->widget,
956           NULL);
957
958       empathy_account_widget_handle_params (self,
959           "entry_id_g_simple", "account",
960           "entry_password_g_simple", "password",
961           NULL);
962
963       self->ui_details->default_focus = g_strdup ("entry_id_g_simple");
964     }
965   else
966     {
967       self->ui_details->gui = empathy_builder_get_file (filename,
968           "table_common_settings", &priv->table_common_settings,
969           "vbox_jabber_settings", &self->ui_details->widget,
970           "spinbutton_port", &spinbutton_port,
971           "checkbutton_ssl", &checkbutton_ssl,
972           "label_username_example", &label_example_jabber,
973           "label_username_g_example", &label_example_gtalk,
974           NULL);
975
976       empathy_account_widget_handle_params (self,
977           "entry_id", "account",
978           "entry_password", "password",
979           "entry_resource", "resource",
980           "entry_server", "server",
981           "spinbutton_port", "port",
982           "spinbutton_priority", "priority",
983           "checkbutton_ssl", "old-ssl",
984           "checkbutton_ignore_ssl_errors", "ignore-ssl-errors",
985           "checkbutton_encryption", "require-encryption",
986           NULL);
987
988       self->ui_details->default_focus = g_strdup ("entry_id");
989       self->ui_details->add_forget = TRUE;
990       priv->spinbutton_port = spinbutton_port;
991
992       g_signal_connect (checkbutton_ssl, "toggled",
993           G_CALLBACK (account_widget_jabber_ssl_toggled_cb),
994           self);
995
996       if (is_gtalk)
997         {
998           gtk_widget_hide (label_example_jabber);
999           gtk_widget_show (label_example_gtalk);
1000         }
1001     }
1002 }
1003
1004 static void
1005 account_widget_build_icq (EmpathyAccountWidget *self,
1006     const char *filename)
1007 {
1008   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1009   GtkWidget *spinbutton_port;
1010
1011   if (priv->simple)
1012     {
1013       self->ui_details->gui = empathy_builder_get_file (filename,
1014           "vbox_icq_simple", &self->ui_details->widget,
1015           NULL);
1016
1017       empathy_account_widget_handle_params (self,
1018           "entry_uin_simple", "account",
1019           "entry_password_simple", "password",
1020           NULL);
1021
1022       self->ui_details->default_focus = g_strdup ("entry_uin_simple");
1023     }
1024   else
1025     {
1026       self->ui_details->gui = empathy_builder_get_file (filename,
1027           "table_common_settings", &priv->table_common_settings,
1028           "vbox_icq_settings", &self->ui_details->widget,
1029           "spinbutton_port", &spinbutton_port,
1030           NULL);
1031
1032       empathy_account_widget_handle_params (self,
1033           "entry_uin", "account",
1034           "entry_password", "password",
1035           "entry_server", "server",
1036           "spinbutton_port", "port",
1037           "entry_charset", "charset",
1038           NULL);
1039
1040       self->ui_details->default_focus = g_strdup ("entry_uin");
1041       self->ui_details->add_forget = TRUE;
1042     }
1043 }
1044
1045 static void
1046 account_widget_build_aim (EmpathyAccountWidget *self,
1047     const char *filename)
1048 {
1049   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1050   GtkWidget *spinbutton_port;
1051
1052   if (priv->simple)
1053     {
1054       self->ui_details->gui = empathy_builder_get_file (filename,
1055           "vbox_aim_simple", &self->ui_details->widget,
1056           NULL);
1057
1058       empathy_account_widget_handle_params (self,
1059           "entry_screenname_simple", "account",
1060           "entry_password_simple", "password",
1061           NULL);
1062
1063       self->ui_details->default_focus = g_strdup ("entry_screenname_simple");
1064     }
1065   else
1066     {
1067       self->ui_details->gui = empathy_builder_get_file (filename,
1068           "table_common_settings", &priv->table_common_settings,
1069           "vbox_aim_settings", &self->ui_details->widget,
1070           "spinbutton_port", &spinbutton_port,
1071           NULL);
1072
1073       empathy_account_widget_handle_params (self,
1074           "entry_screenname", "account",
1075           "entry_password", "password",
1076           "entry_server", "server",
1077           "spinbutton_port", "port",
1078           NULL);
1079
1080       self->ui_details->default_focus = g_strdup ("entry_screenname");
1081       self->ui_details->add_forget = TRUE;
1082     }
1083 }
1084
1085 static void
1086 account_widget_build_yahoo (EmpathyAccountWidget *self,
1087     const char *filename)
1088 {
1089   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1090
1091   if (priv->simple)
1092     {
1093       self->ui_details->gui = empathy_builder_get_file (filename,
1094           "vbox_yahoo_simple", &self->ui_details->widget,
1095           NULL);
1096
1097       empathy_account_widget_handle_params (self,
1098           "entry_id_simple", "account",
1099           "entry_password_simple", "password",
1100           NULL);
1101
1102       self->ui_details->default_focus = g_strdup ("entry_id_simple");
1103     }
1104   else
1105     {
1106       self->ui_details->gui = empathy_builder_get_file (filename,
1107           "table_common_settings", &priv->table_common_settings,
1108           "vbox_yahoo_settings", &self->ui_details->widget,
1109           NULL);
1110
1111       empathy_account_widget_handle_params (self,
1112           "entry_id", "account",
1113           "entry_password", "password",
1114           "entry_server", "server",
1115           "entry_locale", "room-list-locale",
1116           "entry_charset", "charset",
1117           "spinbutton_port", "port",
1118           "checkbutton_yahoojp", "yahoojp",
1119           "checkbutton_ignore_invites", "ignore-invites",
1120           NULL);
1121
1122       self->ui_details->default_focus = g_strdup ("entry_id");
1123       self->ui_details->add_forget = TRUE;
1124     }
1125 }
1126
1127 static void
1128 account_widget_build_groupwise (EmpathyAccountWidget *self,
1129     const char *filename)
1130 {
1131   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1132
1133   if (priv->simple)
1134     {
1135       self->ui_details->gui = empathy_builder_get_file (filename,
1136           "vbox_groupwise_simple", &self->ui_details->widget,
1137           NULL);
1138
1139       empathy_account_widget_handle_params (self,
1140           "entry_id_simple", "account",
1141           "entry_password_simple", "password",
1142           NULL);
1143
1144       self->ui_details->default_focus = g_strdup ("entry_id_simple");
1145     }
1146   else
1147     {
1148       self->ui_details->gui = empathy_builder_get_file (filename,
1149           "table_common_groupwise_settings", &priv->table_common_settings,
1150           "vbox_groupwise_settings", &self->ui_details->widget,
1151           NULL);
1152
1153       empathy_account_widget_handle_params (self,
1154           "entry_id", "account",
1155           "entry_password", "password",
1156           "entry_server", "server",
1157           "spinbutton_port", "port",
1158           NULL);
1159
1160       self->ui_details->default_focus = g_strdup ("entry_id");
1161       self->ui_details->add_forget = TRUE;
1162     }
1163 }
1164
1165 static void
1166 account_widget_destroy_cb (GtkWidget *widget,
1167     EmpathyAccountWidget *self)
1168 {
1169   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1170   /* set the destroyed flag - workaround */
1171   priv->destroyed = TRUE;
1172
1173   g_object_unref (self);
1174 }
1175
1176 static void
1177 empathy_account_widget_enabled_cb (TpAccount *account,
1178       GParamSpec *spec,
1179       gpointer user_data)
1180 {
1181   EmpathyAccountWidget *widget = EMPATHY_ACCOUNT_WIDGET (user_data);
1182   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
1183   gboolean enabled = tp_account_is_enabled (account);
1184
1185   if (priv->enabled_checkbox != NULL)
1186     {
1187 #ifndef HAVE_MOBLIN
1188       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->enabled_checkbox),
1189           enabled);
1190 #else
1191       nbtk_gtk_light_switch_set_active (
1192           NBTK_GTK_LIGHT_SWITCH (priv->enabled_checkbox),
1193           enabled);
1194 #endif /* HAVE_MOBLIN */
1195     }
1196 }
1197
1198 static void
1199 #ifndef HAVE_MOBLIN
1200 account_widget_enabled_released_cb (GtkToggleButton *toggle_button,
1201     gpointer user_data)
1202 #else
1203 account_widget_switch_flipped_cb (NbtkGtkLightSwitch *sw,
1204     gboolean state,
1205     gpointer user_data)
1206 #endif /* HAVE_MOBLIN */
1207 {
1208   EmpathyAccountWidgetPriv *priv = GET_PRIV (user_data);
1209   TpAccount *account;
1210 #ifndef HAVE_MOBLIN
1211   gboolean state;
1212
1213   state = gtk_toggle_button_get_active (toggle_button);
1214 #endif
1215
1216   account = empathy_account_settings_get_account (priv->settings);
1217
1218   /* Enable the account according to the value of the "Enabled" checkbox */
1219   /* workaround to keep widget alive during async call */
1220   g_object_ref (user_data);
1221   tp_account_set_enabled_async (account, state,
1222       account_widget_account_enabled_cb, user_data);
1223 }
1224
1225 static void
1226 do_set_property (GObject *object,
1227     guint prop_id,
1228     const GValue *value,
1229     GParamSpec *pspec)
1230 {
1231   EmpathyAccountWidgetPriv *priv = GET_PRIV (object);
1232
1233   switch (prop_id)
1234     {
1235     case PROP_SETTINGS:
1236       priv->settings = g_value_dup_object (value);
1237       break;
1238     case PROP_SIMPLE:
1239       priv->simple = g_value_get_boolean (value);
1240       break;
1241     case PROP_CREATING_ACCOUNT:
1242       priv->creating_account = g_value_get_boolean (value);
1243       break;
1244     default:
1245       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1246     }
1247 }
1248
1249 static void
1250 do_get_property (GObject *object,
1251     guint prop_id,
1252     GValue *value,
1253     GParamSpec *pspec)
1254 {
1255   EmpathyAccountWidgetPriv *priv = GET_PRIV (object);
1256
1257   switch (prop_id)
1258     {
1259     case PROP_PROTOCOL:
1260       g_value_set_string (value,
1261         empathy_account_settings_get_protocol (priv->settings));
1262       break;
1263     case PROP_SETTINGS:
1264       g_value_set_object (value, priv->settings);
1265       break;
1266     case PROP_SIMPLE:
1267       g_value_set_boolean (value, priv->simple);
1268       break;
1269     case PROP_CREATING_ACCOUNT:
1270       g_value_set_boolean (value, priv->creating_account);
1271       break;
1272     default:
1273       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1274     }
1275 }
1276
1277 static void
1278 presence_changed_cb (TpAccountManager *manager,
1279     TpConnectionPresenceType state,
1280     const gchar *status,
1281     const gchar *message,
1282     EmpathyAccountWidget *self)
1283 {
1284   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1285
1286   if (state > TP_CONNECTION_PRESENCE_TYPE_OFFLINE)
1287     {
1288       /* We are online, display a Login button */
1289       GtkWidget *image;
1290
1291       gtk_button_set_use_stock (GTK_BUTTON (priv->apply_button), FALSE);
1292       gtk_button_set_label (GTK_BUTTON (priv->apply_button), _("L_og in"));
1293
1294       image = gtk_image_new_from_stock (GTK_STOCK_CONNECT,
1295           GTK_ICON_SIZE_BUTTON);
1296       gtk_button_set_image (GTK_BUTTON (priv->apply_button), image);
1297     }
1298   else
1299     {
1300       /* We are offline, display a Save button */
1301       gtk_button_set_image (GTK_BUTTON (priv->apply_button), NULL);
1302       gtk_button_set_use_stock (GTK_BUTTON (priv->apply_button), TRUE);
1303       gtk_button_set_label (GTK_BUTTON (priv->apply_button), GTK_STOCK_SAVE);
1304     }
1305 }
1306
1307 static void
1308 account_manager_ready_cb (GObject *source_object,
1309     GAsyncResult *result,
1310     gpointer user_data)
1311 {
1312   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (user_data);
1313   TpAccountManager *account_manager = TP_ACCOUNT_MANAGER (source_object);
1314   GError *error = NULL;
1315   TpConnectionPresenceType state;
1316
1317   if (!tp_account_manager_prepare_finish (account_manager, result, &error))
1318     {
1319       DEBUG ("Failed to prepare account manager: %s", error->message);
1320       g_error_free (error);
1321       return;
1322     }
1323
1324   state = tp_account_manager_get_most_available_presence (account_manager, NULL,
1325       NULL);
1326
1327   /* simulate a presence change so the apply button will be changed
1328    * if needed */
1329   presence_changed_cb (account_manager, state, NULL, NULL, self);
1330 }
1331
1332 #define WIDGET(cm, proto) \
1333   { #cm, #proto, "empathy-account-widget-"#proto".ui", \
1334     account_widget_build_##proto }
1335
1336 static void
1337 do_constructed (GObject *obj)
1338 {
1339   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
1340   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1341   TpAccount *account;
1342   const gchar *protocol, *cm_name;
1343   guint i = 0;
1344   struct {
1345     const gchar *cm_name;
1346     const gchar *protocol;
1347     const char *file;
1348     void (*func)(EmpathyAccountWidget *self, const gchar *filename);
1349   } widgets [] = {
1350     { "salut", "local-xmpp", "empathy-account-widget-local-xmpp.ui",
1351         account_widget_build_salut },
1352     WIDGET (gabble, jabber),
1353     WIDGET (butterfly, msn),
1354     WIDGET (haze, icq),
1355     WIDGET (haze, aim),
1356     WIDGET (haze, yahoo),
1357     WIDGET (haze, groupwise),
1358     WIDGET (idle, irc),
1359     WIDGET (sofiasip, sip),
1360   };
1361
1362   cm_name = empathy_account_settings_get_cm (priv->settings);
1363   protocol = empathy_account_settings_get_protocol (priv->settings);
1364
1365   for (i = 0 ; i < G_N_ELEMENTS (widgets); i++)
1366     {
1367       if (!tp_strdiff (widgets[i].cm_name, cm_name) &&
1368           !tp_strdiff (widgets[i].protocol, protocol))
1369         {
1370           gchar *filename;
1371
1372           filename = empathy_file_lookup (widgets[i].file,
1373               "libempathy-gtk");
1374           widgets[i].func (self, filename);
1375           g_free (filename);
1376
1377           break;
1378         }
1379     }
1380
1381   if (i == G_N_ELEMENTS (widgets))
1382     {
1383       gchar *filename = empathy_file_lookup (
1384           "empathy-account-widget-generic.ui", "libempathy-gtk");
1385       account_widget_build_generic (self, filename);
1386       g_free (filename);
1387     }
1388
1389   /* handle default focus */
1390   if (self->ui_details->default_focus != NULL)
1391     {
1392       GObject *default_focus_entry;
1393
1394       default_focus_entry = gtk_builder_get_object
1395         (self->ui_details->gui, self->ui_details->default_focus);
1396       g_signal_connect (default_focus_entry, "realize",
1397           G_CALLBACK (gtk_widget_grab_focus),
1398           NULL);
1399     }
1400
1401   /* handle forget button */
1402   if (self->ui_details->add_forget)
1403     {
1404       const gchar *password = NULL;
1405
1406       priv->button_forget = GTK_WIDGET (gtk_builder_get_object
1407           (self->ui_details->gui, "button_forget"));
1408       priv->entry_password = GTK_WIDGET (gtk_builder_get_object
1409           (self->ui_details->gui, "entry_password"));
1410
1411       password = empathy_account_settings_get_string (priv->settings,
1412           "password");
1413       gtk_widget_set_sensitive (priv->button_forget,
1414           !EMP_STR_EMPTY (password));
1415
1416       g_signal_connect (priv->button_forget, "clicked",
1417           G_CALLBACK (account_widget_forget_clicked_cb),
1418           self);
1419       g_signal_connect (priv->entry_password, "changed",
1420           G_CALLBACK (account_widget_password_changed_cb),
1421           self);
1422     }
1423
1424   /* dup and init the account-manager */
1425   priv->account_manager = tp_account_manager_dup ();
1426
1427   tp_account_manager_prepare_async (priv->account_manager, NULL,
1428       account_manager_ready_cb, self);
1429
1430   /* handle apply and cancel button */
1431   if (!priv->simple)
1432     {
1433       GtkWidget *hbox = gtk_hbox_new (TRUE, 3);
1434
1435       priv->cancel_button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
1436
1437       if (priv->creating_account)
1438         {
1439           /* Assumre we are offline, display a Save button. We'll update
1440            * it once the account manager is ready if needed */
1441           priv->apply_button = gtk_button_new_from_stock (GTK_STOCK_SAVE);
1442
1443           empathy_signal_connect_weak (priv->account_manager,
1444               "most-available-presence-changed",
1445               G_CALLBACK (presence_changed_cb), obj);
1446         }
1447       else
1448         {
1449           /* We are editing an existing account, display an Apply button */
1450           priv->apply_button = gtk_button_new_from_stock (GTK_STOCK_APPLY);
1451         }
1452
1453       gtk_box_pack_end (GTK_BOX (hbox), priv->apply_button, TRUE,
1454           TRUE, 3);
1455       gtk_box_pack_end (GTK_BOX (hbox), priv->cancel_button, TRUE,
1456           TRUE, 3);
1457
1458       gtk_box_pack_end (GTK_BOX (self->ui_details->widget), hbox, FALSE,
1459           FALSE, 3);
1460
1461       g_signal_connect (priv->cancel_button, "clicked",
1462           G_CALLBACK (account_widget_cancel_clicked_cb),
1463           self);
1464       g_signal_connect (priv->apply_button, "clicked",
1465           G_CALLBACK (account_widget_apply_clicked_cb),
1466           self);
1467       gtk_widget_show_all (hbox);
1468
1469       if (priv->creating_account)
1470         /* When creating an account, the user might have nothing to enter.
1471          * That means that no control interaction might occur,
1472          * so we update the control button sensitivity manually.
1473          */
1474         account_widget_handle_control_buttons_sensitivity (self);
1475       else
1476         account_widget_set_control_buttons_sensitivity (self, FALSE);
1477     }
1478
1479   account = empathy_account_settings_get_account (priv->settings);
1480
1481   if (account != NULL)
1482     {
1483       g_signal_connect (account, "notify::enabled",
1484           G_CALLBACK (empathy_account_widget_enabled_cb), self);
1485     }
1486
1487   /* handle the "Enabled" checkbox. We only add it when modifying an account */
1488   if (!priv->creating_account && priv->table_common_settings != NULL)
1489     {
1490 #ifdef HAVE_MOBLIN
1491       GtkWidget *w;
1492 #endif
1493       guint nb_rows, nb_columns;
1494       gboolean is_enabled;
1495
1496       is_enabled = tp_account_is_enabled (account);
1497
1498 #ifndef HAVE_MOBLIN
1499       priv->enabled_checkbox =
1500           gtk_check_button_new_with_label (_("Enabled"));
1501
1502       gtk_toggle_button_set_active (
1503           GTK_TOGGLE_BUTTON (priv->enabled_checkbox), is_enabled);
1504 #else
1505       /* Translators: this is used only when built on a moblin platform */
1506       w = gtk_label_new (_("Account:"));
1507       gtk_misc_set_alignment (GTK_MISC (w), 0, 0.5);
1508
1509       priv->enabled_checkbox = nbtk_gtk_light_switch_new ();
1510
1511       nbtk_gtk_light_switch_set_active (
1512           NBTK_GTK_LIGHT_SWITCH (priv->enabled_checkbox), is_enabled);
1513
1514       gtk_widget_show (w);
1515 #endif /* HAVE_MOBLIN */
1516
1517       g_object_get (priv->table_common_settings, "n-rows", &nb_rows,
1518           "n-columns", &nb_columns, NULL);
1519
1520       gtk_table_resize (GTK_TABLE (priv->table_common_settings), ++nb_rows,
1521           nb_columns);
1522
1523 #ifndef HAVE_MOBLIN
1524       gtk_table_attach (GTK_TABLE (priv->table_common_settings),
1525           priv->enabled_checkbox,
1526           0, nb_columns, nb_rows - 1, nb_rows,
1527           GTK_EXPAND | GTK_FILL, 0, 0, 0);
1528 #else
1529       gtk_table_attach (GTK_TABLE (priv->table_common_settings),
1530           w,
1531           0, 1, nb_rows - 1, nb_rows,
1532           GTK_FILL, 0, 0, 0);
1533       gtk_table_attach (GTK_TABLE (priv->table_common_settings),
1534           priv->enabled_checkbox,
1535           1, nb_columns, nb_rows - 1, nb_rows,
1536           GTK_EXPAND | GTK_FILL, 0, 0, 0);
1537 #endif /* HAVE_MOBLIN */
1538
1539       gtk_widget_show (priv->enabled_checkbox);
1540
1541 #ifndef HAVE_MOBLIN
1542       g_signal_connect (G_OBJECT (priv->enabled_checkbox), "released",
1543           G_CALLBACK (account_widget_enabled_released_cb), self);
1544 #else
1545       g_signal_connect (G_OBJECT (priv->enabled_checkbox), "switch-flipped",
1546           G_CALLBACK (account_widget_switch_flipped_cb), self);
1547 #endif /* HAVE_MOBLIN */
1548     }
1549
1550   /* hook up to widget destruction to unref ourselves */
1551   g_signal_connect (self->ui_details->widget, "destroy",
1552       G_CALLBACK (account_widget_destroy_cb), self);
1553
1554   empathy_builder_unref_and_keep_widget (self->ui_details->gui,
1555       self->ui_details->widget);
1556   self->ui_details->gui = NULL;
1557 }
1558
1559 static void
1560 do_dispose (GObject *obj)
1561 {
1562   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
1563   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1564
1565   if (priv->dispose_run)
1566     return;
1567
1568   priv->dispose_run = TRUE;
1569
1570   empathy_account_settings_is_ready (priv->settings);
1571
1572   if (priv->settings != NULL)
1573     {
1574       TpAccount *account;
1575       account = empathy_account_settings_get_account (priv->settings);
1576
1577       if (account != NULL)
1578         {
1579           g_signal_handlers_disconnect_by_func (account,
1580               empathy_account_widget_enabled_cb, self);
1581         }
1582
1583       g_object_unref (priv->settings);
1584       priv->settings = NULL;
1585     }
1586
1587   if (priv->account_manager != NULL)
1588     {
1589       g_object_unref (priv->account_manager);
1590       priv->account_manager = NULL;
1591     }
1592
1593   if (G_OBJECT_CLASS (empathy_account_widget_parent_class)->dispose != NULL)
1594     G_OBJECT_CLASS (empathy_account_widget_parent_class)->dispose (obj);
1595 }
1596
1597 static void
1598 do_finalize (GObject *obj)
1599 {
1600   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
1601
1602   g_free (self->ui_details->default_focus);
1603   g_slice_free (EmpathyAccountWidgetUIDetails, self->ui_details);
1604
1605   if (G_OBJECT_CLASS (empathy_account_widget_parent_class)->finalize != NULL)
1606     G_OBJECT_CLASS (empathy_account_widget_parent_class)->finalize (obj);
1607 }
1608
1609 static void
1610 empathy_account_widget_class_init (EmpathyAccountWidgetClass *klass)
1611 {
1612   GObjectClass *oclass = G_OBJECT_CLASS (klass);
1613   GParamSpec *param_spec;
1614
1615   oclass->get_property = do_get_property;
1616   oclass->set_property = do_set_property;
1617   oclass->constructed = do_constructed;
1618   oclass->dispose = do_dispose;
1619   oclass->finalize = do_finalize;
1620
1621   param_spec = g_param_spec_string ("protocol",
1622       "protocol", "The protocol of the account",
1623       NULL,
1624       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
1625   g_object_class_install_property (oclass, PROP_PROTOCOL, param_spec);
1626
1627   param_spec = g_param_spec_object ("settings",
1628       "settings", "The settings of the account",
1629       EMPATHY_TYPE_ACCOUNT_SETTINGS,
1630       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
1631   g_object_class_install_property (oclass, PROP_SETTINGS, param_spec);
1632
1633   param_spec = g_param_spec_boolean ("simple",
1634       "simple", "Whether the account widget is a simple or an advanced one",
1635       FALSE,
1636       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
1637   g_object_class_install_property (oclass, PROP_SIMPLE, param_spec);
1638
1639   param_spec = g_param_spec_boolean ("creating-account",
1640       "creating-account",
1641       "TRUE if we're creating an account, FALSE if we're modifying it",
1642       FALSE,
1643       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
1644   g_object_class_install_property (oclass, PROP_CREATING_ACCOUNT, param_spec);
1645
1646   signals[HANDLE_APPLY] =
1647     g_signal_new ("handle-apply", G_TYPE_FROM_CLASS (klass),
1648         G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1649         g_cclosure_marshal_VOID__BOOLEAN,
1650         G_TYPE_NONE,
1651         1, G_TYPE_BOOLEAN);
1652
1653   /* This signal is emitted when an account has been created and enabled. */
1654   signals[ACCOUNT_CREATED] =
1655       g_signal_new ("account-created", G_TYPE_FROM_CLASS (klass),
1656           G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1657           g_cclosure_marshal_VOID__VOID,
1658           G_TYPE_NONE,
1659           0);
1660
1661   signals[CANCELLED] =
1662       g_signal_new ("cancelled", G_TYPE_FROM_CLASS (klass),
1663           G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1664           g_cclosure_marshal_VOID__VOID,
1665           G_TYPE_NONE,
1666           0);
1667
1668   g_type_class_add_private (klass, sizeof (EmpathyAccountWidgetPriv));
1669 }
1670
1671 static void
1672 empathy_account_widget_init (EmpathyAccountWidget *self)
1673 {
1674   EmpathyAccountWidgetPriv *priv =
1675     G_TYPE_INSTANCE_GET_PRIVATE ((self), EMPATHY_TYPE_ACCOUNT_WIDGET,
1676         EmpathyAccountWidgetPriv);
1677
1678   self->priv = priv;
1679   priv->dispose_run = FALSE;
1680
1681   self->ui_details = g_slice_new0 (EmpathyAccountWidgetUIDetails);
1682 }
1683
1684 /* public methods */
1685
1686 void
1687 empathy_account_widget_discard_pending_changes
1688     (EmpathyAccountWidget *widget)
1689 {
1690   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
1691
1692   empathy_account_settings_discard_changes (priv->settings);
1693   priv->contains_pending_changes = FALSE;
1694 }
1695
1696 gboolean
1697 empathy_account_widget_contains_pending_changes (EmpathyAccountWidget *widget)
1698 {
1699   EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
1700
1701   if (priv->creating_account && !priv->account_created)
1702     /* We always want to warn the user if he's in the process of creating a
1703      * new account which hasn't been actually created yet. */
1704     return TRUE;
1705
1706   return priv->contains_pending_changes;
1707 }
1708
1709 void
1710 empathy_account_widget_handle_params (EmpathyAccountWidget *self,
1711     const gchar *first_widget,
1712     ...)
1713 {
1714   va_list args;
1715
1716   va_start (args, first_widget);
1717   account_widget_handle_params_valist (self, first_widget, args);
1718   va_end (args);
1719 }
1720
1721 GtkWidget *
1722 empathy_account_widget_get_widget (EmpathyAccountWidget *widget)
1723 {
1724   return widget->ui_details->widget;
1725 }
1726
1727 EmpathyAccountWidget *
1728 empathy_account_widget_new_for_protocol (EmpathyAccountSettings *settings,
1729     gboolean simple)
1730 {
1731   EmpathyAccountWidget *self;
1732
1733   g_return_val_if_fail (EMPATHY_IS_ACCOUNT_SETTINGS (settings), NULL);
1734
1735   self = g_object_new
1736     (EMPATHY_TYPE_ACCOUNT_WIDGET,
1737         "settings", settings, "simple", simple,
1738         "creating-account",
1739         empathy_account_settings_get_account (settings) == NULL,
1740         NULL);
1741
1742   return self;
1743 }
1744
1745 gchar *
1746 empathy_account_widget_get_default_display_name (EmpathyAccountWidget *self)
1747 {
1748   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
1749   const gchar *login_id;
1750   const gchar *protocol, *p;
1751   gchar *default_display_name;
1752
1753   login_id = empathy_account_settings_get_string (priv->settings, "account");
1754   protocol = empathy_account_settings_get_protocol (priv->settings);
1755
1756   if (login_id != NULL)
1757     {
1758       /* TODO: this should be done in empathy-account-widget-irc */
1759       if (!tp_strdiff (protocol, "irc"))
1760         {
1761           const gchar* server;
1762           server = empathy_account_settings_get_string (priv->settings,
1763               "server");
1764
1765           /* To translators: The first parameter is the login id and the
1766            * second one is the server. The resulting string will be something
1767            * like: "MyUserName on chat.freenode.net".
1768            * You should reverse the order of these arguments if the
1769            * server should come before the login id in your locale.*/
1770           default_display_name = g_strdup_printf (_("%1$s on %2$s"),
1771               login_id, server);
1772         }
1773       else
1774         {
1775           default_display_name = g_strdup (login_id);
1776         }
1777
1778       return default_display_name;
1779     }
1780
1781   if ((p = empathy_protocol_name_to_display_name (protocol)) != NULL)
1782     protocol = p;
1783
1784   if (protocol != NULL)
1785     {
1786       /* To translators: The parameter is the protocol name. The resulting
1787        * string will be something like: "Jabber Account" */
1788       default_display_name = g_strdup_printf (_("%s Account"), protocol);
1789     }
1790   else
1791     {
1792       default_display_name = g_strdup (_("New account"));
1793     }
1794
1795   return default_display_name;
1796 }