aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>2012-08-10 23:23:52 +0800
committerGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>2012-08-10 23:23:52 +0800
commita5346f80e2d9b5f2fac7909e3688a6ae69d823a8 (patch)
tree29c30be05dc6fc86827b845d07367026851e4d71
parent53257c1959bb7575cf72868e5ce798f5984d62d8 (diff)
parent91186e9bfcc4dc46d329f18ff0533a6bfff97a65 (diff)
downloadgsoc2013-empathy-a5346f80e2d9b5f2fac7909e3688a6ae69d823a8.tar
gsoc2013-empathy-a5346f80e2d9b5f2fac7909e3688a6ae69d823a8.tar.gz
gsoc2013-empathy-a5346f80e2d9b5f2fac7909e3688a6ae69d823a8.tar.bz2
gsoc2013-empathy-a5346f80e2d9b5f2fac7909e3688a6ae69d823a8.tar.lz
gsoc2013-empathy-a5346f80e2d9b5f2fac7909e3688a6ae69d823a8.tar.xz
gsoc2013-empathy-a5346f80e2d9b5f2fac7909e3688a6ae69d823a8.tar.zst
gsoc2013-empathy-a5346f80e2d9b5f2fac7909e3688a6ae69d823a8.zip
Merge remote-tracking branch 'burton/aggregator'
-rw-r--r--libempathy-gtk/Makefile.am2
-rw-r--r--libempathy-gtk/empathy-roster-model-aggregator.c425
-rw-r--r--libempathy-gtk/empathy-roster-model-aggregator.h93
-rw-r--r--tests/interactive/Makefile.am4
-rw-r--r--tests/interactive/test-empathy-roster-model-aggregator.c164
5 files changed, 687 insertions, 1 deletions
diff --git a/libempathy-gtk/Makefile.am b/libempathy-gtk/Makefile.am
index 87d787525..902a5e57f 100644
--- a/libempathy-gtk/Makefile.am
+++ b/libempathy-gtk/Makefile.am
@@ -77,6 +77,7 @@ libempathy_gtk_handwritten_source = \
empathy-roster-contact.c \
empathy-roster-group.c \
empathy-roster-model.c \
+ empathy-roster-model-aggregator.c \
empathy-roster-model-manager.c \
empathy-roster-view.c \
empathy-search-bar.c \
@@ -148,6 +149,7 @@ libempathy_gtk_headers = \
empathy-roster-contact.h \
empathy-roster-group.h \
empathy-roster-model.h \
+ empathy-roster-model-aggregator.h \
empathy-roster-model-manager.h \
empathy-roster-view.h \
empathy-search-bar.h \
diff --git a/libempathy-gtk/empathy-roster-model-aggregator.c b/libempathy-gtk/empathy-roster-model-aggregator.c
new file mode 100644
index 000000000..b0b68449a
--- /dev/null
+++ b/libempathy-gtk/empathy-roster-model-aggregator.c
@@ -0,0 +1,425 @@
+/*
+ * empathy-roster-model-aggregator.c
+ *
+ * Implementation of EmpathyRosterModel using FolksIndividualAggregator as
+ * source.
+ *
+ * Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include "config.h"
+
+#include <folks/folks.h>
+#include <folks/folks-telepathy.h>
+
+#include "empathy-roster-model-aggregator.h"
+
+/**
+ * SECTION: empathy-roster-model-aggregator
+ * @title: EmpathyRosterModelAggregator
+ * @short_description: TODO
+ *
+ * TODO
+ */
+
+/**
+ * EmpathyRosterModelAggregator:
+ *
+ * Data structure representing a #EmpathyRosterModelAggregator.
+ *
+ * Since: UNRELEASED
+ */
+
+/**
+ * EmpathyRosterModelAggregatorClass:
+ *
+ * The class of a #EmpathyRosterModelAggregator.
+ *
+ * Since: UNRELEASED
+ */
+
+static void roster_model_iface_init (EmpathyRosterModelInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EmpathyRosterModelAggregator,
+ empathy_roster_model_aggregator,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_ROSTER_MODEL, roster_model_iface_init))
+
+enum
+{
+ PROP_AGGREGATOR = 1,
+ PROP_FILTER_FUNC,
+ PROP_FILTER_DATA,
+ N_PROPS
+};
+
+/*
+enum
+{
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+*/
+
+struct _EmpathyRosterModelAggregatorPriv
+{
+ FolksIndividualAggregator *aggregator;
+ GHashTable *filtered_individuals; /* Individual -> Individual */
+
+ EmpathyRosterModelAggregatorFilterFunc filter_func;
+ gpointer filter_data;
+};
+
+static void
+individual_group_changed_cb (FolksIndividual *individual,
+ gchar *group,
+ gboolean is_member,
+ EmpathyRosterModelAggregator *self)
+{
+ empathy_roster_model_fire_groups_changed (EMPATHY_ROSTER_MODEL (self),
+ individual, group, is_member);
+}
+
+static void
+add_to_filtered_individuals (EmpathyRosterModelAggregator *self,
+ FolksIndividual *individual)
+{
+ g_hash_table_add (self->priv->filtered_individuals,
+ g_object_ref (individual));
+
+ tp_g_signal_connect_object (individual, "group-changed",
+ G_CALLBACK (individual_group_changed_cb), self, 0);
+
+ empathy_roster_model_fire_individual_added (EMPATHY_ROSTER_MODEL (self),
+ individual);
+}
+
+static void
+remove_from_filtered_individuals (EmpathyRosterModelAggregator *self,
+ FolksIndividual *individual)
+{
+ g_signal_handlers_disconnect_by_func (individual,
+ individual_group_changed_cb, self);
+
+ g_hash_table_remove (self->priv->filtered_individuals, individual);
+
+ empathy_roster_model_fire_individual_removed (EMPATHY_ROSTER_MODEL (self),
+ individual);
+}
+
+static void
+individual_notify_cb (FolksIndividual *individual,
+ GParamSpec *param,
+ EmpathyRosterModelAggregator *self)
+{
+ if (!self->priv->filter_func (EMPATHY_ROSTER_MODEL (self), individual, self)
+ && g_hash_table_contains (self->priv->filtered_individuals, individual))
+ remove_from_filtered_individuals (self, individual);
+
+ if (self->priv->filter_func (EMPATHY_ROSTER_MODEL (self), individual, self)
+ && !g_hash_table_contains (self->priv->filtered_individuals, individual))
+ add_to_filtered_individuals (self, individual);
+}
+
+static void
+add_individual (EmpathyRosterModelAggregator *self,
+ FolksIndividual *individual)
+{
+ if (self->priv->filter_func != NULL)
+ {
+ tp_g_signal_connect_object (individual, "notify",
+ G_CALLBACK (individual_notify_cb), self, 0);
+
+ if (!self->priv->filter_func (EMPATHY_ROSTER_MODEL (self), individual,
+ self))
+ return;
+ }
+
+ add_to_filtered_individuals (self, individual);
+}
+
+static void
+remove_individual (EmpathyRosterModelAggregator *self,
+ FolksIndividual *individual)
+{
+ if (self->priv->filter_func != NULL)
+ g_signal_handlers_disconnect_by_func (individual,
+ individual_notify_cb, self);
+
+ if (g_hash_table_contains (self->priv->filtered_individuals,
+ individual))
+ remove_from_filtered_individuals (self, individual);
+}
+
+static void
+populate_individuals (EmpathyRosterModelAggregator *self)
+{
+ GeeMap *individuals;
+ GeeMapIterator *iter;
+
+ individuals = folks_individual_aggregator_get_individuals (
+ self->priv->aggregator);
+ iter = gee_map_map_iterator (individuals);
+ while (gee_map_iterator_next (iter))
+ {
+ add_individual (self, gee_map_iterator_get_value (iter));
+ }
+ g_clear_object (&iter);
+}
+
+static void
+aggregator_individuals_changed_cb (FolksIndividualAggregator *aggregator,
+ GeeSet *added,
+ GeeSet *removed,
+ gchar *message,
+ FolksPersona *actor,
+ FolksGroupDetailsChangeReason reason,
+ EmpathyRosterModelAggregator *self)
+{
+ if (gee_collection_get_size (GEE_COLLECTION (added)) > 0)
+ {
+ GeeIterator *iter = gee_iterable_iterator (GEE_ITERABLE (added));
+
+ while (iter != NULL && gee_iterator_next (iter))
+ {
+ add_individual (self, gee_iterator_get (iter));
+ }
+ g_clear_object (&iter);
+ }
+
+ if (gee_collection_get_size (GEE_COLLECTION (removed)) > 0)
+ {
+ GeeIterator *iter = gee_iterable_iterator (GEE_ITERABLE (removed));
+
+ while (iter != NULL && gee_iterator_next (iter))
+ {
+ remove_individual (self, gee_iterator_get (iter));
+ }
+ g_clear_object (&iter);
+ }
+}
+
+static void
+empathy_roster_model_aggregator_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EmpathyRosterModelAggregator *self = EMPATHY_ROSTER_MODEL_AGGREGATOR (object);
+
+ switch (property_id)
+ {
+ case PROP_AGGREGATOR:
+ g_value_set_object (value, self->priv->aggregator);
+ break;
+ case PROP_FILTER_FUNC:
+ g_value_set_pointer (value, self->priv->filter_func);
+ break;
+ case PROP_FILTER_DATA:
+ g_value_set_pointer (value, self->priv->filter_data);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+empathy_roster_model_aggregator_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EmpathyRosterModelAggregator *self = EMPATHY_ROSTER_MODEL_AGGREGATOR (object);
+
+ switch (property_id)
+ {
+ case PROP_AGGREGATOR:
+ g_assert (self->priv->aggregator == NULL); /* construct only */
+ self->priv->aggregator = g_value_dup_object (value);
+ break;
+ case PROP_FILTER_FUNC:
+ g_assert (self->priv->filter_func == NULL); /* construct only */
+ self->priv->filter_func = g_value_get_pointer (value);
+ break;
+ case PROP_FILTER_DATA:
+ g_assert (self->priv->filter_data == NULL); /* construct only */
+ self->priv->filter_data = g_value_get_pointer (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+empathy_roster_model_aggregator_constructed (GObject *object)
+{
+ EmpathyRosterModelAggregator *self = EMPATHY_ROSTER_MODEL_AGGREGATOR (object);
+ void (*chain_up) (GObject *) =
+ ((GObjectClass *) empathy_roster_model_aggregator_parent_class)->constructed;
+
+ if (chain_up != NULL)
+ chain_up (object);
+
+ if (self->priv->aggregator == NULL)
+ self->priv->aggregator = folks_individual_aggregator_new ();
+
+ g_assert (FOLKS_IS_INDIVIDUAL_AGGREGATOR (self->priv->aggregator));
+
+ tp_g_signal_connect_object (self->priv->aggregator, "individuals-changed",
+ G_CALLBACK (aggregator_individuals_changed_cb), self, 0);
+
+ folks_individual_aggregator_prepare (self->priv->aggregator, NULL, NULL);
+
+ populate_individuals (self);
+}
+
+static void
+empathy_roster_model_aggregator_dispose (GObject *object)
+{
+ EmpathyRosterModelAggregator *self = EMPATHY_ROSTER_MODEL_AGGREGATOR (object);
+ void (*chain_up) (GObject *) =
+ ((GObjectClass *) empathy_roster_model_aggregator_parent_class)->dispose;
+
+ g_clear_object (&self->priv->aggregator);
+ g_clear_pointer (&self->priv->filtered_individuals, g_hash_table_unref);
+
+ if (chain_up != NULL)
+ chain_up (object);
+}
+
+static void
+empathy_roster_model_aggregator_finalize (GObject *object)
+{
+ //EmpathyRosterModelAggregator *self = EMPATHY_ROSTER_MODEL_AGGREGATOR (object);
+ void (*chain_up) (GObject *) =
+ ((GObjectClass *) empathy_roster_model_aggregator_parent_class)->finalize;
+
+ if (chain_up != NULL)
+ chain_up (object);
+}
+
+static void
+empathy_roster_model_aggregator_class_init (
+ EmpathyRosterModelAggregatorClass *klass)
+{
+ GObjectClass *oclass = G_OBJECT_CLASS (klass);
+ GParamSpec *spec;
+
+ oclass->get_property = empathy_roster_model_aggregator_get_property;
+ oclass->set_property = empathy_roster_model_aggregator_set_property;
+ oclass->constructed = empathy_roster_model_aggregator_constructed;
+ oclass->dispose = empathy_roster_model_aggregator_dispose;
+ oclass->finalize = empathy_roster_model_aggregator_finalize;
+
+ spec = g_param_spec_object ("aggregator", "Aggregator",
+ "FolksIndividualAggregator",
+ FOLKS_TYPE_INDIVIDUAL_AGGREGATOR,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_AGGREGATOR, spec);
+
+ spec = g_param_spec_pointer ("filter-func", "Filter-Func",
+ "EmpathyRosterModelAggregatorFilterFunc",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_FILTER_FUNC, spec);
+
+ spec = g_param_spec_pointer ("filter-data", "Filter-Data",
+ "GPointer",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_FILTER_DATA, spec);
+
+ g_type_class_add_private (klass, sizeof (EmpathyRosterModelAggregatorPriv));
+}
+
+static void
+empathy_roster_model_aggregator_init (EmpathyRosterModelAggregator *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ EMPATHY_TYPE_ROSTER_MODEL_AGGREGATOR, EmpathyRosterModelAggregatorPriv);
+
+ self->priv->filtered_individuals = g_hash_table_new_full (NULL, NULL, NULL,
+ g_object_unref);
+}
+
+EmpathyRosterModelAggregator *
+empathy_roster_model_aggregator_new (
+ EmpathyRosterModelAggregatorFilterFunc filter_func,
+ gpointer user_data)
+{
+ return g_object_new (EMPATHY_TYPE_ROSTER_MODEL_AGGREGATOR,
+ "filter-func", filter_func,
+ "filter-data", user_data,
+ NULL);
+}
+
+EmpathyRosterModelAggregator *
+empathy_roster_model_aggregator_new_with_aggregator (
+ FolksIndividualAggregator *aggregator,
+ EmpathyRosterModelAggregatorFilterFunc filter_func,
+ gpointer user_data)
+{
+ g_return_val_if_fail (FOLKS_IS_INDIVIDUAL_AGGREGATOR (aggregator), NULL);
+
+ return g_object_new (EMPATHY_TYPE_ROSTER_MODEL_AGGREGATOR,
+ "aggregator", aggregator,
+ "filter-func", filter_func,
+ "filter-data", user_data,
+ NULL);
+}
+
+static GList *
+empathy_roster_model_aggregator_get_individuals (EmpathyRosterModel *model)
+{
+ EmpathyRosterModelAggregator *self = EMPATHY_ROSTER_MODEL_AGGREGATOR (model);
+
+ return g_hash_table_get_values (self->priv->filtered_individuals);
+}
+
+static GList *
+empathy_roster_model_aggregator_get_groups_for_individual (
+ EmpathyRosterModel *model,
+ FolksIndividual *individual)
+{
+ GList *groups_list = NULL;
+ GeeSet *groups_set;
+
+ groups_set = folks_group_details_get_groups (
+ FOLKS_GROUP_DETAILS (individual));
+ if (gee_collection_get_size (GEE_COLLECTION (groups_set)) > 0)
+ {
+ GeeIterator *iter = gee_iterable_iterator (GEE_ITERABLE (groups_set));
+
+ while (iter != NULL && gee_iterator_next (iter))
+ {
+ groups_list = g_list_prepend (groups_list, gee_iterator_get (iter));
+ }
+ g_clear_object (&iter);
+ }
+
+ return groups_list;
+}
+
+static void
+roster_model_iface_init (EmpathyRosterModelInterface *iface)
+{
+ iface->get_individuals = empathy_roster_model_aggregator_get_individuals;
+ iface->get_groups_for_individual =
+ empathy_roster_model_aggregator_get_groups_for_individual;
+}
diff --git a/libempathy-gtk/empathy-roster-model-aggregator.h b/libempathy-gtk/empathy-roster-model-aggregator.h
new file mode 100644
index 000000000..e29e36eb0
--- /dev/null
+++ b/libempathy-gtk/empathy-roster-model-aggregator.h
@@ -0,0 +1,93 @@
+/*
+ * empathy-roster-model-aggregator.h
+ *
+ * Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#ifndef __EMPATHY_ROSTER_MODEL_AGGREGATOR_H__
+#define __EMPATHY_ROSTER_MODEL_AGGREGATOR_H__
+
+#include <glib-object.h>
+
+#include <folks/folks.h>
+
+#include "empathy-roster-model.h"
+
+G_BEGIN_DECLS
+
+typedef struct _EmpathyRosterModelAggregator EmpathyRosterModelAggregator;
+typedef struct _EmpathyRosterModelAggregatorClass
+EmpathyRosterModelAggregatorClass;
+typedef struct _EmpathyRosterModelAggregatorPriv
+EmpathyRosterModelAggregatorPriv;
+
+struct _EmpathyRosterModelAggregatorClass
+{
+ /*<private>*/
+ GObjectClass parent_class;
+};
+
+struct _EmpathyRosterModelAggregator
+{
+ /*<private>*/
+ GObject parent;
+ EmpathyRosterModelAggregatorPriv *priv;
+};
+
+typedef gboolean (* EmpathyRosterModelAggregatorFilterFunc) (
+ EmpathyRosterModel *model,
+ FolksIndividual *individual,
+ gpointer user_data);
+
+GType empathy_roster_model_aggregator_get_type (void);
+
+/* TYPE MACROS */
+#define EMPATHY_TYPE_ROSTER_MODEL_AGGREGATOR \
+ (empathy_roster_model_aggregator_get_type ())
+#define EMPATHY_ROSTER_MODEL_AGGREGATOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ EMPATHY_TYPE_ROSTER_MODEL_AGGREGATOR, \
+ EmpathyRosterModelAggregator))
+#define EMPATHY_ROSTER_MODEL_AGGREGATOR_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), \
+ EMPATHY_TYPE_ROSTER_MODEL_AGGREGATOR, \
+ EmpathyRosterModelAggregatorClass))
+#define EMPATHY_IS_ROSTER_MODEL_AGGREGATOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
+ EMPATHY_TYPE_ROSTER_MODEL_AGGREGATOR))
+#define EMPATHY_IS_ROSTER_MODEL_AGGREGATOR_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), \
+ EMPATHY_TYPE_ROSTER_MODEL_AGGREGATOR))
+#define EMPATHY_ROSTER_MODEL_AGGREGATOR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ EMPATHY_TYPE_ROSTER_MODEL_AGGREGATOR, \
+ EmpathyRosterModelAggregatorClass))
+
+EmpathyRosterModelAggregator * empathy_roster_model_aggregator_new (
+ EmpathyRosterModelAggregatorFilterFunc filter_func,
+ gpointer user_data);
+
+EmpathyRosterModelAggregator *
+empathy_roster_model_aggregator_new_with_aggregator (
+ FolksIndividualAggregator *aggregator,
+ EmpathyRosterModelAggregatorFilterFunc filter_func,
+ gpointer user_data);
+
+G_END_DECLS
+
+#endif /* #ifndef __EMPATHY_ROSTER_MODEL_AGGREGATOR_H__*/
diff --git a/tests/interactive/Makefile.am b/tests/interactive/Makefile.am
index d741f24da..27fdbf7e4 100644
--- a/tests/interactive/Makefile.am
+++ b/tests/interactive/Makefile.am
@@ -20,7 +20,8 @@ noinst_PROGRAMS = \
test-empathy-account-chooser \
test-empathy-calendar-button \
test-empathy-roster-view \
- test-empathy-dual-roster-view
+ test-empathy-dual-roster-view \
+ test-empathy-roster-model-aggregator
empathy_logs_SOURCES = empathy-logs.c
test_empathy_contact_blocking_dialog_SOURCES = test-empathy-contact-blocking-dialog.c
@@ -31,3 +32,4 @@ test_empathy_account_chooser_SOURCES = test-empathy-account-chooser.c
test_empathy_calendar_button_SOURCES = test-empathy-calendar-button.c
test_empathy_roster_view_SOURCES = test-empathy-roster-view.c
test_empathy_dual_roster_view_SOURCES = test-empathy-dual-roster-view.c
+test_empathy_roster_model_aggregator_SOURCES = test-empathy-roster-model-aggregator.c
diff --git a/tests/interactive/test-empathy-roster-model-aggregator.c b/tests/interactive/test-empathy-roster-model-aggregator.c
new file mode 100644
index 000000000..49f2012f0
--- /dev/null
+++ b/tests/interactive/test-empathy-roster-model-aggregator.c
@@ -0,0 +1,164 @@
+#include <config.h>
+
+#include <libempathy-gtk/empathy-roster-model.h>
+#include <libempathy-gtk/empathy-roster-model-aggregator.h>
+
+#include <libempathy-gtk/empathy-roster-view.h>
+#include <libempathy-gtk/empathy-ui-utils.h>
+
+static gboolean show_offline = FALSE;
+static gboolean show_groups = FALSE;
+
+static GOptionEntry entries[] =
+ {
+ { "offline", 0, 0, G_OPTION_ARG_NONE, &show_offline, "Show offline contacts", NULL },
+ { "groups", 0, 0, G_OPTION_ARG_NONE, &show_groups, "Show groups", NULL },
+ { NULL }
+ };
+
+static void
+individual_activated_cb (EmpathyRosterView *self,
+ FolksIndividual *individual,
+ gpointer user_data)
+{
+ g_assert (FOLKS_IS_INDIVIDUAL (individual));
+
+ g_print ("'%s' activated\n",
+ folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (individual)));
+}
+
+static void
+popup_individual_menu_cb (EmpathyRosterView *self,
+ FolksIndividual *individual,
+ guint button,
+ guint time,
+ gpointer user_data)
+{
+ GtkWidget *menu, *item;
+
+ g_print ("'%s' popup menu\n",
+ folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (individual)));
+
+ menu = gtk_menu_new ();
+
+ g_signal_connect (menu, "deactivate",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+
+ item = gtk_menu_item_new_with_label (folks_alias_details_get_alias (
+ FOLKS_ALIAS_DETAILS (individual)));
+ gtk_widget_show (item);
+
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+
+ gtk_menu_attach_to_widget (GTK_MENU (menu), GTK_WIDGET (self), NULL);
+
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, button, time);
+}
+
+static gboolean
+individual_tooltip_cb (EmpathyRosterView *view,
+ FolksIndividual *individual,
+ gboolean keyboard_mode,
+ GtkTooltip *tooltip,
+ gpointer user_data)
+{
+ gtk_tooltip_set_text (tooltip,
+ folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (individual)));
+
+ return TRUE;
+}
+
+static void
+empty_cb (EmpathyRosterView *view,
+ GParamSpec *spec,
+ gpointer user_data)
+{
+ if (empathy_roster_view_is_empty (view))
+ g_print ("view is now empty\n");
+ else
+ g_print ("view is no longer empty\n");
+}
+
+static gboolean
+filter (EmpathyRosterModel *model,
+ FolksIndividual *individual,
+ gpointer user_data)
+{
+ if (folks_avatar_details_get_avatar (FOLKS_AVATAR_DETAILS (individual))
+ == NULL)
+ return FALSE;
+
+ return TRUE;
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ GtkWidget *window, *view, *scrolled, *box, *search;
+ GError *error = NULL;
+ GOptionContext *context;
+ EmpathyRosterModel *model;
+
+ gtk_init (&argc, &argv);
+ empathy_gtk_init ();
+
+ context = g_option_context_new ("- test tree model performance");
+ g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
+ g_option_context_add_group (context, gtk_get_option_group (TRUE));
+ if (!g_option_context_parse (context, &argc, &argv, &error))
+ {
+ g_print ("option parsing failed: %s\n", error->message);
+ return 1;
+ }
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ empathy_set_css_provider (window);
+
+ box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
+
+ model = EMPATHY_ROSTER_MODEL (empathy_roster_model_aggregator_new (
+ filter, NULL));
+ view = empathy_roster_view_new (model);
+
+ g_object_unref (model);
+ g_signal_connect (view, "individual-activated",
+ G_CALLBACK (individual_activated_cb), NULL);
+ g_signal_connect (view, "popup-individual-menu",
+ G_CALLBACK (popup_individual_menu_cb), NULL);
+ g_signal_connect (view, "notify::empty",
+ G_CALLBACK (empty_cb), NULL);
+ g_signal_connect (view, "individual-tooltip",
+ G_CALLBACK (individual_tooltip_cb), NULL);
+
+ gtk_widget_set_has_tooltip (view, TRUE);
+
+ empathy_roster_view_show_offline (EMPATHY_ROSTER_VIEW (view), show_offline);
+ empathy_roster_view_show_groups (EMPATHY_ROSTER_VIEW (view), show_groups);
+
+ search = empathy_live_search_new (view);
+ empathy_roster_view_set_live_search (EMPATHY_ROSTER_VIEW (view),
+ EMPATHY_LIVE_SEARCH (search));
+
+ scrolled = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+
+ egg_list_box_add_to_scrolled (EGG_LIST_BOX (view),
+ GTK_SCROLLED_WINDOW (scrolled));
+
+ gtk_box_pack_start (GTK_BOX (box), search, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (box), scrolled, TRUE, TRUE, 0);
+ gtk_container_add (GTK_CONTAINER (window), box);
+
+ gtk_window_set_default_size (GTK_WINDOW (window), 300, 600);
+ gtk_widget_show_all (window);
+
+ g_signal_connect_swapped (window, "destroy",
+ G_CALLBACK (gtk_main_quit), NULL);
+
+ gtk_main ();
+
+ return 0;
+}