diff options
Diffstat (limited to 'libempathy-gtk')
-rw-r--r-- | libempathy-gtk/gossip-account-widget-generic.c | 2 | ||||
-rw-r--r-- | libempathy-gtk/gossip-account-widget-jabber.c | 4 | ||||
-rw-r--r-- | libempathy-gtk/gossip-contact-list.c | 598 | ||||
-rw-r--r-- | libempathy-gtk/gossip-contact-list.h | 12 |
4 files changed, 466 insertions, 150 deletions
diff --git a/libempathy-gtk/gossip-account-widget-generic.c b/libempathy-gtk/gossip-account-widget-generic.c index 1abffa454..4ba0f9f2d 100644 --- a/libempathy-gtk/gossip-account-widget-generic.c +++ b/libempathy-gtk/gossip-account-widget-generic.c @@ -213,7 +213,7 @@ account_widget_generic_setup_foreach (McProtocolParam *param, 0, 0); } else if (param->signature[0] == 'b') { - gboolean value; + gboolean value = FALSE; mc_account_get_param_boolean (settings->account, param->name, diff --git a/libempathy-gtk/gossip-account-widget-jabber.c b/libempathy-gtk/gossip-account-widget-jabber.c index b5cf4ce29..1c3b6108c 100644 --- a/libempathy-gtk/gossip-account-widget-jabber.c +++ b/libempathy-gtk/gossip-account-widget-jabber.c @@ -91,7 +91,7 @@ account_widget_jabber_entry_focus_cb (GtkWidget *widget, str = gtk_entry_get_text (GTK_ENTRY (widget)); if (G_STR_EMPTY (str)) { - gchar *value; + gchar *value = NULL; mc_account_get_param_string (settings->account, param, &value); gtk_entry_set_text (GTK_ENTRY (widget), value ? value : ""); @@ -120,7 +120,7 @@ account_widget_jabber_checkbutton_toggled_cb (GtkWidget *widget, GossipAccountWidgetJabber *settings) { if (widget == settings->checkbutton_ssl) { - gint port; + gint port = 0; gboolean old_ssl; mc_account_get_param_int (settings->account, "port", &port); diff --git a/libempathy-gtk/gossip-contact-list.c b/libempathy-gtk/gossip-contact-list.c index 3a49d12d0..a96c28e51 100644 --- a/libempathy-gtk/gossip-contact-list.c +++ b/libempathy-gtk/gossip-contact-list.c @@ -72,6 +72,10 @@ struct _GossipContactListPriv { GtkUIManager *ui; GtkTreeRowReference *drag_row; + GtkTreeStore *store; + GtkTreeModel *filter; + gchar *filter_text; + gboolean show_offline; gboolean show_avatars; gboolean is_compact; @@ -79,9 +83,9 @@ struct _GossipContactListPriv { }; typedef struct { + GtkTreeIter iter; const gchar *name; gboolean found; - GtkTreeIter iter; } FindGroup; typedef struct { @@ -113,6 +117,9 @@ static void contact_list_set_property (GObject guint param_id, const GValue *value, GParamSpec *pspec); +static gboolean contact_list_row_separator_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data); static void contact_list_contact_update (GossipContactList *list, GossipContact *contact); static void contact_list_contact_added_cb (EmpathyContactManager *manager, @@ -142,7 +149,8 @@ static gchar * contact_list_get_parent_group (GtkTreeModel gboolean *path_is_group); static void contact_list_get_group (GossipContactList *list, const gchar *name, - GtkTreeIter *iter_to_set, + GtkTreeIter *iter_group_to_set, + GtkTreeIter *iter_separator_to_set, gboolean *created); static gboolean contact_list_get_group_foreach (GtkTreeModel *model, GtkTreePath *path, @@ -228,6 +236,9 @@ static gint contact_list_sort_func (GtkTreeModel GtkTreeIter *iter_a, GtkTreeIter *iter_b, gpointer user_data); +static gboolean contact_list_filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + GossipContactList *list); static GList * contact_list_find_contact (GossipContactList *list, GossipContact *contact); static gboolean contact_list_find_contact_foreach (GtkTreeModel *model, @@ -265,6 +276,7 @@ enum { COL_IS_GROUP, COL_IS_ACTIVE, COL_IS_ONLINE, + COL_IS_SEPARATOR, COL_COUNT }; @@ -273,6 +285,7 @@ enum { PROP_SHOW_OFFLINE, PROP_SHOW_AVATARS, PROP_IS_COMPACT, + PROP_FILTER }; static const GtkActionEntry entries[] = { @@ -468,6 +481,14 @@ gossip_contact_list_class_init (GossipContactListClass *klass) FALSE, G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_FILTER, + g_param_spec_string ("filter", + "Filter", + "The text to use to filter the contact list", + NULL, + G_PARAM_READWRITE)); + g_type_class_add_private (object_class, sizeof (GossipContactListPriv)); } @@ -509,6 +530,10 @@ gossip_contact_list_init (GossipContactList *list) g_object_unref (action_group); + gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (list), + contact_list_row_separator_func, + NULL, NULL); + /* Signal connection. */ g_signal_connect (priv->manager, "contact-added", @@ -548,6 +573,7 @@ gossip_contact_list_init (GossipContactList *list) g_object_unref (contact); } + g_list_free (contacts); } static void @@ -561,6 +587,9 @@ contact_list_finalize (GObject *object) g_object_unref (priv->manager); g_object_unref (priv->ui); + g_object_unref (priv->store); + g_object_unref (priv->filter); + g_free (priv->filter_text); G_OBJECT_CLASS (gossip_contact_list_parent_class)->finalize (object); } @@ -585,6 +614,9 @@ contact_list_get_property (GObject *object, case PROP_IS_COMPACT: g_value_set_boolean (value, priv->is_compact); break; + case PROP_FILTER: + g_value_set_string (value, priv->filter_text); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; @@ -614,12 +646,30 @@ contact_list_set_property (GObject *object, gossip_contact_list_set_is_compact (GOSSIP_CONTACT_LIST (object), g_value_get_boolean (value)); break; + case PROP_FILTER: + gossip_contact_list_set_filter (GOSSIP_CONTACT_LIST (object), + g_value_get_string (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; }; } +static gboolean +contact_list_row_separator_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + gboolean is_separator = FALSE; + + gtk_tree_model_get (model, iter, + COL_IS_SEPARATOR, &is_separator, + -1); + + return is_separator; +} + static void contact_list_contact_update (GossipContactList *list, GossipContact *contact) @@ -641,7 +691,7 @@ contact_list_contact_update (GossipContactList *list, priv = GET_PRIV (list); - model = gtk_tree_view_get_model (GTK_TREE_VIEW (list)); + model = GTK_TREE_MODEL (priv->store); iters = contact_list_find_contact (list, contact); if (!iters) { @@ -705,10 +755,7 @@ contact_list_contact_update (GossipContactList *list, /* Get online state before. */ if (iters && g_list_length (iters) > 0) { - GtkTreeIter *iter; - - iter = g_list_nth_data (iters, 0); - gtk_tree_model_get (model, iter, COL_IS_ONLINE, &was_online, -1); + gtk_tree_model_get (model, iters->data, COL_IS_ONLINE, &was_online, -1); } /* Is this really an update or an online/offline. */ @@ -741,7 +788,7 @@ contact_list_contact_update (GossipContactList *list, pixbuf_presence = gossip_pixbuf_for_contact (contact); pixbuf_avatar = gossip_pixbuf_avatar_from_contact_scaled (contact, 32, 32); for (l = iters; l && set_model; l = l->next) { - gtk_tree_store_set (GTK_TREE_STORE (model), l->data, + gtk_tree_store_set (priv->store, l->data, COL_PIXBUF_STATUS, pixbuf_presence, COL_STATUS, gossip_contact_get_status (contact), COL_IS_ONLINE, now_online, @@ -786,10 +833,10 @@ contact_list_contact_added_cb (EmpathyContactManager *manager, priv = GET_PRIV (list); - gossip_debug (DEBUG_DOMAIN, "Contact:'%s' added", + gossip_debug (DEBUG_DOMAIN, + "Contact:'%s' added", gossip_contact_get_name (contact)); - /* Connect notifications for contact updates */ g_signal_connect (contact, "notify::groups", G_CALLBACK (contact_list_contact_groups_updated_cb), list); @@ -838,6 +885,10 @@ contact_list_contact_updated_cb (GossipContact *contact, GParamSpec *param, GossipContactList *list) { + gossip_debug (DEBUG_DOMAIN, + "Contact:'%s' updated, checking roster is in sync...", + gossip_contact_get_name (contact)); + contact_list_contact_update (list, contact); } @@ -866,32 +917,34 @@ contact_list_contact_set_active (GossipContactList *list, gboolean active, gboolean set_changed) { - GtkTreeModel *model; - GList *iters, *l; + GossipContactListPriv *priv; + GtkTreeModel *model; + GList *iters, *l; - model = gtk_tree_view_get_model (GTK_TREE_VIEW (list)); + priv = GET_PRIV (list); + + model = GTK_TREE_MODEL (priv->store); iters = contact_list_find_contact (list, contact); for (l = iters; l; l = l->next) { GtkTreePath *path; - GtkTreeIter *iter; - iter = l->data; - - gtk_tree_store_set (GTK_TREE_STORE (model), iter, + gtk_tree_store_set (priv->store, l->data, COL_IS_ACTIVE, active, -1); + gossip_debug (DEBUG_DOMAIN, "Set item %s", active ? "active" : "inactive"); if (set_changed) { - path = gtk_tree_model_get_path (model, iter); - gtk_tree_model_row_changed (model, path, iter); + path = gtk_tree_model_get_path (model, l->data); + gtk_tree_model_row_changed (model, path, l->data); gtk_tree_path_free (path); } } g_list_foreach (iters, (GFunc)gtk_tree_iter_free, NULL); g_list_free (iters); + } static ShowActiveData * @@ -1008,20 +1061,54 @@ contact_list_get_parent_group (GtkTreeModel *model, return name; } +static gboolean +contact_list_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, + COL_NAME, &str, + COL_IS_GROUP, &is_group, + -1); + + if (is_group && strcmp (str, fg->name) == 0) { + fg->found = TRUE; + fg->iter = *iter; + } + + g_free (str); + + return fg->found; +} + static void contact_list_get_group (GossipContactList *list, const gchar *name, - GtkTreeIter *iter_to_set, + GtkTreeIter *iter_group_to_set, + GtkTreeIter *iter_separator_to_set, gboolean *created) { - GtkTreeModel *model; - FindGroup fg; + GossipContactListPriv *priv; + GtkTreeModel *model; + GtkTreeIter iter_group, iter_separator; + FindGroup fg; + + priv = GET_PRIV (list); memset (&fg, 0, sizeof (fg)); fg.name = name; - model = gtk_tree_view_get_model (GTK_TREE_VIEW (list)); + model = GTK_TREE_MODEL (priv->store); gtk_tree_model_foreach (model, (GtkTreeModelForeachFunc) contact_list_get_group_foreach, &fg); @@ -1031,48 +1118,52 @@ contact_list_get_group (GossipContactList *list, *created = TRUE; } - gtk_tree_store_append (GTK_TREE_STORE (model), iter_to_set, NULL); - gtk_tree_store_set (GTK_TREE_STORE (model), iter_to_set, + gtk_tree_store_append (priv->store, &iter_group, NULL); + gtk_tree_store_set (priv->store, &iter_group, COL_PIXBUF_STATUS, NULL, COL_NAME, name, COL_IS_GROUP, TRUE, COL_IS_ACTIVE, FALSE, + COL_IS_SEPARATOR, FALSE, + -1); + + if (iter_group_to_set) { + *iter_group_to_set = iter_group; + } + + gtk_tree_store_append (priv->store, + &iter_separator, + &iter_group); + gtk_tree_store_set (priv->store, &iter_separator, + COL_IS_SEPARATOR, TRUE, -1); + + if (iter_separator_to_set) { + *iter_separator_to_set = iter_separator; + } } else { if (created) { *created = FALSE; } - *iter_to_set = fg.iter; - } -} - -static gboolean -contact_list_get_group_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - FindGroup *fg) -{ - gchar *str; - gboolean is_group; + if (iter_group_to_set) { + *iter_group_to_set = fg.iter; + } - /* Groups are only at the top level. */ - if (gtk_tree_path_get_depth (path) != 1) { - return FALSE; - } + iter_separator = fg.iter; - gtk_tree_model_get (model, iter, - COL_NAME, &str, - COL_IS_GROUP, &is_group, - -1); - if (is_group && strcmp (str, fg->name) == 0) { - fg->found = TRUE; - fg->iter = *iter; - } + if (gtk_tree_model_iter_next (model, &iter_separator)) { + gboolean is_separator; - g_free (str); + gtk_tree_model_get (model, &iter_separator, + COL_IS_SEPARATOR, &is_separator, + -1); - return fg->found; + if (is_separator && iter_separator_to_set) { + *iter_separator_to_set = iter_separator; + } + } + } } static void @@ -1080,7 +1171,7 @@ contact_list_add_contact (GossipContactList *list, GossipContact *contact) { GossipContactListPriv *priv; - GtkTreeIter iter, iter_group; + GtkTreeIter iter, iter_group, iter_separator; GtkTreeModel *model; GList *l, *groups; @@ -1090,7 +1181,7 @@ contact_list_add_contact (GossipContactList *list, return; } - model = gtk_tree_view_get_model (GTK_TREE_VIEW (list)); + model = GTK_TREE_MODEL (priv->store); /* If no groups just add it at the top level. */ groups = gossip_contact_get_groups (contact); @@ -1100,15 +1191,24 @@ contact_list_add_contact (GossipContactList *list, gboolean show_avatar = FALSE; pixbuf_status = gossip_pixbuf_for_contact (contact); - pixbuf_avatar = gossip_pixbuf_avatar_from_contact_scaled ( - contact, 32, 32); + pixbuf_avatar = gossip_pixbuf_avatar_from_contact_scaled (contact, 32, 32); if (priv->show_avatars && !priv->is_compact) { show_avatar = TRUE; } - gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL); - gtk_tree_store_set (GTK_TREE_STORE (model), &iter, + gossip_debug (DEBUG_DOMAIN, ""); + gossip_debug (DEBUG_DOMAIN, + "vvvvvvvvvvvvvvvv FIXME: Errors may follow below (since filter work) vvvvvvvvvvvvvvvv"); + + gossip_debug (DEBUG_DOMAIN, + "**** GossipContact:%p, is GObject:%s, is GossipContact:%s, ADDING CONTACT #1", + contact, + G_IS_OBJECT (contact) ? "yes" : "no", + GOSSIP_IS_CONTACT (contact) ? "yes" : "no"); + + gtk_tree_store_append (priv->store, &iter, NULL); + gtk_tree_store_set (priv->store, &iter, COL_PIXBUF_STATUS, pixbuf_status, COL_PIXBUF_AVATAR, pixbuf_avatar, COL_PIXBUF_AVATAR_VISIBLE, show_avatar, @@ -1119,8 +1219,13 @@ contact_list_add_contact (GossipContactList *list, COL_IS_GROUP, FALSE, COL_IS_ACTIVE, FALSE, COL_IS_ONLINE, gossip_contact_is_online (contact), + COL_IS_SEPARATOR, FALSE, -1); + gossip_debug (DEBUG_DOMAIN, + "^^^^^^^^^^^^^^^^ FIXME: Errors may occur above (since filter work) ^^^^^^^^^^^^^^^^"); + gossip_debug (DEBUG_DOMAIN, ""); + if (pixbuf_avatar) { g_object_unref (pixbuf_avatar); } @@ -1132,10 +1237,12 @@ contact_list_add_contact (GossipContactList *list, /* Else add to each group. */ for (l = groups; l; l = l->next) { GtkTreePath *path; + GtkTreeIter model_iter_group; GdkPixbuf *pixbuf_status; GdkPixbuf *pixbuf_avatar; const gchar *name; gboolean created; + gboolean found; gboolean show_avatar = FALSE; name = l->data; @@ -1144,17 +1251,26 @@ contact_list_add_contact (GossipContactList *list, } pixbuf_status = gossip_pixbuf_for_contact (contact); - pixbuf_avatar = gossip_pixbuf_avatar_from_contact_scaled ( - contact, 32, 32); + pixbuf_avatar = gossip_pixbuf_avatar_from_contact_scaled (contact, 32, 32); - contact_list_get_group (list, name, &iter_group, &created); + contact_list_get_group (list, name, &iter_group, &iter_separator, &created); if (priv->show_avatars && !priv->is_compact) { show_avatar = TRUE; } - gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &iter_group); - gtk_tree_store_set (GTK_TREE_STORE (model), &iter, + gossip_debug (DEBUG_DOMAIN, ""); + gossip_debug (DEBUG_DOMAIN, + "vvvvvvvvvvvvvvvv FIXME: Errors may follow below (since filter work) vvvvvvvvvvvvvvvv"); + + gossip_debug (DEBUG_DOMAIN, + "**** GossipContact:%p, is GObject:%s, is GossipContact:%s, ADDING CONTACT #2", + contact, + G_IS_OBJECT (contact) ? "yes" : "no", + GOSSIP_IS_CONTACT (contact) ? "yes" : "no"); + + gtk_tree_store_insert_after (priv->store, &iter, &iter_group, NULL); + gtk_tree_store_set (priv->store, &iter, COL_PIXBUF_STATUS, pixbuf_status, COL_PIXBUF_AVATAR, pixbuf_avatar, COL_PIXBUF_AVATAR_VISIBLE, show_avatar, @@ -1165,8 +1281,13 @@ contact_list_add_contact (GossipContactList *list, COL_IS_GROUP, FALSE, COL_IS_ACTIVE, FALSE, COL_IS_ONLINE, gossip_contact_is_online (contact), + COL_IS_SEPARATOR, FALSE, -1); + gossip_debug (DEBUG_DOMAIN, + "^^^^^^^^^^^^^^^^ FIXME: Errors may occur above (since filter work) ^^^^^^^^^^^^^^^^"); + gossip_debug (DEBUG_DOMAIN, ""); + if (pixbuf_avatar) { g_object_unref (pixbuf_avatar); } @@ -1178,7 +1299,14 @@ contact_list_add_contact (GossipContactList *list, continue; } - path = gtk_tree_model_get_path (model, &iter_group); + found = gtk_tree_model_filter_convert_child_iter_to_iter (GTK_TREE_MODEL_FILTER (priv->filter), + &model_iter_group, + &iter_group); + if (!found) { + continue; + } + + path = gtk_tree_model_get_path (model, &model_iter_group); if (!path) { continue; } @@ -1221,41 +1349,60 @@ contact_list_remove_contact (GossipContactList *list, } /* Clean up model */ - model = gtk_tree_view_get_model (GTK_TREE_VIEW (list)); + model = GTK_TREE_MODEL (priv->store); for (l = iters; l; l = l->next) { GtkTreeIter parent; + /* 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) && - gtk_tree_model_iter_n_children (model, &parent) <= 1) { - gtk_tree_store_remove (GTK_TREE_STORE (model), &parent); + gtk_tree_model_iter_n_children (model, &parent) <= 2) { + gtk_tree_store_remove (priv->store, &parent); } else { - gtk_tree_store_remove (GTK_TREE_STORE (model), l->data); + gtk_tree_store_remove (priv->store, l->data); } } - g_list_foreach (iters, (GFunc)gtk_tree_iter_free, NULL); + g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL); g_list_free (iters); } static void contact_list_create_model (GossipContactList *list) { - GtkTreeModel *model; + GossipContactListPriv *priv; + GtkTreeModel *model; + + priv = GET_PRIV (list); - model = GTK_TREE_MODEL ( - gtk_tree_store_new (COL_COUNT, - GDK_TYPE_PIXBUF, /* Status pixbuf */ - GDK_TYPE_PIXBUF, /* Avatar pixbuf */ - G_TYPE_BOOLEAN, /* Avatar pixbuf visible */ - G_TYPE_STRING, /* Name */ - G_TYPE_STRING, /* Status string */ - G_TYPE_BOOLEAN, /* Show status */ - GOSSIP_TYPE_CONTACT, /* Contact type */ - G_TYPE_BOOLEAN, /* Is group */ - G_TYPE_BOOLEAN, /* Is active */ - G_TYPE_BOOLEAN)); /* Is online */ + if (priv->store) { + g_object_unref (priv->store); + } + + if (priv->filter) { + g_object_unref (priv->filter); + } + + priv->store = gtk_tree_store_new (COL_COUNT, + GDK_TYPE_PIXBUF, /* Status pixbuf */ + GDK_TYPE_PIXBUF, /* Avatar pixbuf */ + G_TYPE_BOOLEAN, /* Avatar pixbuf visible */ + G_TYPE_STRING, /* Name */ + G_TYPE_STRING, /* Status string */ + G_TYPE_BOOLEAN, /* Show status */ + GOSSIP_TYPE_CONTACT, /* Contact type */ + G_TYPE_BOOLEAN, /* Is group */ + G_TYPE_BOOLEAN, /* Is active */ + G_TYPE_BOOLEAN, /* Is online */ + G_TYPE_BOOLEAN); /* Is separator */ + + /* Save normal model */ + model = GTK_TREE_MODEL (priv->store); + /* Set up sorting */ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (model), COL_NAME, contact_list_sort_func, @@ -1265,9 +1412,15 @@ contact_list_create_model (GossipContactList *list) COL_NAME, GTK_SORT_ASCENDING); - gtk_tree_view_set_model (GTK_TREE_VIEW (list), model); + /* Create filter */ + priv->filter = gtk_tree_model_filter_new (model, NULL); - g_object_unref (model); + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (priv->filter), + (GtkTreeModelFilterVisibleFunc) + contact_list_filter_func, + list, NULL); + + gtk_tree_view_set_model (GTK_TREE_VIEW (list), priv->filter); } static gboolean @@ -1281,14 +1434,21 @@ contact_list_search_equal_func (GtkTreeModel *model, gchar *key_folded; gboolean ret; - gtk_tree_model_get (model, iter, - COL_NAME, &name, - -1); + if (!key) { + return FALSE; + } + + gtk_tree_model_get (model, iter, COL_NAME, &name, -1); + + if (!name) { + return FALSE; + } name_folded = g_utf8_casefold (name, -1); key_folded = g_utf8_casefold (key, -1); - if (strstr (name_folded, key_folded)) { + if (name_folded && key_folded && + strstr (name_folded, key_folded)) { ret = FALSE; } else { ret = TRUE; @@ -1730,7 +1890,6 @@ contact_list_cell_set_background (GossipContactList *list, { GdkColor color; GtkStyle *style; - gint color_sum_normal, color_sum_selected; g_return_if_fail (list != NULL); g_return_if_fail (cell != NULL); @@ -1759,19 +1918,26 @@ contact_list_cell_set_background (GossipContactList *list, NULL); } } else { + g_object_set (cell, + "cell-background-gdk", NULL, + NULL); +#if 0 + gint color_sum_normal; + gint color_sum_selected; + color = style->base[GTK_STATE_SELECTED]; color_sum_normal = color.red+color.green+color.blue; color = style->base[GTK_STATE_NORMAL]; color_sum_selected = color.red+color.green+color.blue; color = style->text_aa[GTK_STATE_INSENSITIVE]; - if(color_sum_normal < color_sum_selected) { - /* found a light theme */ + if (color_sum_normal < color_sum_selected) { + /* Found a light theme */ color.red = (color.red + (style->white).red) / 2; color.green = (color.green + (style->white).green) / 2; color.blue = (color.blue + (style->white).blue) / 2; } else { - /* found a dark theme */ + /* Found a dark theme */ color.red = (color.red + (style->black).red) / 2; color.green = (color.green + (style->black).green) / 2; color.blue = (color.blue + (style->black).blue) / 2; @@ -1780,6 +1946,7 @@ contact_list_cell_set_background (GossipContactList *list, g_object_set (cell, "cell-background-gdk", &color, NULL); +#endif } } @@ -1980,7 +2147,7 @@ contact_list_button_press_event_cb (GossipContactList *list, priv = GET_PRIV (list); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list)); - model = gtk_tree_view_get_model (GTK_TREE_VIEW (list)); + model = GTK_TREE_MODEL (priv->store); gtk_widget_grab_focus (GTK_WIDGET (list)); @@ -2073,20 +2240,29 @@ contact_list_sort_func (GtkTreeModel *model, { gchar *name_a, *name_b; GossipContact *contact_a, *contact_b; + gboolean is_separator_a, is_separator_b; gint ret_val; gtk_tree_model_get (model, iter_a, COL_NAME, &name_a, COL_CONTACT, &contact_a, + COL_IS_SEPARATOR, &is_separator_a, -1); gtk_tree_model_get (model, iter_b, COL_NAME, &name_b, COL_CONTACT, &contact_b, + COL_IS_SEPARATOR, &is_separator_b, -1); /* If contact is NULL it means it's a group. */ - if (!contact_a && contact_b) { + if (is_separator_a || is_separator_b) { + if (is_separator_a) { + ret_val = -1; + } else if (is_separator_b) { + ret_val = 1; + } + } else if (!contact_a && contact_b) { ret_val = 1; } else if (contact_a && !contact_b) { ret_val = -1; @@ -2108,6 +2284,121 @@ contact_list_sort_func (GtkTreeModel *model, return ret_val; } +static gboolean +contact_list_filter_show_contact (GossipContact *contact, + const gchar *filter) +{ + gchar *str; + gboolean visible; + + /* Check contact id */ + str = g_utf8_casefold (gossip_contact_get_id (contact), -1); + visible = G_STR_EMPTY (str) || strstr (str, filter); + g_free (str); + + if (visible) { + return TRUE; + } + + /* Check contact name */ + str = g_utf8_casefold (gossip_contact_get_name (contact), -1); + visible = G_STR_EMPTY (str) || strstr (str, filter); + g_free (str); + + return visible; +} + +static gboolean +contact_list_filter_show_group (GossipContactList *list, + const gchar *group, + const gchar *filter) +{ + GossipContactListPriv *priv; + GList *contacts, *l; + gchar *str; + gboolean show_group = FALSE; + + priv = GET_PRIV (list); + + str = g_utf8_casefold (group, -1); + if (!str) { + return FALSE; + } + + /* If the filter is the partially the group name, we show the + * whole group. + */ + if (strstr (str, filter)) { + g_free (str); + return TRUE; + } + + /* At this point, we need to check in advance if this + * group should be shown because a contact we want to + * show exists in it. + */ + contacts = empathy_contact_manager_get_contacts (priv->manager); + for (l = contacts; l && !show_group; l = l->next) { + if (!gossip_contact_is_in_group (l->data, group)) { + continue; + } + + if (contact_list_filter_show_contact (l->data, filter)) { + show_group = TRUE; + } + } + g_list_foreach (contacts, (GFunc) g_object_unref, NULL); + g_list_free (contacts); + g_free (str); + + return show_group; +} + +static gboolean +contact_list_filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + GossipContactList *list) +{ + GossipContactListPriv *priv; + gboolean is_group; + gboolean is_separator; + gboolean visible = TRUE; + + priv = GET_PRIV (list); + + if (G_STR_EMPTY (priv->filter_text)) { + return TRUE; + } + + /* Check to see if iter matches any group names */ + gtk_tree_model_get (model, iter, + COL_IS_GROUP, &is_group, + COL_IS_SEPARATOR, &is_separator, + -1); + + if (is_group) { + gchar *name; + + gtk_tree_model_get (model, iter, COL_NAME, &name, -1); + visible &= contact_list_filter_show_group (list, + name, + priv->filter_text); + g_free (name); + } else if (is_separator) { + /* Do nothing here */ + } else { + GossipContact *contact; + + /* Check contact id */ + gtk_tree_model_get (model, iter, COL_CONTACT, &contact, -1); + visible &= contact_list_filter_show_contact (contact, + priv->filter_text); + g_object_unref (contact); + } + + return visible; +} + static gboolean contact_list_iter_equal_contact (GtkTreeModel *model, GtkTreeIter *iter, @@ -2130,19 +2421,40 @@ contact_list_iter_equal_contact (GtkTreeModel *model, return equal; } +static gboolean +contact_list_find_contact_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + FindContact *fc) +{ + if (contact_list_iter_equal_contact (model, iter, fc->contact)) { + fc->found = TRUE; + fc->iters = g_list_append (fc->iters, gtk_tree_iter_copy (iter)); + } + + /* We want to find ALL contacts that match, this means if we + * have the same contact in 3 groups, all iters should be + * returned. + */ + return FALSE; +} + static GList * contact_list_find_contact (GossipContactList *list, GossipContact *contact) { - GtkTreeModel *model; - FindContact fc; - GList *l = NULL; + GossipContactListPriv *priv; + GtkTreeModel *model; + GList *l = NULL; + FindContact fc; + + priv = GET_PRIV (list); memset (&fc, 0, sizeof (fc)); fc.contact = contact; - model = gtk_tree_view_get_model (GTK_TREE_VIEW (list)); + model = GTK_TREE_MODEL (priv->store); gtk_tree_model_foreach (model, (GtkTreeModelForeachFunc) contact_list_find_contact_foreach, &fc); @@ -2154,24 +2466,6 @@ contact_list_find_contact (GossipContactList *list, return l; } -static gboolean -contact_list_find_contact_foreach (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - FindContact *fc) -{ - if (contact_list_iter_equal_contact (model, iter, fc->contact)) { - fc->found = TRUE; - fc->iters = g_list_append (fc->iters, gtk_tree_iter_copy (iter)); - } - - /* We want to find ALL contacts that match, this means if we - * have the same contact in 3 groups, all iters should be - * returned. - */ - return FALSE; -} - static void contact_list_action_cb (GtkAction *action, GossipContactList *list) @@ -2236,7 +2530,7 @@ contact_list_update_list_mode_foreach (GtkTreeModel *model, show_avatar = TRUE; } - gtk_tree_store_set (GTK_TREE_STORE (model), iter, + gtk_tree_store_set (priv->store, iter, COL_PIXBUF_AVATAR_VISIBLE, show_avatar, COL_STATUS_VISIBLE, !priv->is_compact, -1); @@ -2317,6 +2611,30 @@ gossip_contact_list_get_show_offline (GossipContactList *list) return priv->show_offline; } +gboolean +gossip_contact_list_get_show_avatars (GossipContactList *list) +{ + GossipContactListPriv *priv; + + g_return_val_if_fail (GOSSIP_IS_CONTACT_LIST (list), TRUE); + + priv = GET_PRIV (list); + + return priv->show_avatars; +} + +gboolean +gossip_contact_list_get_is_compact (GossipContactList *list) +{ + GossipContactListPriv *priv; + + g_return_val_if_fail (GOSSIP_IS_CONTACT_LIST (list), TRUE); + + priv = GET_PRIV (list); + + return priv->is_compact; +} + void gossip_contact_list_set_show_offline (GossipContactList *list, gboolean show_offline) @@ -2351,18 +2669,6 @@ gossip_contact_list_set_show_offline (GossipContactList *list, priv->show_active = show_active; } -gboolean -gossip_contact_list_get_show_avatars (GossipContactList *list) -{ - GossipContactListPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONTACT_LIST (list), TRUE); - - priv = GET_PRIV (list); - - return priv->show_avatars; -} - void gossip_contact_list_set_show_avatars (GossipContactList *list, gboolean show_avatars) @@ -2376,7 +2682,7 @@ gossip_contact_list_set_show_avatars (GossipContactList *list, priv->show_avatars = show_avatars; - model = gtk_tree_view_get_model (GTK_TREE_VIEW (list)); + model = GTK_TREE_MODEL (priv->store); gtk_tree_model_foreach (model, (GtkTreeModelForeachFunc) @@ -2384,18 +2690,6 @@ gossip_contact_list_set_show_avatars (GossipContactList *list, list); } -gboolean -gossip_contact_list_get_is_compact (GossipContactList *list) -{ - GossipContactListPriv *priv; - - g_return_val_if_fail (GOSSIP_IS_CONTACT_LIST (list), TRUE); - - priv = GET_PRIV (list); - - return priv->is_compact; -} - void gossip_contact_list_set_is_compact (GossipContactList *list, gboolean is_compact) @@ -2409,7 +2703,7 @@ gossip_contact_list_set_is_compact (GossipContactList *list, priv->is_compact = is_compact; - model = gtk_tree_view_get_model (GTK_TREE_VIEW (list)); + model = GTK_TREE_MODEL (priv->store); gtk_tree_model_foreach (model, (GtkTreeModelForeachFunc) @@ -2417,3 +2711,23 @@ gossip_contact_list_set_is_compact (GossipContactList *list, list); } +void +gossip_contact_list_set_filter (GossipContactList *list, + const gchar *filter) +{ + GossipContactListPriv *priv; + + g_return_if_fail (GOSSIP_IS_CONTACT_LIST (list)); + + priv = GET_PRIV (list); + + g_free (priv->filter_text); + if (filter) { + priv->filter_text = g_utf8_casefold (filter, -1); + } else { + priv->filter_text = NULL; + } + + gossip_debug (DEBUG_DOMAIN, "Refiltering with filter:'%s' (case folded)", filter); + gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter)); +} diff --git a/libempathy-gtk/gossip-contact-list.h b/libempathy-gtk/gossip-contact-list.h index b5947b947..42c949c11 100644 --- a/libempathy-gtk/gossip-contact-list.h +++ b/libempathy-gtk/gossip-contact-list.h @@ -54,17 +54,19 @@ GossipContactList *gossip_contact_list_new (void); GossipContact * gossip_contact_list_get_selected (GossipContactList *list); gchar * gossip_contact_list_get_selected_group (GossipContactList *list); gboolean gossip_contact_list_get_show_offline (GossipContactList *list); +gboolean gossip_contact_list_get_show_avatars (GossipContactList *list); +gboolean gossip_contact_list_get_is_compact (GossipContactList *list); +GtkWidget * gossip_contact_list_get_contact_menu (GossipContactList *list, + GossipContact *contact); +GtkWidget * gossip_contact_list_get_group_menu (GossipContactList *list); void gossip_contact_list_set_show_offline (GossipContactList *list, gboolean show_offline); -gboolean gossip_contact_list_get_show_avatars (GossipContactList *list); void gossip_contact_list_set_show_avatars (GossipContactList *list, gboolean show_avatars); -gboolean gossip_contact_list_get_is_compact (GossipContactList *list); void gossip_contact_list_set_is_compact (GossipContactList *list, gboolean is_compact); -GtkWidget * gossip_contact_list_get_contact_menu (GossipContactList *list, - GossipContact *contact); -GtkWidget * gossip_contact_list_get_group_menu (GossipContactList *list); +void gossip_contact_list_set_filter (GossipContactList *list, + const gchar *filter); G_END_DECLS |