]> git.0d.be Git - empathy.git/blobdiff - libempathy-gtk/empathy-account-chooser.c
Merge branch 'sasl'
[empathy.git] / libempathy-gtk / empathy-account-chooser.c
index de6d55177a3ceb67602a4fe417dbae96f0ad2dbc..f1c0ec6b4e87ace664373999628b4f975d95e1ef 100644 (file)
@@ -1,6 +1,7 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
  * Copyright (C) 2005-2007 Imendio AB
+ * Copyright (C) 2007-2008 Collabora Ltd.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  *
  * You should have received a copy of the GNU General Public
  * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- * 
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA  02110-1301  USA
+ *
  * Authors: Martyn Russell <martyn@imendio.com>
+ *          Xavier Claessens <xclaesse@gmail.com>
  */
 
 #include "config.h"
 
 #include <string.h>
 
-#include <glib/gi18n.h>
+#include <glib/gi18n-lib.h>
 #include <gtk/gtk.h>
-#include <glade/glade.h>
 
-#include <libtelepathy/tp-conn.h>
-#include <libmissioncontrol/mc-account-monitor.h>
-#include <libmissioncontrol/mission-control.h>
+#include <telepathy-glib/account-manager.h>
+#include <telepathy-glib/util.h>
 
 #include <libempathy/empathy-utils.h>
 
 #include "empathy-ui-utils.h"
 #include "empathy-account-chooser.h"
 
-#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_ACCOUNT_CHOOSER, EmpathyAccountChooserPriv))
+#define DEBUG_FLAG EMPATHY_DEBUG_OTHER
+#include <libempathy/empathy-debug.h>
+
+/**
+ * SECTION:empathy-account-chooser
+ * @title:EmpathyAccountChooser
+ * @short_description: A widget used to choose from a list of accounts
+ * @include: libempathy-gtk/empathy-account-chooser.h
+ *
+ * #EmpathyAccountChooser is a widget which extends #GtkComboBox to provide
+ * a chooser of available accounts.
+ */
+
+/**
+ * EmpathyAccountChooser:
+ * @parent: parent object
+ *
+ * Widget which extends #GtkComboBox to provide a chooser of available accounts.
+ */
 
+#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccountChooser)
 typedef struct {
-       MissionControl                 *mc;
-       McAccountMonitor               *monitor;
+       TpAccountManager               *manager;
        gboolean                        set_active_item;
+       gboolean                        account_manually_set;
        gboolean                        has_all_option;
        EmpathyAccountChooserFilterFunc filter;
        gpointer                        filter_data;
+       gboolean                        ready;
 } EmpathyAccountChooserPriv;
 
 typedef struct {
        EmpathyAccountChooser *chooser;
-       McAccount             *account;
+       TpAccount             *account;
        gboolean               set;
 } SetAccountData;
 
+typedef struct {
+       EmpathyAccountChooser *chooser;
+       TpAccount             *account;
+       GtkTreeIter           *iter;
+} FilterResultCallbackData;
+
+static FilterResultCallbackData *
+filter_result_callback_data_new (EmpathyAccountChooser *chooser,
+                                TpAccount             *account,
+                                GtkTreeIter           *iter)
+{
+       FilterResultCallbackData *data;
+
+       data = g_slice_new0 (FilterResultCallbackData);
+       data->chooser = g_object_ref (chooser);
+       data->account = g_object_ref (account);
+       data->iter = gtk_tree_iter_copy (iter);
+
+       return data;
+}
+
+static void
+filter_result_callback_data_free (FilterResultCallbackData *data)
+{
+       g_object_unref (data->chooser);
+       g_object_unref (data->account);
+       gtk_tree_iter_free (data->iter);
+       g_slice_free (FilterResultCallbackData, data);
+}
+
+/* Distinguishes between store entries which are actually accounts, and special
+ * items like the "All" entry and the separator below it, so they can be sorted
+ * correctly. Higher-numbered entries will sort earlier.
+ */
+typedef enum {
+       ROW_ACCOUNT = 0,
+       ROW_SEPARATOR,
+       ROW_ALL
+} RowType;
+
 enum {
        COL_ACCOUNT_IMAGE,
        COL_ACCOUNT_TEXT,
        COL_ACCOUNT_ENABLED, /* Usually tied to connected state */
+       COL_ACCOUNT_ROW_TYPE,
        COL_ACCOUNT_POINTER,
        COL_ACCOUNT_COUNT
 };
 
