]> git.0d.be Git - empathy.git/blobdiff - libempathy-gtk/empathy-account-chooser.c
Merge commit 'staz/dnd'
[empathy.git] / libempathy-gtk / empathy-account-chooser.c
index 7624c2c13686dcfaafe4be5f36245de24dddc156..4e3b63b4c81e0a7b534b8e1d1209b729ffffbfdc 100644 (file)
@@ -64,6 +64,7 @@ typedef struct {
        gboolean                        has_all_option;
        EmpathyAccountChooserFilterFunc filter;
        gpointer                        filter_data;
+       gboolean                        ready;
 } EmpathyAccountChooserPriv;
 
 typedef struct {
@@ -72,10 +73,21 @@ typedef struct {
        gboolean               set;
 } SetAccountData;
 
+/* 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
 };
@@ -123,6 +135,13 @@ enum {
        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
@@ -147,6 +166,16 @@ 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));
 }
 
@@ -425,6 +454,7 @@ empathy_account_chooser_set_has_all_option (EmpathyAccountChooser *chooser,
                                    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);
@@ -432,6 +462,7 @@ empathy_account_chooser_set_has_all_option (EmpathyAccountChooser *chooser,
                                    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)) {
@@ -458,6 +489,7 @@ account_manager_prepared_cb (GObject *source_object,
        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)) {
@@ -479,6 +511,57 @@ account_manager_prepared_cb (GObject *source_object,
        }
 
        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
@@ -500,8 +583,14 @@ account_chooser_setup (EmpathyAccountChooser *chooser)
                                    G_TYPE_STRING,    /* Image */
                                    G_TYPE_STRING,    /* Name */
                                    G_TYPE_BOOLEAN,   /* Enabled */
+                                   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));
 
        renderer = gtk_cell_renderer_pixbuf_new ();
@@ -696,21 +785,10 @@ account_chooser_separator_func (GtkTreeModel         *model,
                                GtkTreeIter          *iter,
                                EmpathyAccountChooser *chooser)
 {
-       EmpathyAccountChooserPriv *priv;
-       gchar                    *text;
-       gboolean                  is_separator;
-
-       priv = GET_PRIV (chooser);
-
-       if (!priv->has_all_option) {
-               return FALSE;
-       }
+       RowType row_type;
 
-       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
@@ -724,13 +802,7 @@ account_chooser_set_account_foreach (GtkTreeModel   *model,
 
        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 == NULL) != (account == NULL)) {
-               equal = FALSE;
-       }
-       else {
-               equal = (data->account == account);
-       }
+       equal = (data->account == account);
 
        if (account) {
                g_object_unref (account);
@@ -817,3 +889,10 @@ empathy_account_chooser_filter_is_connected (TpAccount *account,
            == TP_CONNECTION_STATUS_CONNECTED);
 }
 
+gboolean
+empathy_account_chooser_is_ready (EmpathyAccountChooser *self)
+{
+       EmpathyAccountChooserPriv *priv = GET_PRIV (self);
+
+       return priv->ready;
+}