]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-roster-model-manager.c
Use a flat namespace for internal includes
[empathy.git] / libempathy-gtk / empathy-roster-model-manager.c
1 /*
2  * empathy-roster-model-manager.c
3  *
4  * Implementation of EmpathyRosterModel using EmpathyIndividualManager 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
26 #include "empathy-roster-model-manager.h"
27
28 #include "empathy-roster-model.h"
29
30 #include <glib/gi18n-lib.h>
31
32 #include "empathy-utils.h"
33
34 static void roster_model_iface_init (EmpathyRosterModelInterface *iface);
35
36 G_DEFINE_TYPE_WITH_CODE (EmpathyRosterModelManager,
37     empathy_roster_model_manager,
38     G_TYPE_OBJECT,
39     G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_ROSTER_MODEL, roster_model_iface_init))
40
41 enum
42 {
43   PROP_MANAGER = 1,
44   N_PROPS
45 };
46
47 /*
48 enum
49 {
50   LAST_SIGNAL
51 };
52
53 static guint signals[LAST_SIGNAL];
54 */
55
56 struct _EmpathyRosterModelManagerPriv
57 {
58   EmpathyIndividualManager *manager;
59   /* FolksIndividual (borrowed) */
60   GList *top_group_members;
61 };
62
63 static gboolean
64 is_xmpp_local_contact (FolksIndividual *individual)
65 {
66   EmpathyContact *contact;
67   TpConnection *connection;
68   const gchar *protocol_name = NULL;
69   gboolean result;
70
71   contact = empathy_contact_dup_from_folks_individual (individual);
72
73   if (contact == NULL)
74     return FALSE;
75
76   connection = empathy_contact_get_connection (contact);
77   protocol_name = tp_connection_get_protocol_name (connection);
78   result = !tp_strdiff (protocol_name, "local-xmpp");
79   g_object_unref (contact);
80
81   return result;
82 }
83
84 static gboolean
85 individual_in_top_group_members (EmpathyRosterModelManager *self,
86     FolksIndividual *individual)
87 {
88   return (g_list_find (self->priv->top_group_members, individual) != NULL);
89 }
90
91 static gboolean
92 individual_should_be_in_top_group_members (EmpathyRosterModelManager *self,
93     FolksIndividual *individual)
94 {
95   GList *tops;
96
97   tops = empathy_individual_manager_get_top_individuals (self->priv->manager);
98
99   return (folks_favourite_details_get_is_favourite (
100           FOLKS_FAVOURITE_DETAILS (individual)) ||
101       g_list_find (tops, individual) != NULL);
102 }
103
104 static void
105 add_to_top_group_members (EmpathyRosterModelManager *self,
106     FolksIndividual *individual)
107 {
108   self->priv->top_group_members = g_list_prepend (self->priv->top_group_members,
109       individual);
110 }
111
112 static void
113 remove_from_top_group_members (EmpathyRosterModelManager *self,
114     FolksIndividual *individual)
115 {
116   self->priv->top_group_members = g_list_remove (self->priv->top_group_members,
117       individual);
118 }
119
120 static void
121 populate_model (EmpathyRosterModelManager *self)
122 {
123   GList *individuals, *l;
124
125   individuals = empathy_individual_manager_get_members (self->priv->manager);
126
127   for (l = individuals; l != NULL; l = g_list_next (l))
128     {
129       if (individual_should_be_in_top_group_members (self, l->data))
130         add_to_top_group_members (self, l->data);
131
132       empathy_roster_model_fire_individual_added (EMPATHY_ROSTER_MODEL (self),
133           l->data);
134     }
135 }
136
137 static void
138 members_changed_cb (EmpathyIndividualManager *manager,
139     const gchar *message,
140     GList *added,
141     GList *removed,
142     TpChannelGroupChangeReason reason,
143     EmpathyRosterModelManager *self)
144 {
145   GList *l;
146
147   for (l = added; l != NULL; l = g_list_next (l))
148     {
149       if (individual_should_be_in_top_group_members (self, l->data) &&
150           !individual_in_top_group_members (self, l->data))
151         add_to_top_group_members (self, l->data);
152
153       empathy_roster_model_fire_individual_added (EMPATHY_ROSTER_MODEL (self),
154           l->data);
155     }
156
157   for (l = removed; l != NULL; l = g_list_next (l))
158     {
159       if (individual_in_top_group_members (self, l->data))
160         remove_from_top_group_members (self, l->data);
161
162       empathy_roster_model_fire_individual_removed (EMPATHY_ROSTER_MODEL (self),
163           l->data);
164     }
165 }
166
167 static void
168 groups_changed_cb (EmpathyIndividualManager *manager,
169     FolksIndividual *individual,
170     const gchar *group,
171     gboolean is_member,
172     EmpathyRosterModelManager *self)
173 {
174   empathy_roster_model_fire_groups_changed (EMPATHY_ROSTER_MODEL (self),
175       individual, group, is_member);
176 }
177
178 static void
179 top_individuals_changed_cb (EmpathyIndividualManager *manager,
180     GParamSpec *spec,
181     EmpathyRosterModelManager *self)
182 {
183   GList *tops, *l;
184
185   tops = empathy_individual_manager_get_top_individuals (self->priv->manager);
186
187   for (l = tops; l != NULL; l = g_list_next (l))
188     {
189       if (!individual_in_top_group_members (self, l->data))
190         {
191           add_to_top_group_members (self, l->data);
192
193           empathy_roster_model_fire_groups_changed (
194               EMPATHY_ROSTER_MODEL (self), l->data,
195               EMPATHY_ROSTER_MODEL_GROUP_TOP_GROUP, TRUE);
196         }
197     }
198
199   l = self->priv->top_group_members;
200   while (l != NULL)
201     {
202       FolksIndividual *individual = l->data;
203
204       /* remove_from_top_group_members will modify the list so we already take
205        * the next pointer. */
206       l = g_list_next (l);
207
208       if (!individual_should_be_in_top_group_members (self, individual))
209         {
210           remove_from_top_group_members (self, individual);
211
212           empathy_roster_model_fire_groups_changed (EMPATHY_ROSTER_MODEL (self),
213               individual, EMPATHY_ROSTER_MODEL_GROUP_TOP_GROUP, FALSE);
214         }
215     }
216 }
217
218 static void
219 favourites_changed_cb (EmpathyIndividualManager *manager,
220     FolksIndividual *individual,
221     gboolean favourite,
222     EmpathyRosterModelManager *self)
223 {
224   if (favourite && !individual_in_top_group_members (self, individual))
225     {
226       add_to_top_group_members (self, individual);
227
228       empathy_roster_model_fire_groups_changed (
229           EMPATHY_ROSTER_MODEL (self), individual,
230           EMPATHY_ROSTER_MODEL_GROUP_TOP_GROUP, favourite);
231     }
232   else if (!favourite &&
233       !individual_should_be_in_top_group_members (self, individual))
234     {
235       remove_from_top_group_members (self, individual);
236
237       empathy_roster_model_fire_groups_changed (
238           EMPATHY_ROSTER_MODEL (self), individual,
239           EMPATHY_ROSTER_MODEL_GROUP_TOP_GROUP, favourite);
240     }
241 }
242
243 static void
244 empathy_roster_model_manager_get_property (GObject *object,
245     guint property_id,
246     GValue *value,
247     GParamSpec *pspec)
248 {
249   EmpathyRosterModelManager *self = EMPATHY_ROSTER_MODEL_MANAGER (object);
250
251   switch (property_id)
252     {
253       case PROP_MANAGER:
254         g_value_set_object (value, self->priv->manager);
255         break;
256       default:
257         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
258         break;
259     }
260 }
261
262 static void
263 empathy_roster_model_manager_set_property (GObject *object,
264     guint property_id,
265     const GValue *value,
266     GParamSpec *pspec)
267 {
268   EmpathyRosterModelManager *self = EMPATHY_ROSTER_MODEL_MANAGER (object);
269
270   switch (property_id)
271     {
272       case PROP_MANAGER:
273         g_assert (self->priv->manager == NULL); /* construct only */
274         self->priv->manager = g_value_dup_object (value);
275         break;
276       default:
277         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
278         break;
279     }
280 }
281
282 static void
283 empathy_roster_model_manager_constructed (GObject *object)
284 {
285   EmpathyRosterModelManager *self = EMPATHY_ROSTER_MODEL_MANAGER (object);
286   void (*chain_up) (GObject *) =
287       ((GObjectClass *) empathy_roster_model_manager_parent_class)->constructed;
288
289   if (chain_up != NULL)
290     chain_up (object);
291
292   g_assert (EMPATHY_IS_INDIVIDUAL_MANAGER (self->priv->manager));
293
294   populate_model (self);
295
296   tp_g_signal_connect_object (self->priv->manager, "members-changed",
297       G_CALLBACK (members_changed_cb), self, 0);
298   tp_g_signal_connect_object (self->priv->manager, "groups-changed",
299       G_CALLBACK (groups_changed_cb), self, 0);
300   tp_g_signal_connect_object (self->priv->manager, "notify::top-individuals",
301       G_CALLBACK (top_individuals_changed_cb), self, 0);
302   tp_g_signal_connect_object (self->priv->manager, "favourites-changed",
303       G_CALLBACK (favourites_changed_cb), self, 0);
304 }
305
306 static void
307 empathy_roster_model_manager_dispose (GObject *object)
308 {
309   EmpathyRosterModelManager *self = EMPATHY_ROSTER_MODEL_MANAGER (object);
310   void (*chain_up) (GObject *) =
311       ((GObjectClass *) empathy_roster_model_manager_parent_class)->dispose;
312
313   g_clear_object (&self->priv->manager);
314
315   if (chain_up != NULL)
316     chain_up (object);
317 }
318
319 static void
320 empathy_roster_model_manager_finalize (GObject *object)
321 {
322   EmpathyRosterModelManager *self = EMPATHY_ROSTER_MODEL_MANAGER (object);
323   void (*chain_up) (GObject *) =
324       ((GObjectClass *) empathy_roster_model_manager_parent_class)->finalize;
325
326   g_list_free (self->priv->top_group_members);
327
328   if (chain_up != NULL)
329     chain_up (object);
330 }
331
332 static void
333 empathy_roster_model_manager_class_init (
334     EmpathyRosterModelManagerClass *klass)
335 {
336   GObjectClass *oclass = G_OBJECT_CLASS (klass);
337   GParamSpec *spec;
338
339   oclass->get_property = empathy_roster_model_manager_get_property;
340   oclass->set_property = empathy_roster_model_manager_set_property;
341   oclass->constructed = empathy_roster_model_manager_constructed;
342   oclass->dispose = empathy_roster_model_manager_dispose;
343   oclass->finalize = empathy_roster_model_manager_finalize;
344
345   spec = g_param_spec_object ("manager", "Manager",
346       "EmpathyIndividualManager",
347       EMPATHY_TYPE_INDIVIDUAL_MANAGER,
348       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
349   g_object_class_install_property (oclass, PROP_MANAGER, spec);
350
351   g_type_class_add_private (klass, sizeof (EmpathyRosterModelManagerPriv));
352 }
353
354 static void
355 empathy_roster_model_manager_init (EmpathyRosterModelManager *self)
356 {
357   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
358       EMPATHY_TYPE_ROSTER_MODEL_MANAGER, EmpathyRosterModelManagerPriv);
359
360   self->priv->top_group_members = NULL;
361 }
362
363 EmpathyRosterModelManager *
364 empathy_roster_model_manager_new (EmpathyIndividualManager *manager)
365 {
366   g_return_val_if_fail (EMPATHY_IS_INDIVIDUAL_MANAGER (manager), NULL);
367
368   return g_object_new (EMPATHY_TYPE_ROSTER_MODEL_MANAGER,
369       "manager", manager,
370       NULL);
371 }
372
373 static GList *
374 empathy_roster_model_manager_get_individuals (EmpathyRosterModel *model)
375 {
376   EmpathyRosterModelManager *self = EMPATHY_ROSTER_MODEL_MANAGER (model);
377
378   return empathy_individual_manager_get_members (self->priv->manager);
379 }
380
381 static GList *
382 empathy_roster_model_manager_dup_groups_for_individual (
383     EmpathyRosterModel *model,
384     FolksIndividual *individual)
385 {
386   GList *groups_list = NULL;
387   GeeSet *groups_set;
388
389   if (is_xmpp_local_contact (individual))
390     {
391       groups_list = g_list_prepend (groups_list,
392           g_strdup (EMPATHY_ROSTER_MODEL_GROUP_PEOPLE_NEARBY));
393       return groups_list;
394     }
395
396   if (individual_in_top_group_members (EMPATHY_ROSTER_MODEL_MANAGER (model),
397           individual))
398     groups_list = g_list_prepend (groups_list,
399         g_strdup (EMPATHY_ROSTER_MODEL_GROUP_TOP_GROUP));
400
401   groups_set = folks_group_details_get_groups (
402       FOLKS_GROUP_DETAILS (individual));
403   if (gee_collection_get_size (GEE_COLLECTION (groups_set)) > 0)
404     {
405       GeeIterator *iter = gee_iterable_iterator (GEE_ITERABLE (groups_set));
406
407       while (iter != NULL && gee_iterator_next (iter))
408         {
409           groups_list = g_list_prepend (groups_list, gee_iterator_get (iter));
410         }
411       g_clear_object (&iter);
412     }
413
414   return groups_list;
415 }
416
417 static void
418 roster_model_iface_init (EmpathyRosterModelInterface *iface)
419 {
420   iface->get_individuals = empathy_roster_model_manager_get_individuals;
421   iface->dup_groups_for_individual =
422     empathy_roster_model_manager_dup_groups_for_individual;
423 }