-static void     account_chooser_finalize               (GObject                         *object);
-static void     account_chooser_get_property           (GObject                         *object,
-                                                       guint                            param_id,
-                                                       GValue                          *value,
-                                                       GParamSpec                      *pspec);
-static void     account_chooser_set_property           (GObject                         *object,
-                                                       guint                            param_id,
-                                                       const GValue                    *value,
-                                                       GParamSpec                      *pspec);
-static void     account_chooser_setup                  (EmpathyAccountChooser            *chooser);
-static void     account_chooser_account_created_cb     (McAccountMonitor                *monitor,
-                                                       const gchar                     *unique_name,
-                                                       EmpathyAccountChooser            *chooser);
-static void     account_chooser_account_add_foreach    (McAccount                       *account,
-                                                       EmpathyAccountChooser            *chooser);
-static void     account_chooser_account_deleted_cb     (McAccountMonitor                *monitor,
-                                                       const gchar                     *unique_name,
-                                                       EmpathyAccountChooser            *chooser);
-static void     account_chooser_account_remove_foreach (McAccount                       *account,
-                                                       EmpathyAccountChooser            *chooser);
-static void     account_chooser_update_iter            (EmpathyAccountChooser            *chooser,
-                                                       GtkTreeIter                     *iter);
-static void     account_chooser_status_changed_cb      (MissionControl                  *mc,
-                                                       TelepathyConnectionStatus        status,
-                                                       McPresence                       presence,
-                                                       TelepathyConnectionStatusReason  reason,
-                                                       const gchar                     *unique_name,
-                                                       EmpathyAccountChooser           *chooser);
-static gboolean account_chooser_separator_func         (GtkTreeModel                    *model,
-                                                       GtkTreeIter                     *iter,
-                                                       EmpathyAccountChooser            *chooser);
-static gboolean account_chooser_set_account_foreach    (GtkTreeModel                    *model,
-                                                       GtkTreePath                     *path,
-                                                       GtkTreeIter                     *iter,
-                                                       SetAccountData                  *data);
+static void     account_chooser_finalize               (GObject                  *object);
+static void     account_chooser_get_property           (GObject                  *object,
+                                                       guint                     param_id,
+                                                       GValue                   *value,
+                                                       GParamSpec               *pspec);
+static void     account_chooser_set_property           (GObject                  *object,
+                                                       guint                     param_id,
+                                                       const GValue             *value,
+                                                       GParamSpec               *pspec);
+static void     account_chooser_setup                  (EmpathyAccountChooser    *chooser);
+static void     account_chooser_account_validity_changed_cb (TpAccountManager    *manager,
+                                                       TpAccount                *account,
+                                                       gboolean                  valid,
+                                                       EmpathyAccountChooser    *chooser);
+static void     account_chooser_account_add_foreach    (TpAccount                *account,
+                                                       EmpathyAccountChooser    *chooser);
+static void     account_chooser_account_removed_cb     (TpAccountManager         *manager,
+                                                       TpAccount                *account,
+                                                       EmpathyAccountChooser    *chooser);
+static void     account_chooser_account_remove_foreach (TpAccount                *account,
+                                                       EmpathyAccountChooser    *chooser);
+static void     account_chooser_update_iter            (EmpathyAccountChooser    *chooser,
+                                                       GtkTreeIter              *iter);
+static void     account_chooser_status_changed_cb      (TpAccount  *account,
+                                                       guint       old_status,
+                                                       guint       new_status,
+                                                       guint       reason,
+                                                       gchar      *dbus_error_name,
+                                                       GHashTable *details,
+                                                       gpointer    user_data);
+static gboolean account_chooser_separator_func         (GtkTreeModel             *model,
+                                                       GtkTreeIter              *iter,
+                                                       EmpathyAccountChooser    *chooser);
+static gboolean account_chooser_set_account_foreach    (GtkTreeModel             *model,
+                                                       GtkTreePath              *path,
+                                                       GtkTreeIter              *iter,
+                                                       SetAccountData           *data);
 
 enum {
        PROP_0,
        PROP_HAS_ALL_OPTION,
 };
 
