]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-roster-model-manager.c
Removed now useless _get_top_individuals function in the model
[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 <libempathy/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 populate_model (EmpathyRosterModelManager *self)
106 {
107   GList *individuals, *l;
108
109   individuals = empathy_individual_manager_get_members (self->priv->manager);
110
111   for (l = individuals; l != NULL; l = g_list_next (l))
112     {
113       if (individual_should_be_in_top_group_members (self, l->data))
114         self->priv->top_group_members = g_list_prepend (
115             self->priv->top_group_members, l->data);
116
117       empathy_roster_model_fire_individual_added (EMPATHY_ROSTER_MODEL (self),
118           l->data);
119     }
120 }
121
122 static void
123 members_changed_cb (EmpathyIndividualManager *manager,
124     const gchar *message,
125     GList *added,
126     GList *removed,
127     TpChannelGroupChangeReason reason,
128     EmpathyRosterModelManager *self)
129 {
130   GList *l;
131
132   for (l = added; l != NULL; l = g_list_next (l))
133     {
134       if (individual_should_be_in_top_group_members (self, l->data) &&
135           !individual_in_top_group_members (self, l->data))
136         self->priv->top_group_members = g_list_prepend (
137             self->priv->top_group_members, l->data);
138
139       empathy_roster_model_fire_individual_added (EMPATHY_ROSTER_MODEL (self),
140           l->data);
141     }
142
143   for (l = removed; l != NULL; l = g_list_next (l))
144     {
145       if (individual_in_top_group_members (self, l->data) &&
146           !individual_should_be_in_top_group_members (self, l->data))
147         self->priv->top_group_members = g_list_remove (
148             self->priv->top_group_members, l->data);
149
150       empathy_roster_model_fire_individual_removed (EMPATHY_ROSTER_MODEL (self),
151           l->data);
152     }
153 }
154
155 static void
156 groups_changed_cb (EmpathyIndividualManager *manager,
157     FolksIndividual *individual,
158     const gchar *group,
159     gboolean is_member,
160     EmpathyRosterModelManager *self)
161 {
162   empathy_roster_model_fire_groups_changed (EMPATHY_ROSTER_MODEL (self),
163       individual, group, is_member);
164 }
165
166 static void
167 top_individuals_changed_cb (EmpathyIndividualManager *manager,
168     GParamSpec *spec,
169     EmpathyRosterModelManager *self)
170 {
171   GList *tops, *l;
172
173   tops = empathy_individual_manager_get_top_individuals (self->priv->manager);
174
175   for (l = tops; l != NULL; l = g_list_next (l))
176     {
177       if (!individual_in_top_group_members (self, l->data))
178         {
179           self->priv->top_group_members = g_list_prepend (
180               self->priv->top_group_members, l->data);
181
182           empathy_roster_model_fire_groups_changed (
183               EMPATHY_ROSTER_MODEL (self), l->data,
184               EMPATHY_ROSTER_MODEL_GROUP_TOP_GROUP, TRUE);
185         }
186     }
187   for (l = self->priv->top_group_members; l != NULL; l = g_list_next (l))
188     {
189       if (!individual_should_be_in_top_group_members (self, l->data))
190         {
191           self->priv->top_group_members = g_list_remove (
192               self->priv->top_group_members, l->data);
193
194           empathy_roster_model_fire_groups_changed (
195               EMPATHY_ROSTER_MODEL (self), l->data,
196               EMPATHY_ROSTER_MODEL_GROUP_TOP_GROUP, FALSE);
197         }
198     }
199 }
200
201 static void
202 favourites_changed_cb (EmpathyIndividualManager *manager,
203     FolksIndividual *individual,
204     gboolean favourite,
205     EmpathyRosterModelManager *self)
206 {
207   if (favourite && !individual_in_top_group_members (self, individual))
208     {
209       self->priv->top_group_members = g_list_prepend (
210           self->priv->top_group_members, individual);
211
212       empathy_roster_model_fire_groups_changed (
213           EMPATHY_ROSTER_MODEL (self), individual,
214           EMPATHY_ROSTER_MODEL_GROUP_TOP_GROUP, favourite);
215     }
216   else if (!favourite &&
217       !individual_should_be_in_top_group_members (self, individual))
218     {
219       self->priv->top_group_members = g_list_remove (
220           self->priv->top_group_members, individual);
221
222       empathy_roster_model_fire_groups_changed (
223           EMPATHY_ROSTER_MODEL (self), individual,
224           EMPATHY_ROSTER_MODEL_GROUP_TOP_GROUP, favourite);
225     }
226 }
227
228 static void
229 empathy_roster_model_manager_get_property (GObject *object,
230     guint property_id,
231     GValue *value,
232     GParamSpec *pspec)
233 {
234   EmpathyRosterModelManager *self = EMPATHY_ROSTER_MODEL_MANAGER (object);
235
236   switch (property_id)
237     {
238       case PROP_MANAGER:
239         g_value_set_object (value, self->priv->manager);
240         break;
241       default:
242         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
243         break;
244     }
245 }
246
247 static void
248 empathy_roster_model_manager_set_property (GObject *object,
249     guint property_id,
250     const GValue *value,
251     GParamSpec *pspec)
252 {
253   EmpathyRosterModelManager *self = EMPATHY_ROSTER_MODEL_MANAGER (object);
254
255   switch (property_id)
256     {
257       case PROP_MANAGER:
258         g_assert (self->priv->manager == NULL); /* construct only */
259         self->priv->manager = g_value_dup_object (value);
260         break;
261       default:
262         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
263         break;
264     }
265 }
266
267 static void
268 empathy_roster_model_manager_constructed (GObject *object)
269 {
270   EmpathyRosterModelManager *self = EMPATHY_ROSTER_MODEL_MANAGER (object);
271   void (*chain_up) (GObject *) =
272       ((GObjectClass *) empathy_roster_model_manager_parent_class)->constructed;
273
274   if (chain_up != NULL)
275     chain_up (object);
276
277   g_assert (EMPATHY_IS_INDIVIDUAL_MANAGER (self->priv->manager));
278
279   populate_model (self);
280
281   tp_g_signal_connect_object (self->priv->manager, "members-changed",
282       G_CALLBACK (members_changed_cb), self, 0);
283   tp_g_signal_connect_object (self->priv->manager, "groups-changed",
284       G_CALLBACK (groups_changed_cb), self, 0);
285   tp_g_signal_connect_object (self->priv->manager, "notify::top-individuals",
286       G_CALLBACK (top_individuals_changed_cb), self, 0);
287   tp_g_signal_connect_object (self->priv->manager, "notify::favourites-changed",
288       G_CALLBACK (favourites_changed_cb), self, 0);
289 }
290
291 static void
292 empathy_roster_model_manager_dispose (GObject *object)
293 {
294   EmpathyRosterModelManager *self = EMPATHY_ROSTER_MODEL_MANAGER (object);
295   void (*chain_up) (GObject *) =
296       ((GObjectClass *) empathy_roster_model_manager_parent_class)->dispose;
297
298   g_clear_object (&self->priv->manager);
299
300   if (chain_up != NULL)
301     chain_up (object);
302 }
303
304 static void
305 empathy_roster_model_manager_finalize (GObject *object)
306 {
307   EmpathyRosterModelManager *self = EMPATHY_ROSTER_MODEL_MANAGER (object);
308   void (*chain_up) (GObject *) =
309       ((GObjectClass *) empathy_roster_model_manager_parent_class)->finalize;
310
311   g_list_free (self->priv->top_group_members);
312
313   if (chain_up != NULL)
314     chain_up (object);
315 }
316
317 static void
318 empathy_roster_model_manager_class_init (
319     EmpathyRosterModelManagerClass *klass)
320 {
321   GObjectClass *oclass = G_OBJECT_CLASS (klass);
322   GParamSpec *spec;
323
324   oclass->get_property = empathy_roster_model_manager_get_property;
325   oclass->set_property = empathy_roster_model_manager_set_property;
326   oclass->constructed = empathy_roster_model_manager_constructed;
327   oclass->dispose = empathy_roster_model_manager_dispose;
328   oclass->finalize = empathy_roster_model_manager_finalize;
329
330   spec = g_param_spec_object ("manager", "Manager",
331       "EmpathyIndividualManager",
332       EMPATHY_TYPE_INDIVIDUAL_MANAGER,
333       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
334   g_object_class_install_property (oclass, PROP_MANAGER, spec);
335
336   g_type_class_add_private (klass, sizeof (EmpathyRosterModelManagerPriv));
337 }
338
339 static void
340 empathy_roster_model_manager_init (EmpathyRosterModelManager *self)
341 {
342   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
343       EMPATHY_TYPE_ROSTER_MODEL_MANAGER, EmpathyRosterModelManagerPriv);
344
345   self->priv->top_group_members = NULL;
346 }
347
348 EmpathyRosterModelManager *
349 empathy_roster_model_manager_new (EmpathyIndividualManager *manager)
350 {
351   g_return_val_if_fail (EMPATHY_IS_INDIVIDUAL_MANAGER (manager), NULL);
352
353   return g_object_new (EMPATHY_TYPE_ROSTER_MODEL_MANAGER,
354       "manager", manager,
355       NULL);
356 }
357
358 static GList *
359 empathy_roster_model_manager_get_individuals (EmpathyRosterModel *model)
360 {
361   EmpathyRosterModelManager *self = EMPATHY_ROSTER_MODEL_MANAGER (model);
362
363   return empathy_individual_manager_get_members (self->priv->manager);
364 }
365
366 static GList *
367 empathy_roster_model_manager_get_groups_for_individual (
368     EmpathyRosterModel *model,
369     FolksIndividual *individual)
370 {
371   GList *groups_list = NULL;
372   GeeSet *groups_set;
373
374   if (is_xmpp_local_contact (individual))
375     {
376       groups_list = g_list_prepend (groups_list,
377           EMPATHY_ROSTER_MODEL_GROUP_PEOPLE_NEARBY);
378       return groups_list;
379     }
380
381   if (individual_in_top_group_members (EMPATHY_ROSTER_MODEL_MANAGER (model),
382           individual))
383     groups_list = g_list_prepend (groups_list,
384         EMPATHY_ROSTER_MODEL_GROUP_TOP_GROUP);
385
386   groups_set = folks_group_details_get_groups (
387       FOLKS_GROUP_DETAILS (individual));
388   if (gee_collection_get_size (GEE_COLLECTION (groups_set)) > 0)
389     {
390       GeeIterator *iter = gee_iterable_iterator (GEE_ITERABLE (groups_set));
391
392       while (iter != NULL && gee_iterator_next (iter))
393         {
394           groups_list = g_list_prepend (groups_list, gee_iterator_get (iter));
395         }
396       g_clear_object (&iter);
397     }
398
399   return groups_list;
400 }
401
402 static void
403 roster_model_iface_init (EmpathyRosterModelInterface *iface)
404 {
405   iface->get_individuals = empathy_roster_model_manager_get_individuals;
406   iface->get_groups_for_individual =
407     empathy_roster_model_manager_get_groups_for_individual;
408 }