4 #include "empathy-roster-view.h"
6 #include <libempathy-gtk/empathy-roster-contact.h>
8 G_DEFINE_TYPE (EmpathyRosterView, empathy_roster_view, EGG_TYPE_LIST_BOX)
24 static guint signals[LAST_SIGNAL];
27 struct _EmpathyRosterViewPriv
29 EmpathyIndividualManager *manager;
31 /* FolksIndividual (borrowed) -> GHashTable (used as a set) of
32 * EmpathyRosterContact (borrowed) */
33 GHashTable *roster_contacts;
35 gboolean show_offline;
40 empathy_roster_view_get_property (GObject *object,
45 EmpathyRosterView *self = EMPATHY_ROSTER_VIEW (object);
50 g_value_set_object (value, self->priv->manager);
52 case PROP_SHOW_OFFLINE:
53 g_value_set_boolean (value, self->priv->show_offline);
55 case PROP_SHOW_GROUPS:
56 g_value_set_boolean (value, self->priv->show_groups);
59 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
65 empathy_roster_view_set_property (GObject *object,
70 EmpathyRosterView *self = EMPATHY_ROSTER_VIEW (object);
75 g_assert (self->priv->manager == NULL); /* construct only */
76 self->priv->manager = g_value_dup_object (value);
78 case PROP_SHOW_OFFLINE:
79 empathy_roster_view_show_offline (self, g_value_get_boolean (value));
81 case PROP_SHOW_GROUPS:
82 empathy_roster_view_show_groups (self, g_value_get_boolean (value));
85 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
91 roster_contact_changed_cb (GtkWidget *child,
93 EmpathyRosterView *self)
95 egg_list_box_child_changed (EGG_LIST_BOX (self), child);
99 add_roster_contact (EmpathyRosterView *self,
100 FolksIndividual *individual)
104 contact = empathy_roster_contact_new (individual);
106 /* Need to refilter if online is changed */
107 g_signal_connect (contact, "notify::online",
108 G_CALLBACK (roster_contact_changed_cb), self);
110 /* Need to resort if alias is changed */
111 g_signal_connect (contact, "notify::alias",
112 G_CALLBACK (roster_contact_changed_cb), self);
114 gtk_widget_show (contact);
115 gtk_container_add (GTK_CONTAINER (self), contact);
121 individual_added (EmpathyRosterView *self,
122 FolksIndividual *individual)
125 GHashTable *contacts;
127 contacts = g_hash_table_lookup (self->priv->roster_contacts, individual);
128 if (contacts != NULL)
131 contacts = g_hash_table_new (NULL, NULL);
133 contact = add_roster_contact (self, individual);
134 g_hash_table_add (contacts, contact);
136 g_hash_table_insert (self->priv->roster_contacts, individual, contacts);
140 individual_removed (EmpathyRosterView *self,
141 FolksIndividual *individual)
143 GHashTable *contacts;
147 contacts = g_hash_table_lookup (self->priv->roster_contacts, individual);
148 if (contacts == NULL)
151 g_hash_table_iter_init (&iter, contacts);
152 while (g_hash_table_iter_next (&iter, &key, NULL))
154 GtkWidget *contact = key;
156 gtk_container_remove (GTK_CONTAINER (self), contact);
159 g_hash_table_remove (self->priv->roster_contacts, individual);
163 members_changed_cb (EmpathyIndividualManager *manager,
164 const gchar *message,
167 TpChannelGroupChangeReason reason,
168 EmpathyRosterView *self)
172 for (l = added; l != NULL; l = g_list_next (l))
174 FolksIndividual *individual = l->data;
176 individual_added (self, individual);
179 for (l = removed; l != NULL; l = g_list_next (l))
181 FolksIndividual *individual = l->data;
183 individual_removed (self, individual);
188 roster_view_sort (EmpathyRosterContact *a,
189 EmpathyRosterContact *b,
190 EmpathyRosterView *self)
192 FolksIndividual *ind_a, *ind_b;
193 const gchar *alias_a, *alias_b;
195 ind_a = empathy_roster_contact_get_individual (a);
196 ind_b = empathy_roster_contact_get_individual (b);
198 alias_a = folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (ind_a));
199 alias_b = folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (ind_b));
201 return g_ascii_strcasecmp (alias_a, alias_b);
205 update_separator (GtkWidget **separator,
212 /* No separator before the first row */
213 g_clear_object (separator);
217 if (*separator != NULL)
220 *separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
221 g_object_ref_sink (*separator);
225 filter_list (GtkWidget *child,
228 EmpathyRosterView *self = user_data;
229 EmpathyRosterContact *contact = EMPATHY_ROSTER_CONTACT (child);
231 if (self->priv->show_offline)
234 return empathy_roster_contact_is_online (contact);
238 populate_view (EmpathyRosterView *self)
240 GList *individuals, *l;
242 individuals = empathy_individual_manager_get_members (self->priv->manager);
243 for (l = individuals; l != NULL; l = g_list_next (l))
245 FolksIndividual *individual = l->data;
247 individual_added (self, individual);
250 g_list_free (individuals);
254 empathy_roster_view_constructed (GObject *object)
256 EmpathyRosterView *self = EMPATHY_ROSTER_VIEW (object);
257 void (*chain_up) (GObject *) =
258 ((GObjectClass *) empathy_roster_view_parent_class)->constructed;
260 if (chain_up != NULL)
263 g_assert (EMPATHY_IS_INDIVIDUAL_MANAGER (self->priv->manager));
265 populate_view (self);
267 tp_g_signal_connect_object (self->priv->manager, "members-changed",
268 G_CALLBACK (members_changed_cb), self, 0);
270 egg_list_box_set_sort_func (EGG_LIST_BOX (self),
271 (GCompareDataFunc) roster_view_sort, self, NULL);
273 egg_list_box_set_separator_funcs (EGG_LIST_BOX (self), update_separator,
276 egg_list_box_set_filter_func (EGG_LIST_BOX (self), filter_list, self, NULL);
280 empathy_roster_view_dispose (GObject *object)
282 EmpathyRosterView *self = EMPATHY_ROSTER_VIEW (object);
283 void (*chain_up) (GObject *) =
284 ((GObjectClass *) empathy_roster_view_parent_class)->dispose;
286 g_clear_object (&self->priv->manager);
288 if (chain_up != NULL)
293 empathy_roster_view_finalize (GObject *object)
295 EmpathyRosterView *self = EMPATHY_ROSTER_VIEW (object);
296 void (*chain_up) (GObject *) =
297 ((GObjectClass *) empathy_roster_view_parent_class)->finalize;
299 g_hash_table_unref (self->priv->roster_contacts);
301 if (chain_up != NULL)
306 empathy_roster_view_class_init (
307 EmpathyRosterViewClass *klass)
309 GObjectClass *oclass = G_OBJECT_CLASS (klass);
312 oclass->get_property = empathy_roster_view_get_property;
313 oclass->set_property = empathy_roster_view_set_property;
314 oclass->constructed = empathy_roster_view_constructed;
315 oclass->dispose = empathy_roster_view_dispose;
316 oclass->finalize = empathy_roster_view_finalize;
318 spec = g_param_spec_object ("manager", "Manager",
319 "EmpathyIndividualManager",
320 EMPATHY_TYPE_INDIVIDUAL_MANAGER,
321 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
322 g_object_class_install_property (oclass, PROP_MANAGER, spec);
324 spec = g_param_spec_boolean ("show-offline", "Show Offline",
325 "Show offline contacts",
327 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
328 g_object_class_install_property (oclass, PROP_SHOW_OFFLINE, spec);
330 spec = g_param_spec_boolean ("show-groups", "Show Groups",
333 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
334 g_object_class_install_property (oclass, PROP_SHOW_GROUPS, spec);
336 g_type_class_add_private (klass, sizeof (EmpathyRosterViewPriv));
340 empathy_roster_view_init (EmpathyRosterView *self)
342 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
343 EMPATHY_TYPE_ROSTER_VIEW, EmpathyRosterViewPriv);
345 self->priv->roster_contacts = g_hash_table_new_full (NULL, NULL,
346 NULL, (GDestroyNotify) g_hash_table_unref);
350 empathy_roster_view_new (EmpathyIndividualManager *manager)
352 g_return_val_if_fail (EMPATHY_IS_INDIVIDUAL_MANAGER (manager), NULL);
354 return g_object_new (EMPATHY_TYPE_ROSTER_VIEW,
359 EmpathyIndividualManager *
360 empathy_roster_view_get_manager (EmpathyRosterView *self)
362 return self->priv->manager;
366 empathy_roster_view_show_offline (EmpathyRosterView *self,
369 if (self->priv->show_offline == show)
372 self->priv->show_offline = show;
373 egg_list_box_refilter (EGG_LIST_BOX (self));
375 g_object_notify (G_OBJECT (self), "show-offline");
379 clear_view (EmpathyRosterView *self)
381 gtk_container_foreach (GTK_CONTAINER (self),
382 (GtkCallback) gtk_widget_destroy, NULL);
384 g_hash_table_remove_all (self->priv->roster_contacts);
388 empathy_roster_view_show_groups (EmpathyRosterView *self,
391 if (self->priv->show_groups == show)
394 self->priv->show_groups = show;
397 populate_view (self);
399 g_object_notify (G_OBJECT (self), "show-groups");