+enum {
+       READY,
+       LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
 G_DEFINE_TYPE (EmpathyAccountChooser, empathy_account_chooser, GTK_TYPE_COMBO_BOX);
 
 static void
@@ -114,6 +184,11 @@ empathy_account_chooser_class_init (EmpathyAccountChooserClass *klass)
        object_class->get_property = account_chooser_get_property;
        object_class->set_property = account_chooser_set_property;
 
+       /**
+        * EmpathyAccountChooser:has-all-option:
+        *
+        * Have an additional option in the list to mean all accounts.
+        */
        g_object_class_install_property (object_class,
                                         PROP_HAS_ALL_OPTION,
                                         g_param_spec_boolean ("has-all-option",
@@ -122,40 +197,55 @@ empathy_account_chooser_class_init (EmpathyAccountChooserClass *klass)
                                                               FALSE,
                                                               G_PARAM_READWRITE));
 
+       signals[READY] =
+               g_signal_new ("ready",
+                             G_OBJECT_CLASS_TYPE (object_class),
+                             G_SIGNAL_RUN_LAST,
+                             0,
+                             NULL, NULL,
+                             g_cclosure_marshal_VOID__VOID,
+                             G_TYPE_NONE,
+                             0);
+
        g_type_class_add_private (object_class, sizeof (EmpathyAccountChooserPriv));
 }
 
 static void
 empathy_account_chooser_init (EmpathyAccountChooser *chooser)
 {
-       EmpathyAccountChooserPriv *priv = GET_PRIV (chooser);
+       EmpathyAccountChooserPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (chooser,
+               EMPATHY_TYPE_ACCOUNT_CHOOSER, EmpathyAccountChooserPriv);
 
+       chooser->priv = priv;
        priv->set_active_item = FALSE;
+       priv->account_manually_set = FALSE;
        priv->filter = NULL;
        priv->filter_data = NULL;
+
+       priv->manager = tp_account_manager_dup ();
+
+       g_signal_connect (priv->manager, "account-validity-changed",
+                         G_CALLBACK (account_chooser_account_validity_changed_cb),
+                         chooser);
+       g_signal_connect (priv->manager, "account-removed",
+                         G_CALLBACK (account_chooser_account_removed_cb),
+                         chooser);
+
+       account_chooser_setup (EMPATHY_ACCOUNT_CHOOSER (chooser));
 }
 
 static void
 account_chooser_finalize (GObject *object)
 {
-       EmpathyAccountChooser     *chooser;
-       EmpathyAccountChooserPriv *priv;
-
-       chooser = EMPATHY_ACCOUNT_CHOOSER (object);
-       priv = GET_PRIV (object);
+       EmpathyAccountChooserPriv *priv = GET_PRIV (object);
 
-       g_signal_handlers_disconnect_by_func (priv->monitor,
-                                             account_chooser_account_created_cb,
-                                             chooser);
-       g_signal_handlers_disconnect_by_func (priv->monitor,
-                                             account_chooser_account_deleted_cb,
-                                             chooser);
-       dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc),
-                                       "AccountStatusChanged",
-                                       G_CALLBACK (account_chooser_status_changed_cb),
-                                       chooser);
-       g_object_unref (priv->mc);
-       g_object_unref (priv->monitor);
+       g_signal_handlers_disconnect_by_func (priv->manager,
+                                             account_chooser_account_validity_changed_cb,
+                                             object);
+       g_signal_handlers_disconnect_by_func (priv->manager,
+                                             account_chooser_account_removed_cb,
+                                             object);
+       g_object_unref (priv->manager);
 
        G_OBJECT_CLASS (empathy_account_chooser_parent_class)->finalize (object);
 }
@@ -201,41 +291,38 @@ account_chooser_set_property (GObject      *object,
        };
 }
 
+/**
+ * empathy_account_chooser_new:
+ *
+ * Creates a new #EmpathyAccountChooser.
+ *
+ * Return value: A new #EmpathyAccountChooser
+ */
 GtkWidget *
 empathy_account_chooser_new (void)
 {
-       EmpathyAccountChooserPriv *priv;
-       McAccountMonitor         *monitor;
        GtkWidget                *chooser;
 
-       monitor = mc_account_monitor_new ();
        chooser = g_object_new (EMPATHY_TYPE_ACCOUNT_CHOOSER, NULL);
 
-       priv = GET_PRIV (chooser);
-
-       priv->mc = empathy_mission_control_new ();
-       priv->monitor = mc_account_monitor_new ();
-
-       g_signal_connect (priv->monitor, "account-created",
-                         G_CALLBACK (account_chooser_account_created_cb),
-                         chooser);
-       g_signal_connect (priv->monitor, "account-deleted",
-                         G_CALLBACK (account_chooser_account_deleted_cb),
-                         chooser);
-       dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc), "AccountStatusChanged",
-                                    G_CALLBACK (account_chooser_status_changed_cb),
-                                    chooser, NULL);
-
-       account_chooser_setup (EMPATHY_ACCOUNT_CHOOSER (chooser));
-
        return chooser;
 }
 
