aboutsummaryrefslogtreecommitdiffstats
path: root/libempathy-gtk
diff options
context:
space:
mode:
Diffstat (limited to 'libempathy-gtk')
-rw-r--r--libempathy-gtk/gossip-account-widget-generic.c2
-rw-r--r--libempathy-gtk/gossip-account-widget-jabber.c4
-rw-r--r--libempathy-gtk/gossip-contact-list.c598
-rw-r--r--libempathy-gtk/gossip-contact-list.h12
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