]> git.0d.be Git - empathy.git/blobdiff - libempathy-gtk/empathy-account-widget.c
Merge commit 'jtellier/confirm-lose-accounts-settings'
[empathy.git] / libempathy-gtk / empathy-account-widget.c
index 5cfff21d9348d96dc79df647b186a7c4cd39f93a..df0dc967ba5c6109b824b1b25f8cc63016356c9b 100644 (file)
@@ -1,4 +1,3 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
  * Copyright (C) 2006-2007 Imendio AB
  * Copyright (C) 2007-2009 Collabora Ltd.
@@ -21,6 +20,7 @@
  * Authors: Xavier Claessens <xclaesse@gmail.com>
  *          Martyn Russell <martyn@imendio.com>
  *          Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
+ *          Jonathan Tellier <jonathan.tellier@gmail.com>
  */
 
 #include <config.h>
 G_DEFINE_TYPE (EmpathyAccountWidget, empathy_account_widget, G_TYPE_OBJECT)
 
 typedef struct {
-  char *protocol;
   EmpathyAccountSettings *settings;
-       
+
+  GtkWidget *table_common_settings;
   GtkWidget *apply_button;
+  GtkWidget *cancel_button;
   GtkWidget *entry_password;
   GtkWidget *button_forget;
   GtkWidget *spinbutton_port;
+  GtkWidget *enabled_checkbox;
+
+  gboolean simple;
+
+  gboolean contains_pending_changes;
+  gboolean original_enabled_checkbox_value;
+
+  /* An EmpathyAccountWidget can be used to either create an account or
+   * modify it. When we are creating an account, this member is set to TRUE */
+  gboolean creating_account;
 
   gboolean dispose_run;
 } EmpathyAccountWidgetPriv;
 
 enum {
   PROP_PROTOCOL = 1,
-  PROP_SETTINGS
+  PROP_SETTINGS,
+  PROP_SIMPLE,
+  PROP_CREATING_ACCOUNT
 };
 
+enum {
+  HANDLE_APPLY,
+  ACCOUNT_CREATED,
+  CANCELLED,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccountWidget)
+#define CHANGED_TIMEOUT 300
 
 static void
-account_widget_handle_apply_sensitivity (EmpathyAccountWidget *self)
+account_widget_set_control_buttons_sensitivity (EmpathyAccountWidget *self,
+    gboolean sensitive)
 {
   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
 
-  gtk_widget_set_sensitive (priv->apply_button,
-      empathy_account_settings_is_valid (priv->settings));
+  if (!priv->simple)
+    {
+      gtk_widget_set_sensitive (priv->apply_button, sensitive);
+      gtk_widget_set_sensitive (priv->cancel_button, sensitive);
+      priv->contains_pending_changes = sensitive;
+    }
 }
 
-static gboolean
-account_widget_entry_focus_cb (GtkWidget *widget,
-    GdkEventFocus *event,
-    EmpathyAccountWidget *self)
+static void
+account_widget_handle_control_buttons_sensitivity (EmpathyAccountWidget *self)
+{
+  EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
+  gboolean is_valid;
+
+  is_valid = empathy_account_settings_is_valid (priv->settings);
+
+  if (!priv->simple)
+      account_widget_set_control_buttons_sensitivity (self, is_valid);
+
+  g_signal_emit (self, signals[HANDLE_APPLY], 0, is_valid);
+}
+
+static void
+account_widget_entry_changed_common (EmpathyAccountWidget *self,
+    GtkEntry *entry, gboolean focus)
 {
   const gchar *str;
   const gchar *param_name;
   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
 
-  str = gtk_entry_get_text (GTK_ENTRY (widget));
-  param_name = g_object_get_data (G_OBJECT (widget), "param_name");
+  str = gtk_entry_get_text (entry);
+  param_name = g_object_get_data (G_OBJECT (entry), "param_name");
 
   if (EMP_STR_EMPTY (str))
     {
       const gchar *value = NULL;
 
       empathy_account_settings_unset (priv->settings, param_name);
-      value = empathy_account_settings_get_string (priv->settings, param_name);
-      DEBUG ("Unset %s and restore to %s", param_name, value);
-      gtk_entry_set_text (GTK_ENTRY (widget), value ? value : "");
+
+      if (focus)
+        {
+          value = empathy_account_settings_get_string (priv->settings,
+              param_name);
+          DEBUG ("Unset %s and restore to %s", param_name, value);
+          gtk_entry_set_text (entry, value ? value : "");
+        }
     }
   else
     {
       DEBUG ("Setting %s to %s", param_name,
-          strstr (param_name, "password") ? "***" : str);
+          tp_strdiff (param_name, "password") ? str : "***");
       empathy_account_settings_set_string (priv->settings, param_name, str);
     }
+}
 
-  account_widget_handle_apply_sensitivity (self);
-
-  return FALSE;
+static void
+account_widget_entry_changed_cb (GtkEditable *entry,
+    EmpathyAccountWidget *self)
+{
+  account_widget_entry_changed_common (self, GTK_ENTRY (entry), FALSE);
+  account_widget_handle_control_buttons_sensitivity (self);
 }
 
 static void
@@ -121,7 +171,8 @@ account_widget_int_changed_cb (GtkWidget *widget,
   value = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
   param_name = g_object_get_data (G_OBJECT (widget), "param_name");
 
-  signature = empathy_settings_get_dbus_signature (priv->settings, param_name);
+  signature = empathy_account_settings_get_dbus_signature (priv->settings,
+    param_name);
   g_return_if_fail (signature != NULL);
 
   DEBUG ("Setting %s to %d", param_name, value);
@@ -145,8 +196,8 @@ account_widget_int_changed_cb (GtkWidget *widget,
     default:
       g_return_if_reached ();
     }
-       
-  account_widget_handle_apply_sensitivity (self);
+
+  account_widget_handle_control_buttons_sensitivity (self);
 }
 
 static void
