]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-roster-model-aggregator.c
remove released flag
[empathy.git] / libempathy-gtk / empathy-roster-model-aggregator.c
1 /*
2  * empathy-roster-model-aggregator.c
3  *
4  * Implementation of EmpathyRosterModel using FolksIndividualAggregator as
5  * source.
6  *
7  * Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22  */
23
24 #include "config.h"
25 #include "empathy-roster-model-aggregator.h"
26
27 #include <folks/folks-telepathy.h>
28
29 /**
30  * SECTION: empathy-roster-model-aggregator
31  * @title: EmpathyRosterModelAggregator
32  * @short_description: TODO
33  *
34  * TODO
35  */
36
37 /**
38  * EmpathyRosterModelAggregator:
39  *
40  * Data structure representing a #EmpathyRosterModelAggregator.
41  *
42  * Since: UNRELEASED
43  */
44
45 /**
46  * EmpathyRosterModelAggregatorClass:
47  *
48  * The class of a #EmpathyRosterModelAggregator.
49  *
50  * Since: UNRELEASED
51  */
52
53 static void roster_model_iface_init (EmpathyRosterModelInterface *iface);
54
55 G_DEFINE_TYPE_WITH_CODE (EmpathyRosterModelAggregator,
56     empathy_roster_model_aggregator,
57     G_TYPE_OBJECT,
58     G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_ROSTER_MODEL, roster_model_iface_init))
59
60 enum
61 {
62   PROP_AGGREGATOR = 1,
63   PROP_FILTER_FUNC,
64   PROP_FILTER_DATA,
65   N_PROPS
66 };
67
68 /*
69 enum
70 {
71   LAST_SIGNAL
72 };
73
74 static guint signals[LAST_SIGNAL];
75 */
76
77 struct _EmpathyRosterModelAggregatorPriv
78 {
79   FolksIndividualAggregator *aggregator;
80   GHashTable *filtered_individuals; /* Individual -> Individual */
81
82   EmpathyRosterModelAggregatorFilterFunc filter_func;
83   gpointer filter_data;
84 };
85
86 static void
87 individual_group_changed_cb (FolksIndividual *individual,
88     gchar *group,
89     gboolean is_member,
90     EmpathyRosterModelAggregator *self)
91 {
92   empathy_roster_model_fire_groups_changed (EMPATHY_ROSTER_MODEL (self),
93       individual, group, is_member);
94 }
95
96 static void
97 add_to_filtered_individuals (EmpathyRosterModelAggregator *self,
98     FolksIndividual *individual)
99 {
100   g_hash_table_add (self->priv->filtered_individuals,
101       g_object_ref (individual));
102
103   tp_g_signal_connect_object (individual, "group-changed",
104       G_CALLBACK (individual_group_changed_cb), self, 0);
105
106   empathy_roster_model_fire_individual_added (EMPATHY_ROSTER_MODEL (self),
107       individual);
108 }
109
110 static void
111 remove_from_filtered_individuals (EmpathyRosterModelAggregator *self,
112     FolksIndividual *individual)
113 {
114   g_signal_handlers_disconnect_by_func (individual,
115       individual_group_changed_cb, self);
116
117   g_hash_table_remove (self->priv->filtered_individuals, individual);
118
119   empathy_roster_model_fire_individual_removed (EMPATHY_ROSTER_MODEL (self),
120       individual);
121 }
122
123 static void
124 individual_notify_cb (FolksIndividual *individual,
125     GParamSpec *param,
126     EmpathyRosterModelAggregator *self)
127 {
128   if (!self->priv->filter_func (EMPATHY_ROSTER_MODEL (self), individual, self)
129       && g_hash_table_contains (self->priv->filtered_individuals, individual))
130     remove_from_filtered_individuals (self, individual);
131
132   if (self->priv->filter_func (EMPATHY_ROSTER_MODEL (self), individual, self)
133       && !g_hash_table_contains (self->priv->filtered_individuals, individual))
134     add_to_filtered_individuals (self, individual);
135 }
136
137 static void
138 add_individual (EmpathyRosterModelAggregator *self,
139     FolksIndividual *individual)
140 {
141   if (self->priv->filter_func != NULL)
142     {
143       tp_g_signal_connect_object (individual, "notify",
144           G_CALLBACK (individual_notify_cb), self, 0);
145
146       if (!self->priv->filter_func (EMPATHY_ROSTER_MODEL (self), individual,
147               self))
148         return;
149     }
150
151   add_to_filtered_individuals (self, individual);
152 }
153
154 static void
155 remove_individual (EmpathyRosterModelAggregator *self,
156     FolksIndividual *individual)
157 {
158   if (self->priv->filter_func != NULL)
159     g_signal_handlers_disconnect_by_func (individual,
160         individual_notify_cb, self);
161
162   if (g_hash_table_contains (self->priv->filtered_individuals,
163           individual))
164     remove_from_filtered_individuals (self, individual);
165 }
166
167 static void
168 populate_individuals (EmpathyRosterModelAggregator *self)
169 {
170   GeeMap *individuals;
171   GeeMapIterator *iter;
172
173   individuals = folks_individual_aggregator_get_individuals (
174       self->priv->aggregator);
175   iter = gee_map_map_iterator (individuals);
176   while (gee_map_iterator_next (iter))
177     {
178       add_individual (self, gee_map_iterator_get_value (iter));
179     }
180   g_clear_object (&iter);
181 }
182
183 static void
184 aggregator_individuals_changed_cb (FolksIndividualAggregator *aggregator,
185     GeeSet *added,
186     GeeSet *removed,
187     gchar *message,
188     FolksPersona *actor,
189     FolksGroupDetailsChangeReason reason,
190     EmpathyRosterModelAggregator *self)
191 {
192   if (gee_collection_get_size (GEE_COLLECTION (added)) > 0)
193     {
194       GeeIterator *iter = gee_iterable_iterator (GEE_ITERABLE (added));
195
196       while (iter != NULL && gee_iterator_next (iter))
197         {
198           add_individual (self, gee_iterator_get (iter));
199         }
200       g_clear_object (&iter);
201     }
202
203   if (gee_collection_get_size (GEE_COLLECTION (removed)) > 0)
204     {
205       GeeIterator *iter = gee_iterable_iterator (GEE_ITERABLE (removed));
206
207       while (iter != NULL && gee_iterator_next (iter))
208         {
209           remove_individual (self, gee_iterator_get (iter));
210         }
211       g_clear_object (&iter);
212     }
213 }
214
215 static void
216 empathy_roster_model_aggregator_get_property (GObject *object,
217     guint property_id,
218     GValue *value,
219     GParamSpec *pspec)
220 {
221   EmpathyRosterModelAggregator *self = EMPATHY_ROSTER_MODEL_AGGREGATOR (object);
222
223   switch (property_id)
224     {
225       case PROP_AGGREGATOR:
226         g_value_set_object (value, self->priv->aggregator);
227         break;
228       case PROP_FILTER_FUNC:
229         g_value_set_pointer (value, self->priv->filter_func);
230         break;
231       case PROP_FILTER_DATA:
232         g_value_set_pointer (value, self->priv->filter_data);
233         break;
234       default:
235         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
236         break;
237     }
238 }
239
240 static void
241 empathy_roster_model_aggregator_set_property (GObject *object,
242     guint property_id,
243     const GValue *value,
244     GParamSpec *pspec)
245 {
246   EmpathyRosterModelAggregator *self = EMPATHY_ROSTER_MODEL_AGGREGATOR (object);
247
248   switch (property_id)
249     {
250       case PROP_AGGREGATOR:
251         g_assert (self->priv->aggregator == NULL); /* construct only */
252         self->priv->aggregator = g_value_dup_object (value);
253         break;
254       case PROP_FILTER_FUNC:
255         g_assert (self->priv->filter_func == NULL); /* construct only */
256         self->priv->filter_func = g_value_get_pointer (value);
257         break;
258       case PROP_FILTER_DATA:
259         g_assert (self->priv->filter_data == NULL); /* construct only */
260         self->priv->filter_data = g_value_get_pointer (value);
261         break;
262       default:
263         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
264         break;
265     }
266 }
267
268 static void
269 empathy_roster_model_aggregator_constructed (GObject *object)
270 {
271   EmpathyRosterModelAggregator *self = EMPATHY_ROSTER_MODEL_AGGREGATOR (object);
272   void (*chain_up) (GObject *) =
273       ((GObjectClass *) empathy_roster_model_aggregator_parent_class)->constructed;
274
275   if (chain_up != NULL)
276     chain_up (object);
277
278   if (self->priv->aggregator == NULL)
279     self->priv->aggregator = folks_individual_aggregator_dup ();
280
281   g_assert (FOLKS_IS_INDIVIDUAL_AGGREGATOR (self->priv->aggregator));
282
283   tp_g_signal_connect_object (self->priv->aggregator, "individuals-changed",
284       G_CALLBACK (aggregator_individuals_changed_cb), self, 0);
285
286   folks_individual_aggregator_prepare (self->priv->aggregator, NULL, NULL);
287
288   populate_individuals (self);
289 }
290
291 static void
292 empathy_roster_model_aggregator_dispose (GObject *object)
293 {
294   EmpathyRosterModelAggregator *self = EMPATHY_ROSTER_MODEL_AGGREGATOR (object);
295   void (*chain_up) (GObject *) =
296       ((GObjectClass *) empathy_roster_model_aggregator_parent_class)->dispose;
297
298   g_clear_object (&self->priv->aggregator);
299   g_clear_pointer (&self->priv->filtered_individuals, g_hash_table_unref);
300
301   if (chain_up != NULL)
302     chain_up (object);
303 }
304
305 static void
306 empathy_roster_model_aggregator_finalize (GObject *object)
307 {
308   //EmpathyRosterModelAggregator *self = EMPATHY_ROSTER_MODEL_AGGREGATOR (object);
309   void (*chain_up) (GObject *) =
310       ((GObjectClass *) empathy_roster_model_aggregator_parent_class)->finalize;
311
312   if (chain_up != NULL)
313     chain_up (object);
314 }
315
316 static void
317 empathy_roster_model_aggregator_class_init (
318     EmpathyRosterModelAggregatorClass *klass)
319 {
320   GObjectClass *oclass = G_OBJECT_CLASS (klass);
321   GParamSpec *spec;
322
323   oclass->get_property = empathy_roster_model_aggregator_get_property;
324   oclass->set_property = empathy_roster_model_aggregator_set_property;
325   oclass->constructed = empathy_roster_model_aggregator_constructed;
326   oclass->dispose = empathy_roster_model_aggregator_dispose;
327   oclass->finalize = empathy_roster_model_aggregator_finalize;
328
329   spec = g_param_spec_object ("aggregator", "Aggregator",
330       "FolksIndividualAggregator",
331       FOLKS_TYPE_INDIVIDUAL_AGGREGATOR,
332       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
333   g_object_class_install_property (oclass, PROP_AGGREGATOR, spec);
334
335   spec = g_param_spec_pointer ("filter-func", "Filter-Func",
336       "EmpathyRosterModelAggregatorFilterFunc",
337       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
338   g_object_class_install_property (oclass, PROP_FILTER_FUNC, spec);
339
340   spec = g_param_spec_pointer ("filter-data", "Filter-Data",
341       "GPointer",
342       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
343   g_object_class_install_property (oclass, PROP_FILTER_DATA, spec);
344
345   g_type_class_add_private (klass, sizeof (EmpathyRosterModelAggregatorPriv));
346 }
347
348 static void
349 empathy_roster_model_aggregator_init (EmpathyRosterModelAggregator *self)
350 {
351   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
352       EMPATHY_TYPE_ROSTER_MODEL_AGGREGATOR, EmpathyRosterModelAggregatorPriv);
353
354   self->priv->filtered_individuals = g_hash_table_new_full (NULL, NULL, NULL,
355       g_object_unref);
356 }
357
358 EmpathyRosterModelAggregator *
359 empathy_roster_model_aggregator_new (
360     EmpathyRosterModelAggregatorFilterFunc filter_func,
361     gpointer user_data)
362 {
363   return g_object_new (EMPATHY_TYPE_ROSTER_MODEL_AGGREGATOR,
364       "filter-func", filter_func,
365       "filter-data", user_data,
366       NULL);
367 }
368
369 EmpathyRosterModelAggregator *
370 empathy_roster_model_aggregator_new_with_aggregator (
371     FolksIndividualAggregator *aggregator,
372     EmpathyRosterModelAggregatorFilterFunc filter_func,
373     gpointer user_data)
374 {
375   g_return_val_if_fail (FOLKS_IS_INDIVIDUAL_AGGREGATOR (aggregator), NULL);
376
377   return g_object_new (EMPATHY_TYPE_ROSTER_MODEL_AGGREGATOR,
378       "aggregator", aggregator,
379       "filter-func", filter_func,
380       "filter-data", user_data,
381       NULL);
382 }
383
384 static GList *
385 empathy_roster_model_aggregator_get_individuals (EmpathyRosterModel *model)
386 {
387   EmpathyRosterModelAggregator *self = EMPATHY_ROSTER_MODEL_AGGREGATOR (model);
388
389   return g_hash_table_get_values (self->priv->filtered_individuals);
390 }
391
392 static GList *
393 empathy_roster_model_aggregator_dup_groups_for_individual (
394     EmpathyRosterModel *model,
395     FolksIndividual *individual)
396 {
397   GList *groups_list = NULL;
398   GeeSet *groups_set;
399
400   groups_set = folks_group_details_get_groups (
401       FOLKS_GROUP_DETAILS (individual));
402   if (gee_collection_get_size (GEE_COLLECTION (groups_set)) > 0)
403     {
404       GeeIterator *iter = gee_iterable_iterator (GEE_ITERABLE (groups_set));
405
406       while (iter != NULL && gee_iterator_next (iter))
407         {
408           groups_list = g_list_prepend (groups_list, gee_iterator_get (iter));
409         }
410       g_clear_object (&iter);
411     }
412
413   return groups_list;
414 }
415
416 static void
417 roster_model_iface_init (EmpathyRosterModelInterface *iface)
418 {
419   iface->get_individuals = empathy_roster_model_aggregator_get_individuals;
420   iface->dup_groups_for_individual =
421     empathy_roster_model_aggregator_dup_groups_for_individual;
422 }