diff options
Diffstat (limited to 'libempathy-gtk/empathy-individual-store.c')
-rw-r--r-- | libempathy-gtk/empathy-individual-store.c | 201 |
1 files changed, 111 insertions, 90 deletions
diff --git a/libempathy-gtk/empathy-individual-store.c b/libempathy-gtk/empathy-individual-store.c index 83ee67e9b..5b920d63b 100644 --- a/libempathy-gtk/empathy-individual-store.c +++ b/libempathy-gtk/empathy-individual-store.c @@ -73,24 +73,14 @@ typedef struct GHashTable *status_icons; /* List of owned GCancellables for each pending avatar load operation */ GList *avatar_cancellables; + /* Hash: FolksIndividual* -> GQueue(GtkTreeRowReference) */ + GHashTable *folks_individual_cache; + /* Hash: char *groupname -> GtkTreeRowReference *row */ + GHashTable *empathy_group_cache; } EmpathyIndividualStorePriv; typedef struct { - GtkTreeIter iter; - const gchar *name; - gboolean found; -} FindGroup; - -typedef struct -{ - FolksIndividual *individual; - gboolean found; - GList *iters; -} FindContact; - -typedef struct -{ EmpathyIndividualStore *self; FolksIndividual *individual; gboolean remove; @@ -212,8 +202,12 @@ add_individual_to_store (GtkTreeStore *self, GtkTreeIter *parent, FolksIndividual *individual) { + EmpathyIndividualStorePriv *priv = GET_PRIV (self); gboolean can_audio_call, can_video_call; const gchar * const *types; + GtkTreeRowReference *row_ref; + GtkTreePath *path; + GQueue *queue; individual_can_audio_video_call (individual, &can_audio_call, &can_video_call); @@ -230,34 +224,22 @@ add_individual_to_store (GtkTreeStore *self, EMPATHY_INDIVIDUAL_STORE_COL_CAN_VIDEO_CALL, can_video_call, EMPATHY_INDIVIDUAL_STORE_COL_CLIENT_TYPES, types, -1); -} - -static gboolean -individual_store_get_group_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - FindGroup *fg) -{ - gchar *str; - gboolean is_group; - - /* Groups are only at the top level. */ - if (gtk_tree_path_get_depth (path) != 1) - return FALSE; - - gtk_tree_model_get (model, iter, - EMPATHY_INDIVIDUAL_STORE_COL_NAME, &str, - EMPATHY_INDIVIDUAL_STORE_COL_IS_GROUP, &is_group, -1); - if (is_group && !tp_strdiff (str, fg->name)) + path = gtk_tree_model_get_path (GTK_TREE_MODEL (self), iter); + row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (self), path); + queue = g_hash_table_lookup (priv->folks_individual_cache, individual); + if (queue) { - fg->found = TRUE; - fg->iter = *iter; + g_queue_push_tail (queue, row_ref); } - - g_free (str); - - return fg->found; + else + { + queue = g_queue_new (); + g_queue_push_tail (queue, row_ref); + g_hash_table_insert (priv->folks_individual_cache, individual, + queue); + } + gtk_tree_path_free (path); } static void @@ -268,21 +250,19 @@ individual_store_get_group (EmpathyIndividualStore *self, gboolean *created, gboolean is_fake_group) { + EmpathyIndividualStorePriv *priv = GET_PRIV (self); GtkTreeModel *model; GtkTreeIter iter_group; GtkTreeIter iter_separator; - FindGroup fg; - - memset (&fg, 0, sizeof (fg)); - - fg.name = name; + GtkTreeRowReference *row_ref; model = GTK_TREE_MODEL (self); - gtk_tree_model_foreach (model, - (GtkTreeModelForeachFunc) individual_store_get_group_foreach, &fg); - - if (!fg.found) + row_ref = g_hash_table_lookup (priv->empathy_group_cache, name); + + if (row_ref == NULL) { + GtkTreePath *path; + if (created) *created = TRUE; @@ -296,6 +276,12 @@ individual_store_get_group (EmpathyIndividualStore *self, EMPATHY_INDIVIDUAL_STORE_COL_IS_FAKE_GROUP, is_fake_group, -1); + path = gtk_tree_model_get_path (GTK_TREE_MODEL (self), &iter_group); + row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (self), path); + g_hash_table_insert (priv->empathy_group_cache, + g_strdup (name), row_ref); + gtk_tree_path_free (path); + if (iter_group_to_set) *iter_group_to_set = iter_group; @@ -309,13 +295,22 @@ individual_store_get_group (EmpathyIndividualStore *self, } else { + GtkTreePath *path = gtk_tree_row_reference_get_path (row_ref); + GtkTreeIter iter; + + if (!gtk_tree_model_get_iter (model, &iter, path)) { + gtk_tree_path_free (path); + return; + } + gtk_tree_path_free (path); + if (created) *created = FALSE; if (iter_group_to_set) - *iter_group_to_set = fg.iter; + *iter_group_to_set = iter; - iter_separator = fg.iter; + iter_separator = iter; if (gtk_tree_model_iter_next (model, &iter_separator)) { @@ -330,48 +325,37 @@ individual_store_get_group (EmpathyIndividualStore *self, } } -static gboolean -individual_store_find_contact_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - FindContact *fc) -{ - FolksIndividual *individual; - - gtk_tree_model_get (model, iter, - EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, &individual, -1); - - if (individual == fc->individual) - { - fc->found = TRUE; - fc->iters = g_list_append (fc->iters, gtk_tree_iter_copy (iter)); - } - - tp_clear_object (&individual); - - return FALSE; -} - static GList * individual_store_find_contact (EmpathyIndividualStore *self, FolksIndividual *individual) { + EmpathyIndividualStorePriv *priv = GET_PRIV (self); GtkTreeModel *model; - GList *l = NULL; - FindContact fc; - - memset (&fc, 0, sizeof (fc)); - - fc.individual = individual; + GQueue *row_refs_queue; + GList *i; + GList *iters_list = NULL; model = GTK_TREE_MODEL (self); - gtk_tree_model_foreach (model, - (GtkTreeModelForeachFunc) individual_store_find_contact_foreach, &fc); + row_refs_queue = g_hash_table_lookup (priv->folks_individual_cache, + individual); + if (!row_refs_queue) + return NULL; - if (fc.found) - l = fc.iters; + for (i = g_queue_peek_head_link (row_refs_queue) ; i != NULL ; i = i->next) + { + GtkTreePath *path = gtk_tree_row_reference_get_path (i->data); + GtkTreeIter iter; + if (!gtk_tree_model_get_iter (model, &iter, path)) + { + gtk_tree_path_free (path); + continue; + } + gtk_tree_path_free (path); + iters_list = g_list_prepend + (iters_list, gtk_tree_iter_copy (&iter)); + } - return l; + return iters_list; } static void @@ -385,36 +369,54 @@ static void individual_store_remove_individual (EmpathyIndividualStore *self, FolksIndividual *individual) { + EmpathyIndividualStorePriv *priv = GET_PRIV (self); GtkTreeModel *model; - GList *iters, *l; + GQueue *row_refs; + GList *l; - iters = individual_store_find_contact (self, individual); - if (iters == NULL) + row_refs = g_hash_table_lookup (priv->folks_individual_cache, individual); + if (!row_refs) return; /* Clean up model */ model = GTK_TREE_MODEL (self); - for (l = iters; l; l = l->next) + for (l = g_queue_peek_head_link (row_refs); l; l = l->next) { + GtkTreePath *path = gtk_tree_row_reference_get_path (l->data); + GtkTreeIter iter; GtkTreeIter parent; + if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (self), &iter, + path)) + { + gtk_tree_path_free (path); + continue; + } + gtk_tree_path_free (path); + /* NOTE: it is only <= 2 here because we have * separators after the group name, otherwise it * should be 1. */ - if (gtk_tree_model_iter_parent (model, &parent, l->data) && + if (gtk_tree_model_iter_parent (model, &parent, &iter) && gtk_tree_model_iter_n_children (model, &parent) <= 2) { + gchar *group_name; + gtk_tree_model_get (model, &parent, + EMPATHY_CONTACT_LIST_STORE_COL_NAME, &group_name, + -1); + g_hash_table_remove (priv->empathy_group_cache, + group_name); gtk_tree_store_remove (GTK_TREE_STORE (self), &parent); } else { - gtk_tree_store_remove (GTK_TREE_STORE (self), l->data); + gtk_tree_store_remove (GTK_TREE_STORE (self), &iter); } } - free_iters (iters); + g_hash_table_remove (priv->folks_individual_cache, individual); } static void @@ -1183,6 +1185,8 @@ individual_store_dispose (GObject *object) } g_hash_table_destroy (priv->status_icons); + g_hash_table_destroy (priv->folks_individual_cache); + g_hash_table_destroy (priv->empathy_group_cache); G_OBJECT_CLASS (empathy_individual_store_parent_class)->dispose (object); } @@ -1620,6 +1624,14 @@ individual_store_inhibit_active_cb (EmpathyIndividualStore *self) } static void +g_queue_free_full_row_ref (gpointer data) +{ + GQueue *queue = (GQueue *) data; + g_queue_foreach (queue, (GFunc) gtk_tree_row_reference_free, NULL); + g_queue_free (queue); +} + +static void empathy_individual_store_init (EmpathyIndividualStore *self) { EmpathyIndividualStorePriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, @@ -1634,6 +1646,11 @@ empathy_individual_store_init (EmpathyIndividualStore *self) (GSourceFunc) individual_store_inhibit_active_cb, self); priv->status_icons = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + priv->folks_individual_cache = g_hash_table_new_full (NULL, NULL, NULL, + g_queue_free_full_row_ref); + priv->empathy_group_cache = g_hash_table_new_full (g_str_hash, + g_str_equal, g_free, + (GDestroyNotify) gtk_tree_row_reference_free); individual_store_setup (self); } @@ -1805,6 +1822,10 @@ empathy_individual_store_set_show_groups (EmpathyIndividualStore *self, GList *contacts; gtk_tree_store_clear (GTK_TREE_STORE (self)); + /* Also clear the cache */ + g_hash_table_remove_all (priv->folks_individual_cache); + g_hash_table_remove_all (priv->empathy_group_cache); + contacts = empathy_individual_manager_get_members (priv->manager); individual_store_members_changed_cb (priv->manager, |