@@ -165,7 +216,8 @@ account_widget_checkbutton_toggled_cb (GtkWidget *widget,
    * always unset the param and set the value if different from the
    * default value. */
   empathy_account_settings_unset (priv->settings, param_name);
-  default_value = empathy_account_settings_get_boolean (priv->settings, param_name);
+  default_value = empathy_account_settings_get_boolean (priv->settings,
+      param_name);
 
   if (default_value == value)
     {
@@ -176,8 +228,8 @@ account_widget_checkbutton_toggled_cb (GtkWidget *widget,
       DEBUG ("Setting %s to %d", param_name, value);
       empathy_account_settings_set_boolean (priv->settings, param_name, value);
     }
-       
-  account_widget_handle_apply_sensitivity (self);
+
+  account_widget_handle_control_buttons_sensitivity (self);
 }
 
 static void
@@ -187,13 +239,14 @@ account_widget_forget_clicked_cb (GtkWidget *button,
   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
   const gchar *param_name;
 
-  param_name = g_object_get_data (G_OBJECT (priv->entry_password), "param_name");
+  param_name = g_object_get_data (G_OBJECT (priv->entry_password),
+      "param_name");
 
   DEBUG ("Unset %s", param_name);
   empathy_account_settings_unset (priv->settings, param_name);
   gtk_entry_set_text (GTK_ENTRY (priv->entry_password), "");
 
-  account_widget_handle_apply_sensitivity (self);
+  account_widget_handle_control_buttons_sensitivity (self);
 }
 
 static void
@@ -238,7 +291,7 @@ account_widget_setup_widget (EmpathyAccountWidget *self,
     const gchar *param_name)
 {
   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
-       
+
   g_object_set_data_full (G_OBJECT (widget), "param_name",
       g_strdup (param_name), g_free);
 
@@ -247,27 +300,32 @@ account_widget_setup_widget (EmpathyAccountWidget *self,
       gint value = 0;
       const gchar *signature;
 
-      signature = empathy_settings_get_dbus_signature (priv->settings, param_name);
+      signature = empathy_account_settings_get_dbus_signature (priv->settings,
+          param_name);
       g_return_if_fail (signature != NULL);
 
       switch ((int)*signature)
         {
-        case DBUS_TYPE_INT16:
-        case DBUS_TYPE_INT32:
-          value = empathy_account_settings_get_int32 (priv->settings, param_name);
-          break;
-        case DBUS_TYPE_INT64:
-          value = empathy_account_settings_get_int64 (priv->settings, param_name);
-          break;
-        case DBUS_TYPE_UINT16:
-        case DBUS_TYPE_UINT32:
-          value = empathy_account_settings_get_uint32 (priv->settings, param_name);
-          break;
-        case DBUS_TYPE_UINT64:
-          value = empathy_account_settings_get_uint64 (priv->settings, param_name);
-          break;
-        default:
-          g_return_if_reached ();
+          case DBUS_TYPE_INT16:
+          case DBUS_TYPE_INT32:
+            value = empathy_account_settings_get_int32 (priv->settings,
+              param_name);
+            break;
+          case DBUS_TYPE_INT64:
+            value = empathy_account_settings_get_int64 (priv->settings,
+              param_name);
+            break;
+          case DBUS_TYPE_UINT16:
+          case DBUS_TYPE_UINT32:
+            value = empathy_account_settings_get_uint32 (priv->settings,
+              param_name);
+            break;
+          case DBUS_TYPE_UINT64:
+            value = empathy_account_settings_get_uint64 (priv->settings,
+                param_name);
+            break;
+          default:
+            g_return_if_reached ();
         }
 
       gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
@@ -288,15 +346,15 @@ account_widget_setup_widget (EmpathyAccountWidget *self,
           gtk_entry_set_visibility (GTK_ENTRY (widget), FALSE);
         }
 
-      g_signal_connect (widget, "focus-out-event",
-          G_CALLBACK (account_widget_entry_focus_cb),
-          self);
+      g_signal_connect (widget, "changed",
+          G_CALLBACK (account_widget_entry_changed_cb), self);
     }
   else if (GTK_IS_TOGGLE_BUTTON (widget))
     {
       gboolean value = FALSE;
 
-      value = empathy_account_settings_get_boolean (priv->settings, param_name);
+      value = empathy_account_settings_get_boolean (priv->settings,
+          param_name);
       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), value);
 
       g_signal_connect (widget, "toggled",
@@ -353,10 +411,13 @@ accounts_widget_generic_setup (EmpathyAccountWidget *self,
 
       if (param->flags & TP_CONN_MGR_PARAM_FLAG_REQUIRED)
         table_settings = table_common_settings;
+      else if (priv->simple)
+        return;
       else
         table_settings = table_advanced_settings;
 
-      param_name_formatted = account_widget_generic_format_param_name (param->name);
+      param_name_formatted = account_widget_generic_format_param_name
+        (param->name);
       g_object_get (table_settings, "n-rows", &n_rows, NULL);
       gtk_table_resize (GTK_TABLE (table_settings), ++n_rows, 2);
 
@@ -416,7 +477,8 @@ accounts_widget_generic_setup (EmpathyAccountWidget *self,
             case 'u': minint = 0;          maxint = G_MAXUINT32; break;
             case 'x': minint = G_MININT64; maxint = G_MAXINT64;  break;
             case 't': minint = 0;          maxint = G_MAXUINT64; break;
-            case 'd': minint = G_MININT32; maxint = G_MAXINT32; step = 0.1; break;
+            case 'd': minint = G_MININT32; maxint = G_MAXINT32;
+              step = 0.1; break;
             }
 
           str = g_strdup_printf (_("%s:"), param_name_formatted);
@@ -490,13 +552,100 @@ account_widget_handle_params_valist (EmpathyAccountWidget *self,
     }
 }
 
+static void
+account_widget_cancel_clicked_cb (GtkWidget *button,
+    EmpathyAccountWidget *self)
+{
+  g_signal_emit (self, signals[CANCELLED], 0);
+}
+
+static void
+account_widget_account_enabled_cb (GObject *source_object,
+    GAsyncResult *res,
+    gpointer user_data)
+{
+  GError *error = NULL;
+  EmpathyAccount *account = EMPATHY_ACCOUNT (source_object);
+  EmpathyAccountWidget *widget = EMPATHY_ACCOUNT_WIDGET (user_data);
+
+  empathy_account_set_enabled_finish (account, res, &error);
+
+  if (error != NULL)
+    {
+      DEBUG ("Could not automatically enable new account: %s", error->message);
+      g_error_free (error);
+    }
+  else
+    {
+      g_signal_emit (widget, signals[ACCOUNT_CREATED], 0);
+    }
+}
+
+static void
+account_widget_applied_cb (GObject *source_object,
+    GAsyncResult *res,
+    gpointer user_data)
+{
+  GError *error = NULL;
+  EmpathyAccount *account;
+  EmpathyAccountSettings *settings = EMPATHY_ACCOUNT_SETTINGS (source_object);
+  EmpathyAccountWidget *widget = EMPATHY_ACCOUNT_WIDGET (user_data);
+  EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
+
+  empathy_account_settings_apply_finish (settings, res, &error);
+
+  if (error != NULL)
+    {
+      DEBUG ("Could not apply changes to account: %s", error->message);
+      g_error_free (error);
+      return;
+    }
+
+  account = empathy_account_settings_get_account (priv->settings);
+
+  if (account != NULL)
+    {
+      if (priv->creating_account)
+        {
+          /* By default, when an account is created, we enable it. */
+          empathy_account_set_enabled_async (account, TRUE,
+              account_widget_account_enabled_cb, widget);
+        }
+      else if (priv->enabled_checkbox != NULL)
+        {
+          gboolean enabled_checked;
+
+          enabled_checked = gtk_toggle_button_get_active (
+              GTK_TOGGLE_BUTTON (priv->enabled_checkbox));
+
+          if (empathy_account_is_enabled (account) && enabled_checked)
+            {
+              /* After having applied changes to a user account, we
+               * automatically reconnect it. This is done so the new
+               * information entered by the user is validated on the server. */
+              empathy_account_reconnect_async (account, NULL, NULL);
+            }
+          else
+            {
+              /* The account is disabled so we enable it according to the value
+               * of the "Enabled" checkbox */
+              empathy_account_set_enabled_async (account, enabled_checked,
+                  NULL, NULL);
+            }
+        }
+    }
+
+  account_widget_set_control_buttons_sensitivity (widget, FALSE);
+}
+
 static void
 account_widget_apply_clicked_cb (GtkWidget *button,
     EmpathyAccountWidget *self)
 {
   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
-       
-  empathy_account_settings_apply_async (priv->settings, NULL, NULL);
+
+  empathy_account_settings_apply_async (priv->settings,
+      account_widget_applied_cb, self);
 }
 
 static void
@@ -505,10 +654,10 @@ account_widget_setup_generic (EmpathyAccountWidget *self)
   GtkWidget *table_common_settings;
   GtkWidget *table_advanced_settings;
 
-  table_common_settings = GTK_WIDGET (gtk_builder_get_object (self->ui_details->gui,
-          "table_common_settings"));
-  table_advanced_settings = GTK_WIDGET (gtk_builder_get_object (self->ui_details->gui,
-          "table_advanced_settings"));
+  table_common_settings = GTK_WIDGET (gtk_builder_get_object
+      (self->ui_details->gui, "table_common_settings"));
+  table_advanced_settings = GTK_WIDGET (gtk_builder_get_object
+      (self->ui_details->gui, "table_advanced_settings"));
 
   accounts_widget_generic_setup (self, table_common_settings,
       table_advanced_settings);
@@ -533,10 +682,17 @@ account_widget_build_generic (EmpathyAccountWidget *self,
     const char *filename)
 {
   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
+  GtkWidget *expander_advanced;
+
   self->ui_details->gui = empathy_builder_get_file (filename,
+      "table_common_settings", &priv->table_common_settings,
       "vbox_generic_settings", &self->ui_details->widget,
+      "expander_advanced_settings", &expander_advanced,
       NULL);
 
+  if (priv->simple)
+    gtk_widget_hide (expander_advanced);
+
   g_object_ref (self->ui_details->gui);
 
   if (empathy_account_settings_is_ready (priv->settings))
@@ -550,7 +706,10 @@ static void
 account_widget_build_salut (EmpathyAccountWidget *self,
     const char *filename)
 {
+  EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
+
   self->ui_details->gui = empathy_builder_get_file (filename,
+      "table_common_settings", &priv->table_common_settings,
       "vbox_salut_settings", &self->ui_details->widget,
       NULL);
 
@@ -566,23 +725,60 @@ account_widget_build_salut (EmpathyAccountWidget *self,
   self->ui_details->default_focus = g_strdup ("entry_nickname");
 }
 
+static void
+account_widget_build_irc (EmpathyAccountWidget *self,
+  const char *filename)
+{
+  EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
+  empathy_account_widget_irc_build (self, filename,
+    &priv->table_common_settings);
+}
+
+static void
+account_widget_build_sip (EmpathyAccountWidget *self,
+  const char *filename)
+{
+  EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
+  empathy_account_widget_sip_build (self, filename,
+    &priv->table_common_settings);
+}
+
 static void
 account_widget_build_msn (EmpathyAccountWidget *self,
     const char *filename)
 {
-  self->ui_details->gui = empathy_builder_get_file (filename,
-      "vbox_msn_settings", &self->ui_details->widget,
-      NULL);
+  EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
 
-  empathy_account_widget_handle_params (self,
-      "entry_id", "account",
-      "entry_password", "password",
-      "entry_server", "server",
-      "spinbutton_port", "port",
-      NULL);
+  if (priv->simple)
+    {
+      self->ui_details->gui = empathy_builder_get_file (filename,
+          "vbox_msn_simple", &self->ui_details->widget,
+          NULL);
+
+      empathy_account_widget_handle_params (self,
+          "entry_id_simple", "account",
+          "entry_password_simple", "password",
+          NULL);
+
+      self->ui_details->default_focus = g_strdup ("entry_id_simple");
+    }
+  else
+    {
+      self->ui_details->gui = empathy_builder_get_file (filename,
+          "table_common_msn_settings", &priv->table_common_settings,
+          "vbox_msn_settings", &self->ui_details->widget,
+          NULL);
 
-  self->ui_details->default_focus = g_strdup ("entry_id");
-  self->ui_details->add_forget = TRUE;
+      empathy_account_widget_handle_params (self,
+          "entry_id", "account",
+          "entry_password", "password",
+          "entry_server", "server",
+          "spinbutton_port", "port",
+          NULL);
+
+      self->ui_details->default_focus = g_strdup ("entry_id");
+      self->ui_details->add_forget = TRUE;
+    }
 }
 
 static void
@@ -592,119 +788,255 @@ account_widget_build_jabber (EmpathyAccountWidget *self,
   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
   GtkWidget *spinbutton_port;
   GtkWidget *checkbutton_ssl;
+  GtkWidget *label_id, *label_password;
+  GtkWidget *label_id_create, *label_password_create;
 
-  self->ui_details->gui = empathy_builder_get_file (filename,
-      "vbox_jabber_settings", &self->ui_details->widget,
-      "spinbutton_port", &spinbutton_port,
-      "checkbutton_ssl", &checkbutton_ssl,
-      NULL);
+  if (priv->simple)
+    {
+      self->ui_details->gui = empathy_builder_get_file (filename,
+          "vbox_jabber_simple", &self->ui_details->widget,
+          "label_id_simple", &label_id,
+          "label_id_create", &label_id_create,
+          "label_password_simple", &label_password,
+          "label_password_create", &label_password_create,
+          NULL);
 
-  empathy_account_widget_handle_params (self,
-      "entry_id", "account",
-      "entry_password", "password",
-      "entry_resource", "resource",
-      "entry_server", "server",
-      "spinbutton_port", "port",
-      "spinbutton_priority", "priority",
-      "checkbutton_ssl", "old-ssl",
-      "checkbutton_ignore_ssl_errors", "ignore-ssl-errors",
-      "checkbutton_encryption", "require-encryption",
-      NULL);
+      if (empathy_account_settings_get_boolean (priv->settings, "register"))
+        {
+          gtk_widget_hide (label_id);
+          gtk_widget_hide (label_password);
+          gtk_widget_show (label_id_create);
+          gtk_widget_show (label_password_create);
+        }
 
-  self->ui_details->default_focus = g_strdup ("entry_id");
-  self->ui_details->add_forget = TRUE;
-  priv->spinbutton_port = spinbutton_port;
+      empathy_account_widget_handle_params (self,
+          "entry_id_simple", "account",
+          "entry_password_simple", "password",
+          NULL);
 
-  g_signal_connect (checkbutton_ssl, "toggled",
-      G_CALLBACK (account_widget_jabber_ssl_toggled_cb),
-      self);
+      self->ui_details->default_focus = g_strdup ("entry_id_simple");
+    }
+  else
+    {
+      self->ui_details->gui = empathy_builder_get_file (filename,
+          "table_common_settings", &priv->table_common_settings,
+          "vbox_jabber_settings", &self->ui_details->widget,
+          "spinbutton_port", &spinbutton_port,
+          "checkbutton_ssl", &checkbutton_ssl,
+          NULL);
+
+      empathy_account_widget_handle_params (self,
+          "entry_id", "account",
+          "entry_password", "password",
+          "entry_resource", "resource",
+          "entry_server", "server",
+          "spinbutton_port", "port",
+          "spinbutton_priority", "priority",
+          "checkbutton_ssl", "old-ssl",
+          "checkbutton_ignore_ssl_errors", "ignore-ssl-errors",
+          "checkbutton_encryption", "require-encryption",
+          NULL);
+
+      self->ui_details->default_focus = g_strdup ("entry_id");
+      self->ui_details->add_forget = TRUE;
+      priv->spinbutton_port = spinbutton_port;
+
+      g_signal_connect (checkbutton_ssl, "toggled",
+          G_CALLBACK (account_widget_jabber_ssl_toggled_cb),
+          self);
+    }
 }
 
 static void
 account_widget_build_icq (EmpathyAccountWidget *self,
     const char *filename)
 {
+  EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
   GtkWidget *spinbutton_port;
 
-  self->ui_details->gui = empathy_builder_get_file (filename,
-      "vbox_icq_settings", &self->ui_details->widget,
-      "spinbutton_port", &spinbutton_port,
-      NULL);
+  if (priv->simple)
+    {
+      self->ui_details->gui = empathy_builder_get_file (filename,
+          "vbox_icq_simple", &self->ui_details->widget,
+          NULL);
 
-  empathy_account_widget_handle_params (self,
-      "entry_uin", "account",
-      "entry_password", "password",
-      "entry_server", "server",
-      "spinbutton_port", "port",
-      "entry_charset", "charset",
-      NULL);
+      empathy_account_widget_handle_params (self,
+          "entry_uin_simple", "account",
+          "entry_password_simple", "password",
+          NULL);
+
+      self->ui_details->default_focus = g_strdup ("entry_uin_simple");
+    }
+  else
+    {
+      self->ui_details->gui = empathy_builder_get_file (filename,
+          "table_common_settings", &priv->table_common_settings,
+          "vbox_icq_settings", &self->ui_details->widget,
+          "spinbutton_port", &spinbutton_port,
+          NULL);
 
-  self->ui_details->default_focus = g_strdup ("entry_uin");
-  self->ui_details->add_forget = TRUE;
+      empathy_account_widget_handle_params (self,
+          "entry_uin", "account",
+          "entry_password", "password",
+          "entry_server", "server",
+          "spinbutton_port", "port",
+          "entry_charset", "charset",
+          NULL);
+
+      self->ui_details->default_focus = g_strdup ("entry_uin");
+      self->ui_details->add_forget = TRUE;
+    }
 }
 
 static void
 account_widget_build_aim (EmpathyAccountWidget *self,
     const char *filename)
 {
+  EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
   GtkWidget *spinbutton_port;
 
-  self->ui_details->gui = empathy_builder_get_file (filename,
-      "vbox_aim_settings", &self->ui_details->widget,
-      "spinbutton_port", &spinbutton_port,
-      NULL);
+  if (priv->simple)
+    {
+      self->ui_details->gui = empathy_builder_get_file (filename,
+          "vbox_aim_simple", &self->ui_details->widget,
+          NULL);
 
-  empathy_account_widget_handle_params (self,
-      "entry_screenname", "account",
-      "entry_password", "password",
-      "entry_server", "server",
-      "spinbutton_port", "port",
-      NULL);
+      empathy_account_widget_handle_params (self,
+          "entry_screenname_simple", "account",
+          "entry_password_simple", "password",
+          NULL);
 
-  self->ui_details->default_focus = g_strdup ("entry_screenname");
-  self->ui_details->add_forget = TRUE;
+      self->ui_details->default_focus = g_strdup ("entry_screenname_simple");
+    }
+  else
+    {
+      self->ui_details->gui = empathy_builder_get_file (filename,
+          "table_common_settings", &priv->table_common_settings,
+          "vbox_aim_settings", &self->ui_details->widget,
+          "spinbutton_port", &spinbutton_port,
+          NULL);
+
+      empathy_account_widget_handle_params (self,
+          "entry_screenname", "account",
+          "entry_password", "password",
+          "entry_server", "server",
+          "spinbutton_port", "port",
+          NULL);
+
+      self->ui_details->default_focus = g_strdup ("entry_screenname");
+      self->ui_details->add_forget = TRUE;
+    }
 }
 
 static void
 account_widget_build_yahoo (EmpathyAccountWidget *self,
     const char *filename)
 {
-  self->ui_details->gui = empathy_builder_get_file (filename,
-      "vbox_yahoo_settings", &self->ui_details->widget,
-      NULL);
+  EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
 
-  empathy_account_widget_handle_params (self,
-      "entry_id", "account",
-      "entry_password", "password",
-      "entry_server", "server",
-      "entry_locale", "room-list-locale",
-      "entry_charset", "charset",
-      "spinbutton_port", "port",
-      "checkbutton_yahoojp", "yahoojp",
-      "checkbutton_ignore_invites", "ignore-invites",
-      NULL);
+  if (priv->simple)
+    {
+      self->ui_details->gui = empathy_builder_get_file (filename,
+          "vbox_yahoo_simple", &self->ui_details->widget,
+          NULL);
+
+      empathy_account_widget_handle_params (self,
+          "entry_id_simple", "account",
+          "entry_password_simple", "password",
+          NULL);
+
+      self->ui_details->default_focus = g_strdup ("entry_id_simple");
+    }
+  else
+    {
+      self->ui_details->gui = empathy_builder_get_file (filename,
+          "table_common_settings", &priv->table_common_settings,
+          "vbox_yahoo_settings", &self->ui_details->widget,
+          NULL);
 
-  self->ui_details->default_focus = g_strdup ("entry_id");
-  self->ui_details->add_forget = TRUE;
+      empathy_account_widget_handle_params (self,
+          "entry_id", "account",
+          "entry_password", "password",
+          "entry_server", "server",
+          "entry_locale", "room-list-locale",
+          "entry_charset", "charset",
+          "spinbutton_port", "port",
+          "checkbutton_yahoojp", "yahoojp",
+          "checkbutton_ignore_invites", "ignore-invites",
+          NULL);
+
+      self->ui_details->default_focus = g_strdup ("entry_id");
+      self->ui_details->add_forget = TRUE;
+    }
 }
 
 static void
 account_widget_build_groupwise (EmpathyAccountWidget *self,
     const char *filename)
 {
-  self->ui_details->gui = empathy_builder_get_file (filename,
-      "vbox_groupwise_settings", &self->ui_details->widget,
-      NULL);
+  EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
 
-  empathy_account_widget_handle_params (self,
-      "entry_id", "account",
-      "entry_password", "password",
-      "entry_server", "server",
-      "spinbutton_port", "port",
-      NULL);
+  if (priv->simple)
+    {
+      self->ui_details->gui = empathy_builder_get_file (filename,
+          "vbox_groupwise_simple", &self->ui_details->widget,
+          NULL);
+
+      empathy_account_widget_handle_params (self,
+          "entry_id_simple", "account",
+          "entry_password_simple", "password",
+          NULL);
+
+      self->ui_details->default_focus = g_strdup ("entry_id_simple");
+    }
+  else
+    {
+      self->ui_details->gui = empathy_builder_get_file (filename,
+          "table_common_groupwise_settings", &priv->table_common_settings,
+          "vbox_groupwise_settings", &self->ui_details->widget,
+          NULL);
+
+      empathy_account_widget_handle_params (self,
+          "entry_id", "account",
+          "entry_password", "password",
+          "entry_server", "server",
+          "spinbutton_port", "port",
+          NULL);
+
+      self->ui_details->default_focus = g_strdup ("entry_id");
+      self->ui_details->add_forget = TRUE;
+    }
+}
+
+static void
+account_widget_destroy_cb (GtkWidget *widget,
+    EmpathyAccountWidget *self)
+{
+  g_object_unref (self);
+}
+
+static void
+empathy_account_widget_enabled_cb (EmpathyAccount *account,
+      GParamSpec *spec,
+      gpointer user_data)
+{
+  EmpathyAccountWidget *widget = EMPATHY_ACCOUNT_WIDGET (user_data);
+  EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
+  gboolean enabled = empathy_account_is_enabled (account);
+
+  if (priv->enabled_checkbox != NULL)
+    {
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->enabled_checkbox),
+          enabled);
+    }
+}
 
-  self->ui_details->default_focus = g_strdup ("entry_id");
-  self->ui_details->add_forget = TRUE;
+static void
+account_widget_enabled_released_cb (GtkToggleButton *toggle_button,
+    gpointer user_data)
+{
+  account_widget_handle_control_buttons_sensitivity (
+      EMPATHY_ACCOUNT_WIDGET (user_data));
 }
 
 static void
@@ -717,12 +1049,15 @@ do_set_property (GObject *object,
 
   switch (prop_id)
     {
-    case PROP_PROTOCOL:
-      priv->protocol = g_value_dup_string (value);
-      break;
     case PROP_SETTINGS:
       priv->settings = g_value_dup_object (value);
       break;
+    case PROP_SIMPLE:
+      priv->simple = g_value_get_boolean (value);
+      break;
+    case PROP_CREATING_ACCOUNT:
+      priv->creating_account = g_value_get_boolean (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -739,57 +1074,79 @@ do_get_property (GObject *object,
   switch (prop_id)
     {
     case PROP_PROTOCOL:
-      g_value_set_string (value, priv->protocol);
+      g_value_set_string (value,
+        empathy_account_settings_get_protocol (priv->settings));
       break;
     case PROP_SETTINGS:
       g_value_set_object (value, priv->settings);
       break;
+    case PROP_SIMPLE:
+      g_value_set_boolean (value, priv->simple);
+      break;
+    case PROP_CREATING_ACCOUNT:
+      g_value_set_boolean (value, priv->creating_account);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
 }
 
+#define WIDGET(cm, proto) \
+  { #cm, #proto, "empathy-account-widget-"#proto".ui", \
+    account_widget_build_##proto }
+
 static void
 do_constructed (GObject *obj)
-{      
+{
   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
-  char *uiname, *filename;
-
-  uiname = g_strconcat ("empathy-account-widget-", priv->protocol,
-      ".ui", NULL);
-  filename = empathy_file_lookup (uiname, "libempathy-gtk");
-
-  if (!tp_strdiff (priv->protocol, "local-xmpp"))
-    account_widget_build_salut (self, filename);
-  else if (!tp_strdiff (priv->protocol, "msn"))
-    account_widget_build_msn (self, filename);
-  else if (!tp_strdiff (priv->protocol, "jabber"))
-    account_widget_build_jabber (self, filename);
-  else if (!tp_strdiff (priv->protocol, "icq"))
-    account_widget_build_icq (self, filename);
-  else if (!tp_strdiff (priv->protocol, "aim"))
-    account_widget_build_aim (self, filename);
-  else if (!tp_strdiff (priv->protocol, "yahoo"))
-    account_widget_build_yahoo (self, filename);
-  else if (!tp_strdiff (priv->protocol, "groupwise"))
-    account_widget_build_groupwise (self, filename);
-  else if (!tp_strdiff (priv->protocol, "irc"))
-    empathy_account_widget_irc_build (self, filename);
-  else if (!tp_strdiff (priv->protocol, "sip"))
-    empathy_account_widget_sip_build (self, filename);
-  else if (!tp_strdiff (priv->protocol, "generic"))
-    account_widget_build_generic (self, filename);
-  else
+  EmpathyAccount *account;
+  const gchar *protocol, *cm_name;
+  int i = 0;
+  struct {
+    const gchar *cm_name;
+    const gchar *protocol;
+    const char *file;
+    void (*func)(EmpathyAccountWidget *self, const gchar *filename);
+  } widgets [] = {
+    { "salut", "local-xmpp", "empathy-account-widget-local-xmpp.ui",
+        account_widget_build_salut },
+    WIDGET (gabble, jabber),
+    WIDGET (butterfly, msn),
+    WIDGET (haze, icq),
+    WIDGET (haze, aim),
+    WIDGET (haze, yahoo),
+    WIDGET (haze, groupwise),
+    WIDGET (idle, irc),
+    WIDGET (sofiasip, sip),
+  };
+
+  cm_name = empathy_account_settings_get_cm (priv->settings);
+  protocol = empathy_account_settings_get_protocol (priv->settings);
+
+  for (i = 0 ; i < G_N_ELEMENTS (widgets); i++)
     {
-      g_free (uiname);
-      g_free (filename);
-      g_critical ("Unknown protocol, can't build the account widget");
-      return;
+      if (!tp_strdiff (widgets[i].cm_name, cm_name) &&
+          !tp_strdiff (widgets[i].protocol, protocol))
+        {
+          gchar *filename;
+
+          filename = empathy_file_lookup (widgets[i].file,
+              "libempathy-gtk");
+          widgets[i].func (self, filename);
+          g_free (filename);
+
+          break;
+        }
     }
 
-  g_free (uiname);
-  g_free (filename);
+  if (i == G_N_ELEMENTS (widgets))
+    {
+      gchar *filename = empathy_file_lookup (
+          "empathy-account-widget-generic.ui", "libempathy-gtk");
+      account_widget_build_generic (self, filename);
+      g_free (filename);
+    }
 
   /* handle default focus */
   if (self->ui_details->default_focus != NULL)
@@ -808,31 +1165,95 @@ do_constructed (GObject *obj)
     {
       const gchar *password = NULL;
 
-      priv->button_forget = GTK_WIDGET (gtk_builder_get_object (self->ui_details->gui, "button_forget"));
-      priv->entry_password = GTK_WIDGET (gtk_builder_get_object (self->ui_details->gui, "entry_password"));
+      priv->button_forget = GTK_WIDGET (gtk_builder_get_object
+          (self->ui_details->gui, "button_forget"));
+      priv->entry_password = GTK_WIDGET (gtk_builder_get_object
+          (self->ui_details->gui, "entry_password"));
 
-      password = empathy_account_settings_get_string (priv->settings, "password");
-      gtk_widget_set_sensitive (priv->button_forget, !EMP_STR_EMPTY (password));
+      password = empathy_account_settings_get_string (priv->settings,
+          "password");
+      gtk_widget_set_sensitive (priv->button_forget,
+          !EMP_STR_EMPTY (password));
 
       g_signal_connect (priv->button_forget, "clicked",
           G_CALLBACK (account_widget_forget_clicked_cb),
           self);
       g_signal_connect (priv->entry_password, "changed",
           G_CALLBACK (account_widget_password_changed_cb),
-          self);  
+          self);
+    }
+
+  /* handle apply and cancel button */
+  if (!priv->simple)
+    {
+      GtkWidget *hbox = gtk_hbox_new (TRUE, 3);
+
+      priv->cancel_button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
+      priv->apply_button = gtk_button_new_from_stock (
+        priv->creating_account ? GTK_STOCK_CONNECT : GTK_STOCK_APPLY);
+
+      gtk_box_pack_end (GTK_BOX (hbox), priv->apply_button, TRUE,
+          TRUE, 3);
+      gtk_box_pack_end (GTK_BOX (hbox), priv->cancel_button, TRUE,
+          TRUE, 3);
+
+      gtk_box_pack_end (GTK_BOX (self->ui_details->widget), hbox, FALSE,
+          FALSE, 3);
+
+      g_signal_connect (priv->cancel_button, "clicked",
+          G_CALLBACK (account_widget_cancel_clicked_cb),
+          self);
+      g_signal_connect (priv->apply_button, "clicked",
+          G_CALLBACK (account_widget_apply_clicked_cb),
+          self);
+      gtk_widget_show_all (hbox);
+      account_widget_set_control_buttons_sensitivity (self, FALSE);
+    }
+
+  account = empathy_account_settings_get_account (priv->settings);
+
+  if (account != NULL)
+    {
+      g_signal_connect (account, "notify::enabled",
+          G_CALLBACK (empathy_account_widget_enabled_cb), self);
     }
 
-  /* handle apply button */
-  priv->apply_button = gtk_button_new_from_stock (GTK_STOCK_APPLY);
-  gtk_box_pack_end (GTK_BOX (self->ui_details->widget), priv->apply_button, FALSE, FALSE, 3);
+  /* handle the "Enabled" checkbox. We only add it when modifying an account */
+  if (!priv->creating_account && priv->table_common_settings != NULL)
+    {
+      guint nb_rows, nb_columns;
+
+      priv->enabled_checkbox =
+          gtk_check_button_new_with_label (_("Enabled"));
+      priv->original_enabled_checkbox_value =
+          empathy_account_is_enabled (account);
+      gtk_toggle_button_set_active (
+          GTK_TOGGLE_BUTTON (priv->enabled_checkbox),
+          priv->original_enabled_checkbox_value);
+
+      g_object_get (priv->table_common_settings, "n-rows", &nb_rows,
+          "n-columns", &nb_columns, NULL);
+
+      gtk_table_resize (GTK_TABLE (priv->table_common_settings), ++nb_rows,
+          nb_columns);
+
+      gtk_table_attach (GTK_TABLE (priv->table_common_settings),
+          priv->enabled_checkbox, 0, nb_columns, nb_rows - 1, nb_rows,
+          GTK_EXPAND | GTK_FILL, 0, 0, 0);
+
+      gtk_widget_show (priv->enabled_checkbox);
+
+      g_signal_connect (G_OBJECT (priv->enabled_checkbox), "released",
+          G_CALLBACK (account_widget_enabled_released_cb), self);
+    }
 
-  g_signal_connect (priv->apply_button, "clicked",
-      G_CALLBACK (account_widget_apply_clicked_cb),
-      self);
-  account_widget_handle_apply_sensitivity (self);
-  gtk_widget_show (priv->apply_button);
+  /* hook up to widget destruction to unref ourselves */
+  g_signal_connect (self->ui_details->widget, "destroy",
+      G_CALLBACK (account_widget_destroy_cb), self);
 
-  empathy_builder_unref_and_keep_widget (self->ui_details->gui, self->ui_details->widget);
+  empathy_builder_unref_and_keep_widget (self->ui_details->gui,
+      self->ui_details->widget);
+  self->ui_details->gui = NULL;
 }
 
 static void
@@ -846,14 +1267,19 @@ do_dispose (GObject *obj)
 
   priv->dispose_run = TRUE;
 
-  if (self->ui_details->gui != NULL)
-    {
-      g_object_unref (self->ui_details->gui);
-      self->ui_details->gui = NULL;
-    }
+  empathy_account_settings_is_ready (priv->settings);
 
   if (priv->settings != NULL)
     {
+      EmpathyAccount *account;
+      account = empathy_account_settings_get_account (priv->settings);
+
+      if (account != NULL)
+        {
+          g_signal_handlers_disconnect_by_func (account,
+              empathy_account_widget_enabled_cb, self);
+        }
+
       g_object_unref (priv->settings);
       priv->settings = NULL;
     }
@@ -866,13 +1292,10 @@ static void
 do_finalize (GObject *obj)
 {
   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
-  EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
 
   g_free (self->ui_details->default_focus);
   g_slice_free (EmpathyAccountWidgetUIDetails, self->ui_details);
 
-  g_free (priv->protocol);
-
   if (G_OBJECT_CLASS (empathy_account_widget_parent_class)->finalize != NULL)
     G_OBJECT_CLASS (empathy_account_widget_parent_class)->finalize (obj);
 }
@@ -892,14 +1315,49 @@ empathy_account_widget_class_init (EmpathyAccountWidgetClass *klass)
   param_spec = g_param_spec_string ("protocol",
       "protocol", "The protocol of the account",
       NULL,
-      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
+      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
   g_object_class_install_property (oclass, PROP_PROTOCOL, param_spec);
 
   param_spec = g_param_spec_object ("settings",
       "settings", "The settings of the account",
       EMPATHY_TYPE_ACCOUNT_SETTINGS,
       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
-  g_object_class_install_property (oclass, PROP_SETTINGS, param_spec); 
+  g_object_class_install_property (oclass, PROP_SETTINGS, param_spec);
+
+  param_spec = g_param_spec_boolean ("simple",
+      "simple", "Whether the account widget is a simple or an advanced one",
+      FALSE,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
+  g_object_class_install_property (oclass, PROP_SIMPLE, param_spec);
+
+  param_spec = g_param_spec_boolean ("creating-account",
+      "creating-account",
+      "TRUE if we're creating an account, FALSE if we're modifying it",
+      FALSE,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
+  g_object_class_install_property (oclass, PROP_CREATING_ACCOUNT, param_spec);
+
+  signals[HANDLE_APPLY] =
+    g_signal_new ("handle-apply", G_TYPE_FROM_CLASS (klass),
+        G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+        g_cclosure_marshal_VOID__BOOLEAN,
+        G_TYPE_NONE,
+        1, G_TYPE_BOOLEAN);
+
+  /* This signal is emitted when an account has been created and enabled. */
+  signals[ACCOUNT_CREATED] =
+      g_signal_new ("account-created", G_TYPE_FROM_CLASS (klass),
+          G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+          g_cclosure_marshal_VOID__VOID,
+          G_TYPE_NONE,
+          0);
+
+  signals[CANCELLED] =
+      g_signal_new ("cancelled", G_TYPE_FROM_CLASS (klass),
+          G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+          g_cclosure_marshal_VOID__VOID,
+          G_TYPE_NONE,
+          0);
 
   g_type_class_add_private (klass, sizeof (EmpathyAccountWidgetPriv));
 }
@@ -907,7 +1365,7 @@ empathy_account_widget_class_init (EmpathyAccountWidgetClass *klass)
 static void
 empathy_account_widget_init (EmpathyAccountWidget *self)
 {
-  EmpathyAccountWidgetPriv *priv = 
+  EmpathyAccountWidgetPriv *priv =
     G_TYPE_INSTANCE_GET_PRIVATE ((self), EMPATHY_TYPE_ACCOUNT_WIDGET,
         EmpathyAccountWidgetPriv);
 
@@ -919,6 +1377,26 @@ empathy_account_widget_init (EmpathyAccountWidget *self)
 
 /* public methods */
 
+void
+empathy_account_widget_discard_pending_changes
+    (EmpathyAccountWidget *widget)
+{
+  EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
+
+  empathy_account_settings_discard_changes (priv->settings);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->enabled_checkbox),
+      priv->original_enabled_checkbox_value);
+  priv->contains_pending_changes = FALSE;
+}
+
+gboolean
+empathy_account_widget_contains_pending_changes (EmpathyAccountWidget *widget)
+{
+  EmpathyAccountWidgetPriv *priv = GET_PRIV (widget);
+
+  return priv->contains_pending_changes;
+}
+
 void
 empathy_account_widget_handle_params (EmpathyAccountWidget *self,
     const gchar *first_widget,
@@ -932,19 +1410,25 @@ empathy_account_widget_handle_params (EmpathyAccountWidget *self,
 }
 
 GtkWidget *
-empathy_account_widget_new_for_protocol (const char *protocol,
-    EmpathyAccountSettings *settings)
+empathy_account_widget_get_widget (EmpathyAccountWidget *widget)
+{
+  return widget->ui_details->widget;
+}
+
+EmpathyAccountWidget *
+empathy_account_widget_new_for_protocol (EmpathyAccountSettings *settings,
+    gboolean simple)
 {
   EmpathyAccountWidget *self;
-  EmpathyAccountWidgetPriv *priv;
 
   g_return_val_if_fail (EMPATHY_IS_ACCOUNT_SETTINGS (settings), NULL);
-  g_return_val_if_fail (settings != NULL, NULL);
 
   self = g_object_new
-    (EMPATHY_TYPE_ACCOUNT_WIDGET, "protocol", protocol,
-        "settings", settings, NULL);
-  priv = GET_PRIV (self);
+    (EMPATHY_TYPE_ACCOUNT_WIDGET,
+        "settings", settings, "simple", simple,
+        "creating-account",
+        empathy_account_settings_get_account (settings) == NULL,
+        NULL);
 
-  return self->ui_details->widget;
+  return self;
 }