]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-roster-model-aggregator.c
Updated Kannada translation
[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       FolksIndividual *individual = gee_map_iterator_get_value (iter);
179       add_individual (self, individual);
180       g_object_unref (individual);
181     }
182   g_clear_object (&iter);
183 }
184
185 static void
186 aggregator_individuals_changed_cb (FolksIndividualAggregator *aggregator,
187     GeeSet *added,
188     GeeSet *removed,
189     gchar *message,
190     FolksPersona *actor,
191     FolksGroupDetailsChangeReason reason,
192     EmpathyRosterModelAggregator *self)
193 {
194   if (gee_collection_get_size (GEE_COLLECTION (added)) > 0)
195     {
196       GeeIterator *iter = gee_iterable_iterator (GEE_ITERABLE (added));
197
198       while (iter != NULL && gee_iterator_next (iter))
199         {
200           FolksIndividual *individual = gee_iterator_get (iter);
201           add_individual (self, individual);
202           g_object_unref (individual);
203         }
204       g_clear_object (&iter);
205     }
206
207   if (gee_collection_get_size (GEE_COLLECTION (removed)) > 0)
208     {
209       GeeIterator *iter = gee_iterable_iterator (GEE_ITERABLE (removed));
210
211       while (iter != NULL && gee_iterator_next (iter))
212         {
213           FolksIndividual *individual = gee_iterator_get (iter);
214           remove_individual (self, individual);
215           g_object_unref (individual);
216         }
217       g_clear_object (&iter);
218     }
219 }
220
221 static void
222 empathy_roster_model_aggregator_get_property (GObject *object,
223     guint property_id,
224     GValue *value,
225     GParamSpec *pspec)
226 {
227   EmpathyRosterModelAggregator *self = EMPATHY_ROSTER_MODEL_AGGREGATOR (object);
228
229   switch (property_id)
230     {
231       case PROP_AGGREGATOR:
232         g_value_set_object (value, self->priv->aggregator);
233         break;
234       case PROP_FILTER_FUNC:
235         g_value_set_pointer (value, self->priv->filter_func);
236         break;
237       case PROP_FILTER_DATA:
238         g_value_set_pointer (value, self->priv->filter_data);
239         break;
240       default:
241         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
242         break;
243     }
244 }
245
246 static void
247 empathy_roster_model_aggregator_set_property (GObject *object,
248     guint property_id,
249     const GValue *value,
250     GParamSpec *pspec)
251 {
252   EmpathyRosterModelAggregator *self = EMPATHY_ROSTER_MODEL_AGGREGATOR (object);
253
254   switch (property_id)
255     {
256       case PROP_AGGREGATOR:
257         g_assert (self->priv->aggregator == NULL); /* construct only */
258         self->priv->aggregator = g_value_dup_object (value);
259         break;
260       case PROP_FILTER_FUNC:
261         g_assert (self->priv->filter_func == NULL); /* construct only */
262         self->priv->filter_func = g_value_get_pointer (value);
263         break;
264       case PROP_FILTER_DATA:
265         g_assert (self->priv->filter_data == NULL); /* construct only */
266         self->priv->filter_data = g_value_get_pointer (value);
267         break;
268       default:
269         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
270         break;
271     }
272 }
273
274 static void
275 empathy_roster_model_aggregator_constructed (GObject *object)
276 {
277   EmpathyRosterModelAggregator *self = EMPATHY_ROSTER_MODEL_AGGREGATOR (object);
278   void (*chain_up) (GObject *) =
279       ((GObjectClass *) empathy_roster_model_aggregator_parent_class)->constructed;
280
281   if (chain_up != NULL)
282     chain_up (object);
283
284   if (self->priv->aggregator == NULL)
285     self->priv->aggregator = folks_individual_aggregator_dup ();
286
287   g_assert (FOLKS_IS_INDIVIDUAL_AGGREGATOR (self->priv->aggregator));
288
289   tp_g_signal_connect_object (self->priv->aggregator, "individuals-changed",
290       G_CALLBACK (aggregator_individuals_changed_cb), self, 0);
291
292   folks_individual_aggregator_prepare (self->priv->aggregator, NULL, NULL);
293
294   populate_individuals (self);
295 }
296
297 static void
298 empathy_roster_model_aggregator_dispose (GObject *object)
299 {
300   EmpathyRosterModelAggregator *self = EMPATHY_ROSTER_MODEL_AGGREGATOR (object);
301   void (*chain_up) (GObject *) =
302       ((GObjectClass *) empathy_roster_model_aggregator_parent_class)->dispose;
303
304   g_clear_object (&self->priv->aggregator);
305   g_clear_pointer (&self->priv->filtered_individuals, g_hash_table_unref);
306
307   if (chain_up != NULL)
308     chain_up (object);
309 }
310
311 static void
312 empathy_roster_model_aggregator_finalize (GObject *object)
313 {
314   //EmpathyRosterModelAggregator *self = EMPATHY_ROSTER_MODEL_AGGREGATOR (object);
315   void (*chain_up) (GObject *) =
316       ((GObjectClass *) empathy_roster_model_aggregator_parent_class)->finalize;
317
318   if (chain_up != NULL)
319     chain_up (object);
320 }
321
322 static void
323 empathy_roster_model_aggregator_class_init (
324     EmpathyRosterModelAggregatorClass *klass)
325 {
326   GObjectClass *oclass = G_OBJECT_CLASS (klass);
327   GParamSpec *spec;
328
329   oclass->get_property = empathy_roster_model_aggregator_get_property;
330   oclass->set_property = empathy_roster_model_aggregator_set_property;
331   oclass->constructed = empathy_roster_model_aggregator_constructed;
332   oclass->dispose = empathy_roster_model_aggregator_dispose;
333   oclass->finalize = empathy_roster_model_aggregator_finalize;
334
335   spec = g_param_spec_object ("aggregator", "Aggregator",
336       "FolksIndividualAggregator",
337       FOLKS_TYPE_INDIVIDUAL_AGGREGATOR,
338       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
339   g_object_class_install_property (oclass, PROP_AGGREGATOR, spec);
340
341   spec = g_param_spec_pointer ("filter-func", "Filter-Func",
342       "EmpathyRosterModelAggregatorFilterFunc",
343       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
344   g_object_class_install_property (oclass, PROP_FILTER_FUNC, spec);
345
346   spec = g_param_spec_pointer ("filter-data", "Filter-Data",
347       "GPointer",
348       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
349   g_object_class_install_property (oclass, PROP_FILTER_DATA, spec);
350
351   g_type_class_add_private (klass, sizeof (EmpathyRosterModelAggregatorPriv));
352 }
353
354 static void
355 empathy_roster_model_aggregator_init (EmpathyRosterModelAggregator *self)
356 {
357   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
358       EMPATHY_TYPE_ROSTER_MODEL_AGGREGATOR, EmpathyRosterModelAggregatorPriv);
359
360   self->priv->filtered_individuals = g_hash_table_new_full (NULL, NULL, NULL,
361       g_object_unref);
362 }
363
364 EmpathyRosterModelAggregator *
365 empathy_roster_model_aggregator_new (
366     EmpathyRosterModelAggregatorFilterFunc filter_func,
367     gpointer user_data)
368 {
369   return g_object_new (EMPATHY_TYPE_ROSTER_MODEL_AGGREGATOR,
370       "filter-func", filter_func,
371       "filter-data", user_data,
372       NULL);
373 }
374
375 EmpathyRosterModelAggregator *
376 empathy_roster_model_aggregator_new_with_aggregator (
377     FolksIndividualAggregator *aggregator,
378     EmpathyRosterModelAggregatorFilterFunc filter_func,
379     gpointer user_data)
380 {
381   g_return_val_if_fail (FOLKS_IS_INDIVIDUAL_AGGREGATOR (aggregator), NULL);
382
383   return g_object_new (EMPATHY_TYPE_ROSTER_MODEL_AGGREGATOR,
384       "aggregator", aggregator,
385       "filter-func", filter_func,
386       "filter-data", user_data,
387       NULL);
388 }
389
390 static GList *
391 empathy_roster_model_aggregator_get_individuals (EmpathyRosterModel *model)
392 {
393   EmpathyRosterModelAggregator *self = EMPATHY_ROSTER_MODEL_AGGREGATOR (model);
394
395   return g_hash_table_get_values (self->priv->filtered_individuals);
396 }
397
398 static GList *
399 empathy_roster_model_aggregator_dup_groups_for_individual (
400     EmpathyRosterModel *model,
401     FolksIndividual *individual)
402 {
403   GList *groups_list = NULL;
404   GeeSet *groups_set;
405
406   groups_set = folks_group_details_get_groups (
407       FOLKS_GROUP_DETAILS (individual));
408   if (gee_collection_get_size (GEE_COLLECTION (groups_set)) > 0)
409     {
410       GeeIterator *iter = gee_iterable_iterator (GEE_ITERABLE (groups_set));
411
412       while (iter != NULL && gee_iterator_next (iter))
413         {
414           /* Transfer ownership: */
415           groups_list = g_list_prepend (groups_list, gee_iterator_get (iter));
416         }
417       g_clear_object (&iter);
418     }
419
420   return groups_list;
421 }
422
423 static void
424 roster_model_iface_init (EmpathyRosterModelInterface *iface)
425 {
426   iface->get_individuals = empathy_roster_model_aggregator_get_individuals;
427   iface->dup_groups_for_individual =
428     empathy_roster_model_aggregator_dup_groups_for_individual;
429 }