3 #include "empathy-roster-view.h"
5 #include <glib/gi18n-lib.h>
7 #include <libempathy-gtk/empathy-roster-contact.h>
8 #include <libempathy-gtk/empathy-roster-group.h>
9 #include <libempathy-gtk/empathy-ui-utils.h>
11 G_DEFINE_TYPE (EmpathyRosterView, empathy_roster_view, EGG_TYPE_LIST_BOX)
23 SIG_INDIVIDUAL_ACTIVATED,
24 SIG_POPUP_INDIVIDUAL_MENU,
28 static guint signals[LAST_SIGNAL];
30 #define NO_GROUP "X-no-group"
31 #define UNGROUPPED _("Ungroupped")
32 #define TOP_GROUP _("Most Used")
34 struct _EmpathyRosterViewPriv
36 EmpathyIndividualManager *manager;
38 /* FolksIndividual (borrowed) -> GHashTable (
39 * (gchar * group_name) -> EmpathyRosterContact (borrowed))
41 * When not using groups, this hash just have one element mapped
42 * from the special NO_GROUP key. We could use it as a set but
43 * I prefer to stay coherent in the way this hash is managed.
45 GHashTable *roster_contacts;
46 /* (gchar *group_name) -> EmpathyRosterGroup (borrowed) */
47 GHashTable *roster_groups;
49 gboolean show_offline;
52 EmpathyLiveSearch *search;
56 empathy_roster_view_get_property (GObject *object,
61 EmpathyRosterView *self = EMPATHY_ROSTER_VIEW (object);
66 g_value_set_object (value, self->priv->manager);
68 case PROP_SHOW_OFFLINE:
69 g_value_set_boolean (value, self->priv->show_offline);
71 case PROP_SHOW_GROUPS:
72 g_value_set_boolean (value, self->priv->show_groups);
75 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
81 empathy_roster_view_set_property (GObject *object,
86 EmpathyRosterView *self = EMPATHY_ROSTER_VIEW (object);
91 g_assert (self->priv->manager == NULL); /* construct only */
92 self->priv->manager = g_value_dup_object (value);
94 case PROP_SHOW_OFFLINE:
95 empathy_roster_view_show_offline (self, g_value_get_boolean (value));
97 case PROP_SHOW_GROUPS:
98 empathy_roster_view_show_groups (self, g_value_get_boolean (value));
101 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
107 roster_contact_changed_cb (GtkWidget *child,
109 EmpathyRosterView *self)
111 egg_list_box_child_changed (EGG_LIST_BOX (self), child);
115 add_roster_contact (EmpathyRosterView *self,
116 FolksIndividual *individual,
121 contact = empathy_roster_contact_new (individual, group);
123 /* Need to refilter if online is changed */
124 g_signal_connect (contact, "notify::online",
125 G_CALLBACK (roster_contact_changed_cb), self);
127 /* Need to resort if alias is changed */
128 g_signal_connect (contact, "notify::alias",
129 G_CALLBACK (roster_contact_changed_cb), self);
131 gtk_widget_show (contact);
132 gtk_container_add (GTK_CONTAINER (self), contact);
138 group_expanded_cb (EmpathyRosterGroup *group,
140 EmpathyRosterView *self)
144 widgets = empathy_roster_group_get_widgets (group);
145 for (l = widgets; l != NULL; l = g_list_next (l))
147 egg_list_box_child_changed (EGG_LIST_BOX (self), l->data);
150 g_list_free (widgets);
153 static EmpathyRosterGroup *
154 lookup_roster_group (EmpathyRosterView *self,
157 return g_hash_table_lookup (self->priv->roster_groups, group);
161 ensure_roster_group (EmpathyRosterView *self,
164 GtkWidget *roster_group;
166 roster_group = (GtkWidget *) lookup_roster_group (self, group);
167 if (roster_group != NULL)
170 roster_group = empathy_roster_group_new (group);
172 g_signal_connect (roster_group, "notify::expanded",
173 G_CALLBACK (group_expanded_cb), self);
175 gtk_widget_show (roster_group);
176 gtk_container_add (GTK_CONTAINER (self), roster_group);
178 g_hash_table_insert (self->priv->roster_groups, g_strdup (group),
183 add_to_group (EmpathyRosterView *self,
184 FolksIndividual *individual,
188 GHashTable *contacts;
190 contacts = g_hash_table_lookup (self->priv->roster_contacts, individual);
191 if (contacts == NULL)
194 if (tp_strdiff (group, NO_GROUP))
195 ensure_roster_group (self, group);
197 contact = add_roster_contact (self, individual, group);
198 g_hash_table_insert (contacts, g_strdup (group), contact);
202 individual_added (EmpathyRosterView *self,
203 FolksIndividual *individual)
205 GHashTable *contacts;
207 contacts = g_hash_table_lookup (self->priv->roster_contacts, individual);
208 if (contacts != NULL)
211 contacts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
213 g_hash_table_insert (self->priv->roster_contacts, individual, contacts);
215 if (!self->priv->show_groups)
217 add_to_group (self, individual, NO_GROUP);
223 groups = folks_group_details_get_groups (
224 FOLKS_GROUP_DETAILS (individual));
226 if (gee_collection_get_size (GEE_COLLECTION (groups)) > 0)
228 GeeIterator *iter = gee_iterable_iterator (GEE_ITERABLE (groups));
230 while (iter != NULL && gee_iterator_next (iter))
232 gchar *group = gee_iterator_get (iter);
234 add_to_group (self, individual, group);
239 g_clear_object (&iter);
243 /* No group, adds to Ungroupped */
244 add_to_group (self, individual, UNGROUPPED);
250 update_group_widgets_count (EmpathyRosterView *self,
251 EmpathyRosterGroup *group,
252 EmpathyRosterContact *contact,
257 if (empathy_roster_group_add_widget (group, GTK_WIDGET (contact)) == 1)
259 egg_list_box_child_changed (EGG_LIST_BOX (self),
265 if (empathy_roster_group_remove_widget (group, GTK_WIDGET (contact)) == 0)
267 egg_list_box_child_changed (EGG_LIST_BOX (self),
274 individual_removed (EmpathyRosterView *self,
275 FolksIndividual *individual)
277 GHashTable *contacts;
281 contacts = g_hash_table_lookup (self->priv->roster_contacts, individual);
282 if (contacts == NULL)
285 g_hash_table_iter_init (&iter, contacts);
286 while (g_hash_table_iter_next (&iter, &key, &value))
288 const gchar *group_name = key;
289 GtkWidget *contact = value;
290 EmpathyRosterGroup *group;
292 group = lookup_roster_group (self, group_name);
295 update_group_widgets_count (self, group,
296 EMPATHY_ROSTER_CONTACT (contact), FALSE);
299 gtk_container_remove (GTK_CONTAINER (self), contact);
302 g_hash_table_remove (self->priv->roster_contacts, individual);
306 members_changed_cb (EmpathyIndividualManager *manager,
307 const gchar *message,
310 TpChannelGroupChangeReason reason,
311 EmpathyRosterView *self)
315 for (l = added; l != NULL; l = g_list_next (l))
317 FolksIndividual *individual = l->data;
319 individual_added (self, individual);
322 for (l = removed; l != NULL; l = g_list_next (l))
324 FolksIndividual *individual = l->data;
326 individual_removed (self, individual);
331 compare_roster_contacts_by_alias (EmpathyRosterContact *a,
332 EmpathyRosterContact *b)
334 FolksIndividual *ind_a, *ind_b;
335 const gchar *alias_a, *alias_b;
337 ind_a = empathy_roster_contact_get_individual (a);
338 ind_b = empathy_roster_contact_get_individual (b);
340 alias_a = folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (ind_a));
341 alias_b = folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (ind_b));
343 return g_ascii_strcasecmp (alias_a, alias_b);
347 compare_individual_top_position (EmpathyRosterView *self,
348 EmpathyRosterContact *a,
349 EmpathyRosterContact *b)
351 FolksIndividual *ind_a, *ind_b;
353 gint index_a, index_b;
355 ind_a = empathy_roster_contact_get_individual (a);
356 ind_b = empathy_roster_contact_get_individual (b);
358 tops = empathy_individual_manager_get_top_individuals (self->priv->manager);
360 index_a = g_list_index (tops, ind_a);
361 index_b = g_list_index (tops, ind_b);
363 if (index_a == index_b)
372 return index_a - index_b;
376 compare_roster_contacts_no_group (EmpathyRosterView *self,
377 EmpathyRosterContact *a,
378 EmpathyRosterContact *b)
382 top = compare_individual_top_position (self, a, b);
386 return compare_roster_contacts_by_alias (a, b);
390 compare_group_names (const gchar *group_a,
391 const gchar *group_b)
393 if (!tp_strdiff (group_a, TOP_GROUP))
396 if (!tp_strdiff (group_b, TOP_GROUP))
399 return g_ascii_strcasecmp (group_a, group_b);
403 compare_roster_contacts_with_groups (EmpathyRosterView *self,
404 EmpathyRosterContact *a,
405 EmpathyRosterContact *b)
407 const gchar *group_a, *group_b;
409 group_a = empathy_roster_contact_get_group (a);
410 group_b = empathy_roster_contact_get_group (b);
412 if (!tp_strdiff (group_a, group_b))
413 /* Same group, compare the contacts */
414 return compare_roster_contacts_by_alias (a, b);
417 return compare_group_names (group_a, group_b);
421 compare_roster_contacts (EmpathyRosterView *self,
422 EmpathyRosterContact *a,
423 EmpathyRosterContact *b)
425 if (!self->priv->show_groups)
426 return compare_roster_contacts_no_group (self, a, b);
428 return compare_roster_contacts_with_groups (self, a, b);
432 compare_roster_groups (EmpathyRosterGroup *a,
433 EmpathyRosterGroup *b)
435 const gchar *name_a, *name_b;
437 name_a = empathy_roster_group_get_name (a);
438 name_b = empathy_roster_group_get_name (b);
440 return compare_group_names (name_a, name_b);
444 compare_contact_group (EmpathyRosterContact *contact,
445 EmpathyRosterGroup *group)
447 const char *contact_group, *group_name;
449 contact_group = empathy_roster_contact_get_group (contact);
450 group_name = empathy_roster_group_get_name (group);
452 if (!tp_strdiff (contact_group, group_name))
453 /* @contact is in @group, @group has to be displayed first */
456 /* @contact is in a different group, sort by group name */
457 return compare_group_names (contact_group, group_name);
461 roster_view_sort (gconstpointer a,
465 EmpathyRosterView *self = user_data;
467 if (EMPATHY_IS_ROSTER_CONTACT (a) && EMPATHY_IS_ROSTER_CONTACT (b))
468 return compare_roster_contacts (self, EMPATHY_ROSTER_CONTACT (a),
469 EMPATHY_ROSTER_CONTACT (b));
470 else if (EMPATHY_IS_ROSTER_GROUP (a) && EMPATHY_IS_ROSTER_GROUP (b))
471 return compare_roster_groups (EMPATHY_ROSTER_GROUP (a),
472 EMPATHY_ROSTER_GROUP (b));
473 else if (EMPATHY_IS_ROSTER_CONTACT (a) && EMPATHY_IS_ROSTER_GROUP (b))
474 return compare_contact_group (EMPATHY_ROSTER_CONTACT (a),
475 EMPATHY_ROSTER_GROUP (b));
476 else if (EMPATHY_IS_ROSTER_GROUP (a) && EMPATHY_IS_ROSTER_CONTACT (b))
477 return -1 * compare_contact_group (EMPATHY_ROSTER_CONTACT (b),
478 EMPATHY_ROSTER_GROUP (a));
480 g_return_val_if_reached (0);
484 update_separator (GtkWidget **separator,
491 /* No separator before the first row */
492 g_clear_object (separator);
496 if (*separator != NULL)
499 *separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
500 g_object_ref_sink (*separator);
504 is_searching (EmpathyRosterView *self)
506 if (self->priv->search == NULL)
509 return gtk_widget_get_visible (GTK_WIDGET (self->priv->search));
513 filter_contact (EmpathyRosterView *self,
514 EmpathyRosterContact *contact)
518 if (is_searching (self))
520 FolksIndividual *individual;
522 individual = empathy_roster_contact_get_individual (contact);
524 displayed = empathy_individual_match_string (individual,
525 empathy_live_search_get_text (self->priv->search),
526 empathy_live_search_get_words (self->priv->search));
530 if (self->priv->show_offline)
536 displayed = empathy_roster_contact_is_online (contact);
540 if (self->priv->show_groups)
542 const gchar *group_name;
543 EmpathyRosterGroup *group;
545 group_name = empathy_roster_contact_get_group (contact);
546 group = lookup_roster_group (self, group_name);
550 update_group_widgets_count (self, group, contact, displayed);
552 /* When searching, always display even if the group is closed */
553 if (!is_searching (self) &&
554 !gtk_expander_get_expanded (GTK_EXPANDER (group)))
563 filter_group (EmpathyRosterView *self,
564 EmpathyRosterGroup *group)
566 return empathy_roster_group_get_widgets_count (group);
570 filter_list (GtkWidget *child,
573 EmpathyRosterView *self = user_data;
575 if (EMPATHY_IS_ROSTER_CONTACT (child))
576 return filter_contact (self, EMPATHY_ROSTER_CONTACT (child));
578 else if (EMPATHY_IS_ROSTER_GROUP (child))
579 return filter_group (self, EMPATHY_ROSTER_GROUP (child));
581 g_return_val_if_reached (FALSE);
584 /* @list: GList of EmpathyRosterContact
586 * Returns: %TRUE if @list contains an EmpathyRosterContact associated with
589 individual_in_list (FolksIndividual *individual,
594 for (l = list; l != NULL; l = g_list_next (l))
596 EmpathyRosterContact *contact = l->data;
598 if (empathy_roster_contact_get_individual (contact) == individual)
606 populate_view (EmpathyRosterView *self)
608 GList *individuals, *l;
610 individuals = empathy_individual_manager_get_members (self->priv->manager);
611 for (l = individuals; l != NULL; l = g_list_next (l))
613 FolksIndividual *individual = l->data;
615 individual_added (self, individual);
618 g_list_free (individuals);
622 remove_from_group (EmpathyRosterView *self,
623 FolksIndividual *individual,
626 GHashTable *contacts;
628 EmpathyRosterGroup *roster_group;
630 contacts = g_hash_table_lookup (self->priv->roster_contacts, individual);
631 if (contacts == NULL)
634 contact = g_hash_table_lookup (contacts, group);
638 g_hash_table_remove (contacts, group);
640 if (g_hash_table_size (contacts) == 0)
642 add_to_group (self, individual, UNGROUPPED);
645 roster_group = lookup_roster_group (self, group);
647 if (roster_group != NULL)
649 update_group_widgets_count (self, roster_group,
650 EMPATHY_ROSTER_CONTACT (contact), FALSE);
653 gtk_container_remove (GTK_CONTAINER (self), contact);
657 update_top_contacts (EmpathyRosterView *self)
660 GList *to_add = NULL, *to_remove = NULL;
661 EmpathyRosterGroup *group;
663 if (!self->priv->show_groups)
665 egg_list_box_resort (EGG_LIST_BOX (self));
669 tops = empathy_individual_manager_get_top_individuals (self->priv->manager);
671 group = g_hash_table_lookup (self->priv->roster_groups, TOP_GROUP);
674 to_add = g_list_copy (tops);
680 contacts = empathy_roster_group_get_widgets (group);
682 /* Check which EmpathyRosterContact have to be removed */
683 for (l = contacts; l != NULL; l = g_list_next (l))
685 EmpathyRosterContact *contact = l->data;
686 FolksIndividual *individual;
688 individual = empathy_roster_contact_get_individual (contact);
690 if (g_list_find (tops, individual) == NULL)
691 to_remove = g_list_prepend (to_remove, individual);
694 /* Check which EmpathyRosterContact have to be added */
695 for (l = tops; l != NULL; l = g_list_next (l))
697 FolksIndividual *individual = l->data;
699 if (!individual_in_list (individual, contacts))
700 to_add = g_list_prepend (to_add, individual);
704 for (l = to_add; l != NULL; l = g_list_next (l))
705 add_to_group (self, l->data, TOP_GROUP);
707 for (l = to_remove; l != NULL; l = g_list_next (l))
708 remove_from_group (self, l->data, TOP_GROUP);
710 g_list_free (to_add);
711 g_list_free (to_remove);
715 groups_changed_cb (EmpathyIndividualManager *manager,
716 FolksIndividual *individual,
719 EmpathyRosterView *self)
721 if (!self->priv->show_groups)
726 add_to_group (self, individual, group);
730 remove_from_group (self, individual, group);
735 top_individuals_changed_cb (EmpathyIndividualManager *manager,
737 EmpathyRosterView *self)
739 update_top_contacts (self);
743 empathy_roster_view_constructed (GObject *object)
745 EmpathyRosterView *self = EMPATHY_ROSTER_VIEW (object);
746 void (*chain_up) (GObject *) =
747 ((GObjectClass *) empathy_roster_view_parent_class)->constructed;
749 if (chain_up != NULL)
752 g_assert (EMPATHY_IS_INDIVIDUAL_MANAGER (self->priv->manager));
754 populate_view (self);
756 tp_g_signal_connect_object (self->priv->manager, "members-changed",
757 G_CALLBACK (members_changed_cb), self, 0);
758 tp_g_signal_connect_object (self->priv->manager, "groups-changed",
759 G_CALLBACK (groups_changed_cb), self, 0);
760 tp_g_signal_connect_object (self->priv->manager, "notify::top-individuals",
761 G_CALLBACK (top_individuals_changed_cb), self, 0);
763 egg_list_box_set_sort_func (EGG_LIST_BOX (self),
764 roster_view_sort, self, NULL);
766 egg_list_box_set_separator_funcs (EGG_LIST_BOX (self), update_separator,
769 egg_list_box_set_filter_func (EGG_LIST_BOX (self), filter_list, self, NULL);
771 egg_list_box_set_activate_on_single_click (EGG_LIST_BOX (self), FALSE);
775 empathy_roster_view_dispose (GObject *object)
777 EmpathyRosterView *self = EMPATHY_ROSTER_VIEW (object);
778 void (*chain_up) (GObject *) =
779 ((GObjectClass *) empathy_roster_view_parent_class)->dispose;
781 empathy_roster_view_set_live_search (self, NULL);
782 g_clear_object (&self->priv->manager);
784 if (chain_up != NULL)
789 empathy_roster_view_finalize (GObject *object)
791 EmpathyRosterView *self = EMPATHY_ROSTER_VIEW (object);
792 void (*chain_up) (GObject *) =
793 ((GObjectClass *) empathy_roster_view_parent_class)->finalize;
795 g_hash_table_unref (self->priv->roster_contacts);
796 g_hash_table_unref (self->priv->roster_groups);
798 if (chain_up != NULL)
803 empathy_roster_view_child_activated (EggListBox *box,
806 EmpathyRosterContact *contact;
807 FolksIndividual *individual;
809 if (!EMPATHY_IS_ROSTER_CONTACT (child))
812 contact = EMPATHY_ROSTER_CONTACT (child);
813 individual = empathy_roster_contact_get_individual (contact);
815 g_signal_emit (box, signals[SIG_INDIVIDUAL_ACTIVATED], 0, individual);
819 fire_popup_individual_menu (EmpathyRosterView *self,
824 EmpathyRosterContact *contact;
825 FolksIndividual *individual;
827 if (!EMPATHY_IS_ROSTER_CONTACT (child))
830 contact = EMPATHY_ROSTER_CONTACT (child);
831 individual = empathy_roster_contact_get_individual (contact);
833 g_signal_emit (self, signals[SIG_POPUP_INDIVIDUAL_MENU], 0,
834 individual, button, time);
838 empathy_roster_view_button_press_event (GtkWidget *widget,
839 GdkEventButton *event)
841 EmpathyRosterView *self = EMPATHY_ROSTER_VIEW (widget);
842 gboolean (*chain_up) (GtkWidget *, GdkEventButton *) =
843 ((GtkWidgetClass *) empathy_roster_view_parent_class)->button_press_event;
845 if (event->button == 3)
849 child = egg_list_box_get_child_at_y (EGG_LIST_BOX (self), event->y);
852 fire_popup_individual_menu (self, child, event->button, event->time);
855 return chain_up (widget, event);
859 empathy_roster_view_key_press_event (GtkWidget *widget,
862 EmpathyRosterView *self = EMPATHY_ROSTER_VIEW (widget);
863 gboolean (*chain_up) (GtkWidget *, GdkEventKey *) =
864 ((GtkWidgetClass *) empathy_roster_view_parent_class)->key_press_event;
866 if (event->keyval == GDK_KEY_Menu)
870 child = egg_list_box_get_selected_child (EGG_LIST_BOX (self));
873 fire_popup_individual_menu (self, child, 0, event->time);
876 return chain_up (widget, event);
880 empathy_roster_view_class_init (
881 EmpathyRosterViewClass *klass)
883 GObjectClass *oclass = G_OBJECT_CLASS (klass);
884 EggListBoxClass *box_class = EGG_LIST_BOX_CLASS (klass);
885 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
888 oclass->get_property = empathy_roster_view_get_property;
889 oclass->set_property = empathy_roster_view_set_property;
890 oclass->constructed = empathy_roster_view_constructed;
891 oclass->dispose = empathy_roster_view_dispose;
892 oclass->finalize = empathy_roster_view_finalize;
894 widget_class->button_press_event = empathy_roster_view_button_press_event;
895 widget_class->key_press_event = empathy_roster_view_key_press_event;
897 box_class->child_activated = empathy_roster_view_child_activated;
899 spec = g_param_spec_object ("manager", "Manager",
900 "EmpathyIndividualManager",
901 EMPATHY_TYPE_INDIVIDUAL_MANAGER,
902 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
903 g_object_class_install_property (oclass, PROP_MANAGER, spec);
905 spec = g_param_spec_boolean ("show-offline", "Show Offline",
906 "Show offline contacts",
908 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
909 g_object_class_install_property (oclass, PROP_SHOW_OFFLINE, spec);
911 spec = g_param_spec_boolean ("show-groups", "Show Groups",
914 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
915 g_object_class_install_property (oclass, PROP_SHOW_GROUPS, spec);
917 signals[SIG_INDIVIDUAL_ACTIVATED] = g_signal_new ("individual-activated",
918 G_OBJECT_CLASS_TYPE (klass),
922 1, FOLKS_TYPE_INDIVIDUAL);
924 signals[SIG_POPUP_INDIVIDUAL_MENU] = g_signal_new ("popup-individual-menu",
925 G_OBJECT_CLASS_TYPE (klass),
929 3, FOLKS_TYPE_INDIVIDUAL, G_TYPE_UINT, G_TYPE_UINT);
931 g_type_class_add_private (klass, sizeof (EmpathyRosterViewPriv));
935 empathy_roster_view_init (EmpathyRosterView *self)
937 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
938 EMPATHY_TYPE_ROSTER_VIEW, EmpathyRosterViewPriv);
940 self->priv->roster_contacts = g_hash_table_new_full (NULL, NULL,
941 NULL, (GDestroyNotify) g_hash_table_unref);
942 self->priv->roster_groups = g_hash_table_new_full (g_str_hash, g_str_equal,
947 empathy_roster_view_new (EmpathyIndividualManager *manager)
949 g_return_val_if_fail (EMPATHY_IS_INDIVIDUAL_MANAGER (manager), NULL);
951 return g_object_new (EMPATHY_TYPE_ROSTER_VIEW,
956 EmpathyIndividualManager *
957 empathy_roster_view_get_manager (EmpathyRosterView *self)
959 return self->priv->manager;
963 empathy_roster_view_show_offline (EmpathyRosterView *self,
966 if (self->priv->show_offline == show)
969 self->priv->show_offline = show;
970 egg_list_box_refilter (EGG_LIST_BOX (self));
972 g_object_notify (G_OBJECT (self), "show-offline");
976 clear_view (EmpathyRosterView *self)
978 gtk_container_foreach (GTK_CONTAINER (self),
979 (GtkCallback) gtk_widget_destroy, NULL);
981 g_hash_table_remove_all (self->priv->roster_contacts);
985 empathy_roster_view_show_groups (EmpathyRosterView *self,
988 if (self->priv->show_groups == show)
991 self->priv->show_groups = show;
993 /* TODO: block sort/filter? */
995 populate_view (self);
997 g_object_notify (G_OBJECT (self), "show-groups");
1001 select_first_contact (EmpathyRosterView *self)
1003 GList *children, *l;
1005 children = gtk_container_get_children (GTK_CONTAINER (self));
1006 for (l = children; l != NULL; l = g_list_next (l))
1008 GtkWidget *child = l->data;
1010 if (!gtk_widget_get_child_visible (child))
1013 if (!EMPATHY_IS_ROSTER_CONTACT (child))
1016 egg_list_box_select_child (EGG_LIST_BOX (self), child);
1020 g_list_free (children);
1024 search_text_notify_cb (EmpathyLiveSearch *search,
1026 EmpathyRosterView *self)
1028 egg_list_box_refilter (EGG_LIST_BOX (self));
1030 select_first_contact (self);
1034 search_activate_cb (GtkWidget *search,
1035 EmpathyRosterView *self)
1037 EggListBox *box = EGG_LIST_BOX (self);
1040 child = egg_list_box_get_selected_child (box);
1044 empathy_roster_view_child_activated (box, child);
1048 empathy_roster_view_set_live_search (EmpathyRosterView *self,
1049 EmpathyLiveSearch *search)
1051 if (self->priv->search != NULL)
1053 g_signal_handlers_disconnect_by_func (self->priv->search,
1054 search_text_notify_cb, self);
1055 g_signal_handlers_disconnect_by_func (self->priv->search,
1056 search_activate_cb, self);
1058 g_clear_object (&self->priv->search);
1064 self->priv->search = g_object_ref (search);
1066 g_signal_connect (self->priv->search, "notify::text",
1067 G_CALLBACK (search_text_notify_cb), self);
1068 g_signal_connect (self->priv->search, "activate",
1069 G_CALLBACK (search_activate_cb), self);