-McAccount *
-empathy_account_chooser_get_account (EmpathyAccountChooser *chooser)
+/**
+ * empathy_account_chooser_dup_account:
+ * @chooser: an #EmpathyAccountChooser
+ *
+ * Returns the account which is currently selected in the chooser or %NULL
+ * if there is no account selected. The #TpAccount returned should be
+ * unrefed with g_object_unref() when finished with.
+ *
+ * Return value: a new ref to the #TpAccount currently selected, or %NULL.
+ */
+TpAccount *
+empathy_account_chooser_dup_account (EmpathyAccountChooser *chooser)
 {
        EmpathyAccountChooserPriv *priv;
-       McAccount                *account;
+       TpAccount                 *account;
        GtkTreeModel             *model;
        GtkTreeIter               iter;
 
@@ -244,17 +331,66 @@ empathy_account_chooser_get_account (EmpathyAccountChooser *chooser)
        priv = GET_PRIV (chooser);
 
        model = gtk_combo_box_get_model (GTK_COMBO_BOX (chooser));
-       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (chooser), &iter);
+       if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (chooser), &iter)) {
+               return NULL;
+       }
 
        gtk_tree_model_get (model, &iter, COL_ACCOUNT_POINTER, &account, -1);
 
        return account;
 }
 
+/**
+ * empathy_account_chooser_get_connection:
+ * @chooser: an #EmpathyAccountChooser
+ *
+ * Returns a borrowed reference to the #TpConnection associated with the
+ * account currently selected. The caller must reference the returned object with
+ * g_object_ref() if it will be kept
+ *
+ * Return value: a borrowed reference to the #TpConnection associated with the
+ * account curently selected.
+ */
+TpConnection *
+empathy_account_chooser_get_connection (EmpathyAccountChooser *chooser)
+{
+       EmpathyAccountChooserPriv *priv;
+       TpAccount                 *account;
+       TpConnection              *connection;
+
+       g_return_val_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser), NULL);
+
+       priv = GET_PRIV (chooser);
+
+       account = empathy_account_chooser_dup_account (chooser);
+
+       /* if the returned account is NULL, then the account manager probably
+        * hasn't been prepared yet. It should be safe to return NULL here
+        * though. */
+       if (account == NULL) {
+               return NULL;
+       }
+
+       connection = tp_account_get_connection (account);
+       g_object_unref (account);
+
+       return connection;
+}
+
+/**
+ * empathy_account_chooser_set_account:
+ * @chooser: an #EmpathyAccountChooser
+ * @account: a #TpAccount
+ *
+ * Sets the currently selected account to @account, if it exists in the list.
+ *
+ * Return value: whether the chooser was set to @account.
+ */
 gboolean
 empathy_account_chooser_set_account (EmpathyAccountChooser *chooser,
-                                    McAccount             *account)
+                                    TpAccount             *account)
 {
+       EmpathyAccountChooserPriv *priv;
        GtkComboBox    *combobox;
        GtkTreeModel   *model;
        GtkTreeIter     iter;
@@ -262,6 +398,8 @@ empathy_account_chooser_set_account (EmpathyAccountChooser *chooser,
 
        g_return_val_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser), FALSE);
 
+       priv = GET_PRIV (chooser);
+
        combobox = GTK_COMBO_BOX (chooser);
        model = gtk_combo_box_get_model (combobox);
        gtk_combo_box_get_active_iter (combobox, &iter);
@@ -273,9 +411,21 @@ empathy_account_chooser_set_account (EmpathyAccountChooser *chooser,
                                (GtkTreeModelForeachFunc) account_chooser_set_account_foreach,
                                &data);
 
+       priv->account_manually_set = data.set;
+
        return data.set;
 }
 
+/**
+ * empathy_account_chooser_get_has_all_option:
+ * @chooser: an #EmpathyAccountChooser
+ *
+ * Returns whether @chooser has the #EmpathyAccountChooser:has-all-option property
+ * set to true.
+ *
+ * Return value: whether @chooser has the #EmpathyAccountChooser:has-all-option property
+ * enabled.
+ */
 gboolean
 empathy_account_chooser_get_has_all_option (EmpathyAccountChooser *chooser)
 {
@@ -284,10 +434,17 @@ empathy_account_chooser_get_has_all_option (EmpathyAccountChooser *chooser)
        g_return_val_if_fail (EMPATHY_IS_ACCOUNT_CHOOSER (chooser), FALSE);
 
        priv = GET_PRIV (chooser);
-       
+
        return priv->has_all_option;
 }
 
