]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-roster-view.c
set separators between contacts
[empathy.git] / libempathy-gtk / empathy-roster-view.c
1
2 #include "config.h"
3
4 #include "empathy-roster-view.h"
5
6 #include <libempathy-gtk/empathy-roster-item.h>
7
8 G_DEFINE_TYPE (EmpathyRosterView, empathy_roster_view, EGG_TYPE_LIST_BOX)
9
10 enum
11 {
12   PROP_MANAGER = 1,
13   N_PROPS
14 };
15
16 /*
17 enum
18 {
19   LAST_SIGNAL
20 };
21
22 static guint signals[LAST_SIGNAL];
23 */
24
25 struct _EmpathyRosterViewPriv
26 {
27   EmpathyIndividualManager *manager;
28
29   /* FolksIndividual (borrowed) -> EmpathyRosterItem (borrowed) */
30   GHashTable *items;
31 };
32
33 static void
34 empathy_roster_view_get_property (GObject *object,
35     guint property_id,
36     GValue *value,
37     GParamSpec *pspec)
38 {
39   EmpathyRosterView *self = EMPATHY_ROSTER_VIEW (object);
40
41   switch (property_id)
42     {
43       case PROP_MANAGER:
44         g_value_set_object (value, self->priv->manager);
45         break;
46       default:
47         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
48         break;
49     }
50 }
51
52 static void
53 empathy_roster_view_set_property (GObject *object,
54     guint property_id,
55     const GValue *value,
56     GParamSpec *pspec)
57 {
58   EmpathyRosterView *self = EMPATHY_ROSTER_VIEW (object);
59
60   switch (property_id)
61     {
62       case PROP_MANAGER:
63         g_assert (self->priv->manager == NULL); /* construct only */
64         self->priv->manager = g_value_dup_object (value);
65         break;
66       default:
67         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
68         break;
69     }
70 }
71
72 static void
73 individual_added (EmpathyRosterView *self,
74     FolksIndividual *individual)
75 {
76   GtkWidget *item;
77
78   item = g_hash_table_lookup (self->priv->items, individual);
79   if (item != NULL)
80     return;
81
82   item = empathy_roster_item_new (individual);
83
84   gtk_widget_show (item);
85   gtk_container_add (GTK_CONTAINER (self), item);
86
87   g_hash_table_insert (self->priv->items, individual, item);
88 }
89
90 static void
91 individual_removed (EmpathyRosterView *self,
92     FolksIndividual *individual)
93 {
94   GtkWidget *item;
95
96   item = g_hash_table_lookup (self->priv->items, individual);
97   if (item == NULL)
98     return;
99
100   gtk_container_remove (GTK_CONTAINER (self), item);
101
102   g_hash_table_remove (self->priv->items, individual);
103 }
104
105 static void
106 members_changed_cb (EmpathyIndividualManager *manager,
107     const gchar *message,
108     GList *added,
109     GList *removed,
110     TpChannelGroupChangeReason reason,
111     EmpathyRosterView *self)
112 {
113   GList *l;
114
115   for (l = added; l != NULL; l = g_list_next (l))
116     {
117       FolksIndividual *individual = l->data;
118
119       individual_added (self, individual);
120     }
121
122   for (l = removed; l != NULL; l = g_list_next (l))
123     {
124       FolksIndividual *individual = l->data;
125
126       individual_removed (self, individual);
127     }
128 }
129
130 static gint
131 roster_view_sort (EmpathyRosterItem *a,
132     EmpathyRosterItem *b,
133     EmpathyRosterView *self)
134 {
135   FolksIndividual *ind_a, *ind_b;
136   const gchar *alias_a, *alias_b;
137
138   ind_a = empathy_roster_item_get_individual (a);
139   ind_b = empathy_roster_item_get_individual (b);
140
141   alias_a = folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (ind_a));
142   alias_b = folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (ind_b));
143
144   return g_ascii_strcasecmp (alias_a, alias_b);
145 }
146
147 static void
148 update_separator (GtkWidget **separator,
149     GtkWidget *child,
150     GtkWidget *before,
151     gpointer user_data)
152 {
153   if (before == NULL)
154     {
155       /* No separator before the first row */
156       g_clear_object (separator);
157       return;
158     }
159
160   if (*separator != NULL)
161     return;
162
163   *separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
164   g_object_ref_sink (*separator);
165 }
166
167 static void
168 empathy_roster_view_constructed (GObject *object)
169 {
170   EmpathyRosterView *self = EMPATHY_ROSTER_VIEW (object);
171   void (*chain_up) (GObject *) =
172       ((GObjectClass *) empathy_roster_view_parent_class)->constructed;
173   GList *individuals, *l;
174
175   if (chain_up != NULL)
176     chain_up (object);
177
178   g_assert (EMPATHY_IS_INDIVIDUAL_MANAGER (self->priv->manager));
179
180   individuals = empathy_individual_manager_get_members (self->priv->manager);
181   for (l = individuals; l != NULL; l = g_list_next (l))
182     {
183       FolksIndividual *individual = l->data;
184
185       individual_added (self, individual);
186     }
187
188   tp_g_signal_connect_object (self->priv->manager, "members-changed",
189       G_CALLBACK (members_changed_cb), self, 0);
190
191   g_list_free (individuals);
192
193   egg_list_box_set_sort_func (EGG_LIST_BOX (self),
194       (GCompareDataFunc) roster_view_sort, self, NULL);
195
196   egg_list_box_set_separator_funcs (EGG_LIST_BOX (self), update_separator,
197       self, NULL);
198 }
199
200 static void
201 empathy_roster_view_dispose (GObject *object)
202 {
203   EmpathyRosterView *self = EMPATHY_ROSTER_VIEW (object);
204   void (*chain_up) (GObject *) =
205       ((GObjectClass *) empathy_roster_view_parent_class)->dispose;
206
207   g_clear_object (&self->priv->manager);
208
209   if (chain_up != NULL)
210     chain_up (object);
211 }
212
213 static void
214 empathy_roster_view_finalize (GObject *object)
215 {
216   EmpathyRosterView *self = EMPATHY_ROSTER_VIEW (object);
217   void (*chain_up) (GObject *) =
218       ((GObjectClass *) empathy_roster_view_parent_class)->finalize;
219
220   g_hash_table_unref (self->priv->items);
221
222   if (chain_up != NULL)
223     chain_up (object);
224 }
225
226 static void
227 empathy_roster_view_class_init (
228     EmpathyRosterViewClass *klass)
229 {
230   GObjectClass *oclass = G_OBJECT_CLASS (klass);
231   GParamSpec *spec;
232
233   oclass->get_property = empathy_roster_view_get_property;
234   oclass->set_property = empathy_roster_view_set_property;
235   oclass->constructed = empathy_roster_view_constructed;
236   oclass->dispose = empathy_roster_view_dispose;
237   oclass->finalize = empathy_roster_view_finalize;
238
239   spec = g_param_spec_object ("manager", "Manager",
240       "EmpathyIndividualManager",
241       EMPATHY_TYPE_INDIVIDUAL_MANAGER,
242       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
243   g_object_class_install_property (oclass, PROP_MANAGER, spec);
244
245   g_type_class_add_private (klass, sizeof (EmpathyRosterViewPriv));
246 }
247
248 static void
249 empathy_roster_view_init (EmpathyRosterView *self)
250 {
251   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
252       EMPATHY_TYPE_ROSTER_VIEW, EmpathyRosterViewPriv);
253
254   self->priv->items = g_hash_table_new (NULL, NULL);
255 }
256
257 GtkWidget *
258 empathy_roster_view_new (EmpathyIndividualManager *manager)
259 {
260   g_return_val_if_fail (EMPATHY_IS_INDIVIDUAL_MANAGER (manager), NULL);
261
262   return g_object_new (EMPATHY_TYPE_ROSTER_VIEW,
263       "manager", manager,
264       NULL);
265 }
266
267 EmpathyIndividualManager *
268 empathy_roster_view_get_manager (EmpathyRosterView *self)
269 {
270   return self->priv->manager;
271 }