+/**
+ * empathy_account_chooser_set_has_all_option:
+ * @chooser: an #EmpathyAccountChooser
+ * @has_all_option: a new value for the #EmpathyAccountChooser:has-all-option property
+ *
+ * Sets the #EmpathyAccountChooser:has-all-option property.
+ */
 void
 empathy_account_chooser_set_has_all_option (EmpathyAccountChooser *chooser,
                                           gboolean              has_all_option)
@@ -317,24 +474,26 @@ empathy_account_chooser_set_has_all_option (EmpathyAccountChooser *chooser,
         */
 
        if (has_all_option) {
-               gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (chooser), 
+               gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (chooser),
                                                      (GtkTreeViewRowSeparatorFunc)
                                                      account_chooser_separator_func,
-                                                     chooser, 
+                                                     chooser,
                                                      NULL);
 
                gtk_list_store_prepend (store, &iter);
-               gtk_list_store_set (store, &iter, 
+               gtk_list_store_set (store, &iter,
                                    COL_ACCOUNT_TEXT, NULL,
                                    COL_ACCOUNT_ENABLED, TRUE,
                                    COL_ACCOUNT_POINTER, NULL,
+                                   COL_ACCOUNT_ROW_TYPE, ROW_SEPARATOR,
                                    -1);
 
                gtk_list_store_prepend (store, &iter);
-               gtk_list_store_set (store, &iter, 
-                                   COL_ACCOUNT_TEXT, _("All"), 
+               gtk_list_store_set (store, &iter,
+                                   COL_ACCOUNT_TEXT, _("All"),
                                    COL_ACCOUNT_ENABLED, TRUE,
                                    COL_ACCOUNT_POINTER, NULL,
+                                   COL_ACCOUNT_ROW_TYPE, ROW_ALL,
                                    -1);
        } else {
                if (gtk_tree_model_get_iter_first (model, &iter)) {
@@ -343,21 +502,103 @@ empathy_account_chooser_set_has_all_option (EmpathyAccountChooser *chooser,
                        }
                }
 
-               gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (chooser), 
+               gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (chooser),
                                                      (GtkTreeViewRowSeparatorFunc)
                                                      NULL,
-                                                     NULL, 
+                                                     NULL,
                                                      NULL);
        }
 
        g_object_notify (G_OBJECT (chooser), "has-all-option");
 }
 
+static void
+account_manager_prepared_cb (GObject *source_object,
+                            GAsyncResult *result,
+                            gpointer user_data)
+{
+       GList *accounts, *l;
+       TpAccountManager *manager = TP_ACCOUNT_MANAGER (source_object);
+       EmpathyAccountChooser *chooser = user_data;
+       EmpathyAccountChooserPriv *priv = GET_PRIV (chooser);
+       GError *error = NULL;
+
+       if (!tp_account_manager_prepare_finish (manager, result, &error)) {
+               DEBUG ("Failed to prepare account manager: %s", error->message);
+               g_error_free (error);
+               return;
+       }
+
+       accounts = tp_account_manager_get_valid_accounts (manager);
+
+       for (l = accounts; l != NULL; l = l->next) {
+               TpAccount *account = l->data;
+
+               account_chooser_account_add_foreach (account, chooser);
+
+               tp_g_signal_connect_object (account, "status-changed",
+                                            G_CALLBACK (account_chooser_status_changed_cb),
+                                            chooser, 0);
+       }
+
+       g_list_free (accounts);
+
+       priv->ready = TRUE;
+       g_signal_emit (chooser, signals[READY], 0);
+}
+
+static gint
+account_cmp (GtkTreeModel *model,
+            GtkTreeIter *a,
+            GtkTreeIter *b,
+            gpointer user_data)
+{
+       RowType a_type, b_type;
+       gboolean a_enabled, b_enabled;
+       gchar *a_text, *b_text;
+       gint result;
+
+       gtk_tree_model_get (model, a,
+               COL_ACCOUNT_ENABLED, &a_enabled,
+               COL_ACCOUNT_ROW_TYPE, &a_type,
+               -1);
+       gtk_tree_model_get (model, b,
+               COL_ACCOUNT_ENABLED, &b_enabled,
+               COL_ACCOUNT_ROW_TYPE, &b_type,
+               -1);
+
+       /* This assumes that we have at most one of each special row type. */
+       if (a_type != b_type) {
+               /* Display higher-numbered special row types first. */
+               return (b_type - a_type);
+       }
+
+       /* Enabled accounts are displayed first */
+       if (a_enabled != b_enabled)
+               return a_enabled ? -1: 1;
+
+       gtk_tree_model_get (model, a, COL_ACCOUNT_TEXT, &a_text, -1);
+       gtk_tree_model_get (model, b, COL_ACCOUNT_TEXT, &b_text, -1);
+
+       if (a_text == b_text)
+               result = 0;
+       else if (a_text == NULL)
+               result = 1;
+       else if (b_text == NULL)
+               result = -1;
+       else
+               result = g_ascii_strcasecmp (a_text, b_text);
+
+       g_free (a_text);
+       g_free (b_text);
+
+       return result;
+}
+
 static void
 account_chooser_setup (EmpathyAccountChooser *chooser)
 {
        EmpathyAccountChooserPriv *priv;
-       GList                    *accounts;
        GtkListStore             *store;
        GtkCellRenderer          *renderer;
        GtkComboBox              *combobox;
@@ -373,7 +614,13 @@ account_chooser_setup (EmpathyAccountChooser *chooser)
                                    G_TYPE_STRING,    /* Image */
                                    G_TYPE_STRING,    /* Name */
                                    G_TYPE_BOOLEAN,   /* Enabled */
-                                   MC_TYPE_ACCOUNT);
+                                   G_TYPE_UINT,      /* Row type */
+                                   TP_TYPE_ACCOUNT);
+
+       gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (store),
+               account_cmp, chooser, NULL);
+       gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
+               GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
 
        gtk_combo_box_set_model (combobox, GTK_TREE_MODEL (store));
 
@@ -393,29 +640,27 @@ account_chooser_setup (EmpathyAccountChooser *chooser)
                                        NULL);
 
        /* Populate accounts */
-       accounts = mc_accounts_list ();
-       g_list_foreach (accounts,
-                       (GFunc) account_chooser_account_add_foreach,
-                       chooser);
+       tp_account_manager_prepare_async (priv->manager, NULL,
+                                         account_manager_prepared_cb, chooser);
 
-       mc_accounts_list_free (accounts);
        g_object_unref (store);
 }
 
 static void
-account_chooser_account_created_cb (McAccountMonitor     *monitor,
-                                   const gchar          *unique_name,
-                                   EmpathyAccountChooser *chooser)
+account_chooser_account_validity_changed_cb (TpAccountManager      *manager,
+                                            TpAccount             *account,
+                                            gboolean               valid,
+                                            EmpathyAccountChooser *chooser)
 {
-       McAccount *account;
-
-       account = mc_account_lookup (unique_name);
-       account_chooser_account_add_foreach (account, chooser);
-       g_object_unref (account);
+       if (valid) {
+               account_chooser_account_add_foreach (account, chooser);
+       } else {
+               account_chooser_account_remove_foreach (account, chooser);
+       }
 }
 
 static void
-account_chooser_account_add_foreach (McAccount             *account,
+account_chooser_account_add_foreach (TpAccount             *account,
                                     EmpathyAccountChooser *chooser)
 {
        GtkListStore *store;
@@ -434,19 +679,15 @@ account_chooser_account_add_foreach (McAccount             *account,
 }
 
 static void
-account_chooser_account_deleted_cb (McAccountMonitor     *monitor,
-                                   const gchar          *unique_name,
+account_chooser_account_removed_cb (TpAccountManager      *manager,
+                                   TpAccount             *account,
                                    EmpathyAccountChooser *chooser)
 {
-       McAccount *account;
-
-       account = mc_account_lookup (unique_name);
        account_chooser_account_remove_foreach (account, chooser);
-       g_object_unref (account);
 }
 
 typedef struct {
-       McAccount   *account;
+       TpAccount   *account;
        GtkTreeIter *iter;
        gboolean     found;
 } FindAccountData;
@@ -458,11 +699,11 @@ account_chooser_find_account_foreach (GtkTreeModel *model,
                                      gpointer      user_data)
 {
        FindAccountData *data = user_data;
-       McAccount       *account;
+       TpAccount  *account;
 
        gtk_tree_model_get (model, iter, COL_ACCOUNT_POINTER, &account, -1);
 
-       if (empathy_account_equal (account, data->account)) {
+       if (account == data->account) {
                data->found = TRUE;
                *(data->iter) = *iter;
                g_object_unref (account);
@@ -477,7 +718,7 @@ account_chooser_find_account_foreach (GtkTreeModel *model,
 
 static gboolean
 account_chooser_find_account (EmpathyAccountChooser *chooser,
-                             McAccount             *account,
+                             TpAccount             *account,
                              GtkTreeIter           *iter)
 {
        GtkListStore    *store;
@@ -497,7 +738,7 @@ account_chooser_find_account (EmpathyAccountChooser *chooser,
 }
 
 static void
-account_chooser_account_remove_foreach (McAccount            *account,
+account_chooser_account_remove_foreach (TpAccount             *account,
                                        EmpathyAccountChooser *chooser)
 {
        GtkListStore *store;
@@ -513,61 +754,91 @@ account_chooser_account_remove_foreach (McAccount            *account,
 }
 
 static void
-account_chooser_update_iter (EmpathyAccountChooser *chooser,
-                            GtkTreeIter           *iter)
+account_chooser_filter_ready_cb (gboolean is_enabled,
+                                gpointer data)
 {
+       FilterResultCallbackData  *fr_data = data;
+       EmpathyAccountChooser     *chooser;
        EmpathyAccountChooserPriv *priv;
+       TpAccount                 *account;
+       GtkTreeIter               *iter;
        GtkListStore              *store;
        GtkComboBox               *combobox;
-       McAccount                 *account;
        const gchar               *icon_name;
-       gboolean                   is_enabled = TRUE;
 
+       chooser = fr_data->chooser;
        priv = GET_PRIV (chooser);
-
+       account = fr_data->account;
+       iter = fr_data->iter;
        combobox = GTK_COMBO_BOX (chooser);
        store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox));
 
-       gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
-                           COL_ACCOUNT_POINTER, &account,
-                           -1);
-
-       icon_name = empathy_icon_name_from_account (account);
-       if (priv->filter) {
-               is_enabled = priv->filter (account, priv->filter_data);
-       }
+       icon_name = tp_account_get_icon_name (account);
 
        gtk_list_store_set (store, iter,
                            COL_ACCOUNT_IMAGE, icon_name,
-                           COL_ACCOUNT_TEXT, mc_account_get_display_name (account),
+                           COL_ACCOUNT_TEXT, tp_account_get_display_name (account),
                            COL_ACCOUNT_ENABLED, is_enabled,
                            -1);
 
        /* set first connected account as active account */
-       if (priv->set_active_item == FALSE && is_enabled) {
+       if (priv->account_manually_set == FALSE &&
+           priv->set_active_item == FALSE && is_enabled) {
                priv->set_active_item = TRUE;
                gtk_combo_box_set_active_iter (combobox, iter);
        }
 
        g_object_unref (account);
+       filter_result_callback_data_free (fr_data);
+}
+
+static void
+account_chooser_update_iter (EmpathyAccountChooser *chooser,
+                            GtkTreeIter           *iter)
+{
+       EmpathyAccountChooserPriv *priv;
+       GtkListStore              *store;
+       GtkComboBox               *combobox;
+       TpAccount                 *account;
+       FilterResultCallbackData  *data;
+
+       priv = GET_PRIV (chooser);
+
+       combobox = GTK_COMBO_BOX (chooser);
+       store = GTK_LIST_STORE (gtk_combo_box_get_model (combobox));
+
+       gtk_tree_model_get (GTK_TREE_MODEL (store), iter,
+                           COL_ACCOUNT_POINTER, &account,
+                           -1);
+
+       /* Skip rows without account associated */
+       if (account == NULL)
+               return;
+
+       data = filter_result_callback_data_new (chooser, account, iter);
+
+       if (priv->filter)
+               priv->filter (account, account_chooser_filter_ready_cb,
+                             (gpointer) data, priv->filter_data);
+       else
+               account_chooser_filter_ready_cb (TRUE, (gpointer) data);
 }
 
 static void
-account_chooser_status_changed_cb (MissionControl                  *mc,
-                                  TelepathyConnectionStatus        status,
-                                  McPresence                       presence,
-                                  TelepathyConnectionStatusReason  reason,
-                                  const gchar                     *unique_name,
-                                  EmpathyAccountChooser           *chooser)
+account_chooser_status_changed_cb (TpAccount  *account,
+                                  guint       old_status,
+                                  guint       new_status,
+                                  guint       reason,
+                                  gchar      *dbus_error_name,
+                                  GHashTable *details,
+                                  gpointer    user_data)
 {
-       McAccount   *account;
-       GtkTreeIter  iter;
+       EmpathyAccountChooser *chooser = user_data;
+       GtkTreeIter iter;
 
-       account = mc_account_lookup (unique_name);
        if (account_chooser_find_account (chooser, account, &iter)) {
                account_chooser_update_iter (chooser, &iter);
        }
-       g_object_unref (account);
 }
 
 static gboolean
@@ -575,21 +846,10 @@ account_chooser_separator_func (GtkTreeModel         *model,
                                GtkTreeIter          *iter,
                                EmpathyAccountChooser *chooser)
 {
-       EmpathyAccountChooserPriv *priv;
-       gchar                    *text;
-       gboolean                  is_separator;
+       RowType row_type;
 
-       priv = GET_PRIV (chooser);
-       
-       if (!priv->has_all_option) {
-               return FALSE;
-       }
-       
-       gtk_tree_model_get (model, iter, COL_ACCOUNT_TEXT, &text, -1);
-       is_separator = text == NULL;
-       g_free (text);
-
-       return is_separator;
+       gtk_tree_model_get (model, iter, COL_ACCOUNT_ROW_TYPE, &row_type, -1);
+       return (row_type == ROW_SEPARATOR);
 }
 
 static gboolean
@@ -598,19 +858,14 @@ account_chooser_set_account_foreach (GtkTreeModel   *model,
                                     GtkTreeIter    *iter,
                                     SetAccountData *data)
 {
-       McAccount *account;
+       TpAccount *account;
        gboolean   equal;
 
        gtk_tree_model_get (model, iter, COL_ACCOUNT_POINTER, &account, -1);
 
-       /* Special case so we can make it possible to select the All option */
-       if (!data->account && !account) {
-               equal = TRUE;
-       }
-       else if ((data->account && !account) || (!data->account && account)) {
-               equal = FALSE;
-       } else {
-               equal = empathy_account_equal (data->account, account);
+       equal = (data->account == account);
+
+       if (account) {
                g_object_unref (account);
        }
 
@@ -636,6 +891,15 @@ account_chooser_filter_foreach (GtkTreeModel *model,
        return FALSE;
 }
 
+/**
+ * empathy_account_chooser_set_filter:
+ * @chooser: an #EmpathyAccountChooser
+ * @filter: a filter
+ * @user_data: data to pass to @filter, or %NULL
+ *
+ * Sets a filter on the @chooser so only accounts that are %TRUE in the eyes
+ * of the filter are visible in the @chooser.
+ */
 void
 empathy_account_chooser_set_filter (EmpathyAccountChooser           *chooser,
                                     EmpathyAccountChooserFilterFunc  filter,
@@ -657,19 +921,60 @@ empathy_account_chooser_set_filter (EmpathyAccountChooser           *chooser,
        gtk_tree_model_foreach (model, account_chooser_filter_foreach, chooser);
 }
 
+/**
+ * EmpathyAccountChooserFilterFunc:
+ * @account: a #TpAccount
+ * @user_data: user data, or %NULL
+ *
+ * A function which decides whether the account indicated by @account
+ * is visible.
+ *
+ * Return value: whether the account indicated by @account is visible.
+ */
+
+/**
+ * empathy_account_chooser_filter_is_connected:
+ * @account: a #TpAccount
+ * @callback: an #EmpathyAccountChooserFilterResultCallback accepting the result
+ * @callback_data: data passed to the @callback
+ * @user_data: user data or %NULL
+ *
+ * A useful #EmpathyAccountChooserFilterFunc that one could pass into
+ * empathy_account_chooser_set_filter() and only show connected accounts.
+ *
+ * Returns (via the callback) TRUE is @account is connected
+ */
+void
+empathy_account_chooser_filter_is_connected (
+       TpAccount                                 *account,
+       EmpathyAccountChooserFilterResultCallback  callback,
+       gpointer                                   callback_data,
+       gpointer                                   user_data)
+{
+       gboolean is_connected =
+               tp_account_get_connection_status (account, NULL)
+               == TP_CONNECTION_STATUS_CONNECTED;
+       callback (is_connected, callback_data);
+}
+
 gboolean
-empathy_account_chooser_filter_is_connected (McAccount *account,
-                                            gpointer   user_data)
+empathy_account_chooser_is_ready (EmpathyAccountChooser *self)
 {
-       MissionControl            *mc;
-       TelepathyConnectionStatus  status;
+       EmpathyAccountChooserPriv *priv = GET_PRIV (self);
 
-       g_return_val_if_fail (MC_IS_ACCOUNT (account), FALSE);
+       return priv->ready;
+}
 
-       mc = empathy_mission_control_new ();
-       status = mission_control_get_connection_status (mc, account, NULL);
-       g_object_unref (mc);
+TpAccount *
+empathy_account_chooser_get_account (EmpathyAccountChooser *chooser)
+{
+       TpAccount *account;
 
-       return status == TP_CONN_STATUS_CONNECTED;
-}
+       account = empathy_account_chooser_dup_account (chooser);
+       if (account == NULL)
+               return NULL;
+
+       g_object_unref (account);
 
+       return account;
+}