2 * Copyright (C) 2005-2007 Imendio AB
3 * Copyright (C) 2007-2008, 2010 Collabora Ltd.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301 USA
20 * Authors: Mikael Hallendal <micke@imendio.com>
21 * Martyn Russell <martyn@imendio.com>
22 * Xavier Claessens <xclaesse@gmail.com>
23 * Philip Withnall <philip.withnall@collabora.co.uk>
25 * Based off EmpathyContactListStore.
33 #include <glib/gi18n-lib.h>
36 #include <telepathy-glib/util.h>
38 #include <folks/folks.h>
39 #include <folks/folks-telepathy.h>
41 #include <libempathy/empathy-utils.h>
43 #include "empathy-persona-store.h"
44 #include "empathy-gtk-enum-types.h"
45 #include "empathy-ui-utils.h"
47 #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT
48 #include <libempathy/empathy-debug.h>
50 /* Active users are those which have recently changed state
51 * (e.g. online, offline or from normal to a busy state). */
53 /* Time in seconds user is shown as active */
54 #define ACTIVE_USER_SHOW_TIME 7
56 /* Time in seconds after connecting which we wait before active users are
58 #define ACTIVE_USER_WAIT_TO_ENABLE_TIME 5
60 static void add_persona (EmpathyPersonaStore
*self
,
61 FolksPersona
*persona
);
62 static GtkTreePath
* find_persona (EmpathyPersonaStore
*self
,
63 FolksPersona
*persona
);
64 static void update_persona (EmpathyPersonaStore
*self
,
65 FolksPersona
*persona
);
66 static void remove_persona (EmpathyPersonaStore
*self
,
67 FolksPersona
*persona
);
69 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyPersonaStore)
73 FolksIndividual
*individual
; /* owned */
74 GHashTable
*personas
; /* owned Persona -> owned GtkTreeRowReference */
76 gboolean show_avatars
;
77 gboolean show_protocols
;
79 EmpathyPersonaStoreSort sort_criterion
;
84 GHashTable
*status_icons
; /* owned icon name -> owned GdkPixbuf */
85 } EmpathyPersonaStorePriv
;
95 G_DEFINE_TYPE (EmpathyPersonaStore
, empathy_persona_store
, GTK_TYPE_LIST_STORE
);
98 inhibit_active_cb (EmpathyPersonaStore
*store
)
100 EmpathyPersonaStorePriv
*priv
;
102 priv
= GET_PRIV (store
);
104 priv
->show_active
= TRUE
;
105 priv
->inhibit_active
= 0;
111 EmpathyPersonaStore
*store
;
112 FolksPersona
*persona
;
117 static void persona_active_free (ShowActiveData
*data
);
120 persona_active_invalidated (ShowActiveData
*data
,
123 /* Remove the timeout and free the struct, since the persona or persona
124 * store has disappeared. */
125 g_source_remove (data
->timeout
);
127 if (old_object
== (GObject
*) data
->store
)
129 else if (old_object
== (GObject
*) data
->persona
)
130 data
->persona
= NULL
;
132 g_assert_not_reached ();
134 persona_active_free (data
);
137 static ShowActiveData
*
138 persona_active_new (EmpathyPersonaStore
*self
,
139 FolksPersona
*persona
,
142 ShowActiveData
*data
;
144 DEBUG ("Contact:'%s' now active, and %s be removed",
145 folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (persona
)),
146 remove_
? "WILL" : "WILL NOT");
148 data
= g_slice_new0 (ShowActiveData
);
150 /* We don't actually want to force either the PersonaStore or the
151 * Persona to stay alive, since the user could quit Empathy or disable
152 * the account before the persona_active timeout is fired. */
153 g_object_weak_ref (G_OBJECT (self
),
154 (GWeakNotify
) persona_active_invalidated
, data
);
155 g_object_weak_ref (G_OBJECT (persona
),
156 (GWeakNotify
) persona_active_invalidated
, data
);
159 data
->persona
= persona
;
160 data
->remove
= remove_
;
166 persona_active_free (ShowActiveData
*data
)
168 if (data
->store
!= NULL
)
170 g_object_weak_unref (G_OBJECT (data
->store
),
171 (GWeakNotify
) persona_active_invalidated
, data
);
174 if (data
->persona
!= NULL
)
176 g_object_weak_unref (G_OBJECT (data
->persona
),
177 (GWeakNotify
) persona_active_invalidated
, data
);
180 g_slice_free (ShowActiveData
, data
);
184 persona_set_active (EmpathyPersonaStore
*self
,
185 FolksPersona
*persona
,
187 gboolean set_changed
)
192 path
= find_persona (self
, persona
);
196 gtk_tree_model_get_iter (GTK_TREE_MODEL (self
), &iter
, path
);
197 gtk_list_store_set (GTK_LIST_STORE (self
), &iter
,
198 EMPATHY_PERSONA_STORE_COL_IS_ACTIVE
, active
,
201 DEBUG ("Set item %s", active
? "active" : "inactive");
204 gtk_tree_model_row_changed (GTK_TREE_MODEL (self
), path
, &iter
);
206 gtk_tree_path_free (path
);
210 persona_active_cb (ShowActiveData
*data
)
213 folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (data
->persona
));
217 DEBUG ("Contact:'%s' active timeout, removing item", alias
);
218 remove_persona (data
->store
, data
->persona
);
221 DEBUG ("Contact:'%s' no longer active", alias
);
222 persona_set_active (data
->store
, data
->persona
, FALSE
, TRUE
);
224 persona_active_free (data
);
230 persona_updated_cb (FolksPersona
*persona
,
232 EmpathyPersonaStore
*self
)
234 DEBUG ("Contact:'%s' updated, checking roster is in sync...",
235 folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (persona
)));
237 update_persona (self
, persona
);
241 add_persona_and_connect (EmpathyPersonaStore
*self
,
242 FolksPersona
*persona
)
244 /* We don't want any non-Telepathy personas */
245 if (!TPF_IS_PERSONA (persona
))
248 g_signal_connect (persona
, "notify::presence",
249 (GCallback
) persona_updated_cb
, self
);
250 g_signal_connect (persona
, "notify::presence-message",
251 (GCallback
) persona_updated_cb
, self
);
252 g_signal_connect (persona
, "notify::alias",
253 (GCallback
) persona_updated_cb
, self
);
254 g_signal_connect (persona
, "notify::avatar",
255 (GCallback
) persona_updated_cb
, self
);
257 add_persona (self
, persona
);
261 remove_persona_and_disconnect (EmpathyPersonaStore
*self
,
262 FolksPersona
*persona
)
264 if (!TPF_IS_PERSONA (persona
))
267 g_signal_handlers_disconnect_by_func (persona
,
268 (GCallback
) persona_updated_cb
, self
);
270 remove_persona (self
, persona
);
274 add_persona (EmpathyPersonaStore
*self
,
275 FolksPersona
*persona
)
277 EmpathyPersonaStorePriv
*priv
;
280 FolksPersonaStore
*store
;
281 EmpathyContact
*contact
;
284 if (!TPF_IS_PERSONA (persona
))
287 priv
= GET_PRIV (self
);
289 alias
= folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (persona
));
290 if (EMP_STR_EMPTY (alias
))
293 contact
= empathy_contact_dup_from_tp_contact (tpf_persona_get_contact (
294 TPF_PERSONA (persona
)));
295 store
= folks_persona_get_store (persona
);
297 gtk_list_store_insert_with_values (GTK_LIST_STORE (self
), &iter
, 0,
298 EMPATHY_PERSONA_STORE_COL_NAME
, alias
,
299 EMPATHY_PERSONA_STORE_COL_ACCOUNT_NAME
,
300 folks_persona_store_get_display_name (store
),
301 EMPATHY_PERSONA_STORE_COL_DISPLAY_ID
,
302 folks_persona_get_display_id (persona
),
303 EMPATHY_PERSONA_STORE_COL_PERSONA
, persona
,
304 EMPATHY_PERSONA_STORE_COL_CAN_AUDIO_CALL
,
305 empathy_contact_get_capabilities (contact
) &
306 EMPATHY_CAPABILITIES_AUDIO
,
307 EMPATHY_PERSONA_STORE_COL_CAN_VIDEO_CALL
,
308 empathy_contact_get_capabilities (contact
) &
309 EMPATHY_CAPABILITIES_VIDEO
,
312 g_object_unref (contact
);
314 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (self
), &iter
);
315 g_hash_table_replace (priv
->personas
, g_object_ref (persona
),
316 gtk_tree_row_reference_new (GTK_TREE_MODEL (self
), path
));
317 gtk_tree_path_free (path
);
319 update_persona (self
, persona
);
323 remove_persona (EmpathyPersonaStore
*self
,
324 FolksPersona
*persona
)
326 EmpathyPersonaStorePriv
*priv
;
330 if (!TPF_IS_PERSONA (persona
))
333 priv
= GET_PRIV (self
);
335 path
= find_persona (self
, persona
);
339 g_hash_table_remove (priv
->personas
, persona
);
341 gtk_tree_model_get_iter (GTK_TREE_MODEL (self
), &iter
, path
);
342 gtk_list_store_remove (GTK_LIST_STORE (self
), &iter
);
343 gtk_tree_path_free (path
);
347 get_persona_status_icon (EmpathyPersonaStore
*self
,
348 FolksPersona
*persona
)
350 EmpathyPersonaStorePriv
*priv
= GET_PRIV (self
);
351 EmpathyContact
*contact
;
352 const gchar
*protocol_name
= NULL
;
353 gchar
*icon_name
= NULL
;
354 GdkPixbuf
*pixbuf_status
= NULL
;
355 const gchar
*status_icon_name
= NULL
;
357 contact
= empathy_contact_dup_from_tp_contact (tpf_persona_get_contact (
358 TPF_PERSONA (persona
)));
360 status_icon_name
= empathy_icon_name_for_contact (contact
);
361 if (status_icon_name
== NULL
)
363 g_object_unref (contact
);
367 if (priv
->show_protocols
)
369 protocol_name
= empathy_protocol_name_for_contact (contact
);
370 icon_name
= g_strdup_printf ("%s-%s", status_icon_name
, protocol_name
);
374 icon_name
= g_strdup_printf ("%s", status_icon_name
);
377 pixbuf_status
= g_hash_table_lookup (priv
->status_icons
, icon_name
);
379 if (pixbuf_status
== NULL
)
381 pixbuf_status
= empathy_pixbuf_contact_status_icon_with_icon_name (
382 contact
, status_icon_name
, priv
->show_protocols
);
384 if (pixbuf_status
!= NULL
)
386 g_hash_table_insert (priv
->status_icons
, g_strdup (icon_name
),
391 g_object_unref (contact
);
394 return pixbuf_status
;
398 update_persona (EmpathyPersonaStore
*self
,
399 FolksPersona
*persona
)
401 EmpathyPersonaStorePriv
*priv
= GET_PRIV (self
);
403 gboolean do_set_active
= FALSE
;
404 gboolean do_set_refresh
= FALSE
;
407 path
= find_persona (self
, persona
);
408 alias
= folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (persona
));
412 DEBUG ("Contact:'%s' in list:NO, should be:YES", alias
);
414 add_persona (self
, persona
);
416 if (priv
->show_active
)
418 do_set_active
= TRUE
;
419 DEBUG ("Set active (contact added)");
424 FolksPersonaStore
*store
;
425 EmpathyContact
*contact
;
427 GdkPixbuf
*pixbuf_avatar
;
428 GdkPixbuf
*pixbuf_status
;
429 gboolean now_online
= FALSE
;
430 gboolean was_online
= TRUE
;
432 DEBUG ("Contact:'%s' in list:YES, should be:YES", alias
);
434 gtk_tree_model_get_iter (GTK_TREE_MODEL (self
), &iter
, path
);
435 gtk_tree_path_free (path
);
437 /* Get online state now. */
438 now_online
= folks_presence_details_is_online (
439 FOLKS_PRESENCE_DETAILS (persona
));
441 /* Get online state before. */
442 gtk_tree_model_get (GTK_TREE_MODEL (self
), &iter
,
443 EMPATHY_PERSONA_STORE_COL_IS_ONLINE
, &was_online
,
446 /* Is this really an update or an online/offline. */
447 if (priv
->show_active
)
449 if (was_online
!= now_online
)
451 do_set_active
= TRUE
;
452 do_set_refresh
= TRUE
;
454 DEBUG ("Set active (contact updated %s)",
455 was_online
? "online -> offline" : "offline -> online");
459 /* Was TRUE for presence updates. */
460 /* do_set_active = FALSE; */
461 do_set_refresh
= TRUE
;
462 DEBUG ("Set active (contact updated)");
466 /* We still need to use EmpathyContact for the capabilities stuff */
467 contact
= empathy_contact_dup_from_tp_contact (tpf_persona_get_contact (
468 TPF_PERSONA (persona
)));
469 store
= folks_persona_get_store (persona
);
471 pixbuf_avatar
= empathy_pixbuf_avatar_from_contact_scaled (contact
,
473 pixbuf_status
= get_persona_status_icon (self
, persona
);
475 gtk_list_store_set (GTK_LIST_STORE (self
), &iter
,
476 EMPATHY_PERSONA_STORE_COL_ICON_STATUS
, pixbuf_status
,
477 EMPATHY_PERSONA_STORE_COL_PIXBUF_AVATAR
, pixbuf_avatar
,
478 EMPATHY_PERSONA_STORE_COL_PIXBUF_AVATAR_VISIBLE
, priv
->show_avatars
,
479 EMPATHY_PERSONA_STORE_COL_NAME
, alias
,
480 EMPATHY_PERSONA_STORE_COL_ACCOUNT_NAME
,
481 folks_persona_store_get_display_name (store
),
482 EMPATHY_PERSONA_STORE_COL_DISPLAY_ID
,
483 folks_persona_get_display_id (persona
),
484 EMPATHY_PERSONA_STORE_COL_PRESENCE_TYPE
,
485 folks_presence_details_get_presence_type (
486 FOLKS_PRESENCE_DETAILS (persona
)),
487 EMPATHY_PERSONA_STORE_COL_STATUS
,
488 folks_presence_details_get_presence_message (
489 FOLKS_PRESENCE_DETAILS (persona
)),
490 EMPATHY_PERSONA_STORE_COL_IS_ONLINE
, now_online
,
491 EMPATHY_PERSONA_STORE_COL_CAN_AUDIO_CALL
,
492 empathy_contact_get_capabilities (contact
) &
493 EMPATHY_CAPABILITIES_AUDIO
,
494 EMPATHY_PERSONA_STORE_COL_CAN_VIDEO_CALL
,
495 empathy_contact_get_capabilities (contact
) &
496 EMPATHY_CAPABILITIES_VIDEO
,
499 g_object_unref (contact
);
502 g_object_unref (pixbuf_avatar
);
505 if (priv
->show_active
&& do_set_active
)
507 persona_set_active (self
, persona
, do_set_active
, do_set_refresh
);
511 ShowActiveData
*data
;
513 data
= persona_active_new (self
, persona
, FALSE
);
514 data
->timeout
= g_timeout_add_seconds (ACTIVE_USER_SHOW_TIME
,
515 (GSourceFunc
) persona_active_cb
,
520 /* FIXME: when someone goes online then offline quickly, the
521 * first timeout sets the user to be inactive and the second
522 * timeout removes the user from the contact list, really we
523 * should remove the first timeout.
528 individual_personas_changed_cb (GObject
*object
,
531 EmpathyPersonaStore
*self
)
535 /* One of the personas' row references might hold the last reference to the
536 * PersonaStore, so we need to keep a reference ourselves so we don't get
540 /* Remove the old personas. */
541 iter
= gee_iterable_iterator (GEE_ITERABLE (removed
));
542 while (gee_iterator_next (iter
))
544 FolksPersona
*persona
= gee_iterator_get (iter
);
545 remove_persona_and_disconnect (self
, persona
);
546 g_clear_object (&persona
);
548 g_clear_object (&iter
);
550 /* Add each of the new personas to the tree model */
551 iter
= gee_iterable_iterator (GEE_ITERABLE (added
));
552 while (gee_iterator_next (iter
))
554 FolksPersona
*persona
= gee_iterator_get (iter
);
555 add_persona_and_connect (self
, persona
);
556 g_clear_object (&persona
);
558 g_clear_object (&iter
);
560 g_object_unref (self
);
564 sort_personas (FolksPersona
*persona_a
,
565 FolksPersona
*persona_b
)
567 EmpathyContact
*contact
;
568 TpAccount
*account_a
, *account_b
;
571 g_return_val_if_fail (persona_a
!= NULL
|| persona_b
!= NULL
, 0);
574 ret_val
= g_utf8_collate (
575 folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (persona_a
)),
576 folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (persona_b
)));
582 ret_val
= g_utf8_collate (folks_persona_get_display_id (persona_a
),
583 folks_persona_get_display_id (persona_b
));
588 contact
= empathy_contact_dup_from_tp_contact (tpf_persona_get_contact (
589 TPF_PERSONA (persona_a
)));
590 account_a
= empathy_contact_get_account (contact
);
591 g_object_unref (contact
);
593 contact
= empathy_contact_dup_from_tp_contact (tpf_persona_get_contact (
594 TPF_PERSONA (persona_b
)));
595 account_b
= empathy_contact_get_account (contact
);
596 g_object_unref (contact
);
599 ret_val
= strcmp (tp_account_get_protocol (account_a
),
600 tp_account_get_protocol (account_b
));
606 ret_val
= strcmp (tp_proxy_get_object_path (account_a
),
607 tp_proxy_get_object_path (account_b
));
614 state_sort_func (GtkTreeModel
*model
,
620 gchar
*name_a
, *name_b
;
621 FolksPersona
*persona_a
, *persona_b
;
623 gtk_tree_model_get (model
, iter_a
,
624 EMPATHY_PERSONA_STORE_COL_NAME
, &name_a
,
625 EMPATHY_PERSONA_STORE_COL_PERSONA
, &persona_a
,
627 gtk_tree_model_get (model
, iter_b
,
628 EMPATHY_PERSONA_STORE_COL_NAME
, &name_b
,
629 EMPATHY_PERSONA_STORE_COL_PERSONA
, &persona_b
,
632 if (persona_a
== NULL
|| persona_b
== NULL
) {
637 /* If we managed to get this far, we can start looking at
640 ret_val
= -tp_connection_presence_type_cmp_availability (
641 folks_presence_details_get_presence_type (
642 FOLKS_PRESENCE_DETAILS (persona_a
)),
643 folks_presence_details_get_presence_type (
644 FOLKS_PRESENCE_DETAILS (persona_b
)));
647 /* Fallback: compare by name et al. */
648 ret_val
= sort_personas (persona_a
, persona_b
);
655 tp_clear_object (&persona_a
);
656 tp_clear_object (&persona_b
);
662 name_sort_func (GtkTreeModel
*model
,
667 gchar
*name_a
, *name_b
;
668 FolksPersona
*persona_a
, *persona_b
;
671 gtk_tree_model_get (model
, iter_a
,
672 EMPATHY_PERSONA_STORE_COL_NAME
, &name_a
,
673 EMPATHY_PERSONA_STORE_COL_PERSONA
, &persona_a
,
675 gtk_tree_model_get (model
, iter_b
,
676 EMPATHY_PERSONA_STORE_COL_NAME
, &name_b
,
677 EMPATHY_PERSONA_STORE_COL_PERSONA
, &persona_b
,
680 if (persona_a
== NULL
|| persona_b
== NULL
)
683 ret_val
= sort_personas (persona_a
, persona_b
);
685 tp_clear_object (&persona_a
);
686 tp_clear_object (&persona_b
);
692 find_persona (EmpathyPersonaStore
*self
,
693 FolksPersona
*persona
)
695 EmpathyPersonaStorePriv
*priv
= GET_PRIV (self
);
696 GtkTreeRowReference
*row
;
698 row
= g_hash_table_lookup (priv
->personas
, persona
);
702 return gtk_tree_row_reference_get_path (row
);
706 update_list_mode_foreach (GtkTreeModel
*model
,
709 EmpathyPersonaStore
*self
)
711 EmpathyPersonaStorePriv
*priv
;
712 FolksPersona
*persona
;
713 GdkPixbuf
*pixbuf_status
;
715 priv
= GET_PRIV (self
);
717 gtk_tree_model_get (model
, iter
,
718 EMPATHY_PERSONA_STORE_COL_PERSONA
, &persona
,
724 /* get icon from hash_table */
725 pixbuf_status
= get_persona_status_icon (self
, persona
);
727 gtk_list_store_set (GTK_LIST_STORE (self
), iter
,
728 EMPATHY_PERSONA_STORE_COL_ICON_STATUS
, pixbuf_status
,
729 EMPATHY_PERSONA_STORE_COL_PIXBUF_AVATAR_VISIBLE
, priv
->show_avatars
,
732 tp_clear_object (&persona
);
738 set_up (EmpathyPersonaStore
*self
)
740 EmpathyPersonaStorePriv
*priv
;
742 GDK_TYPE_PIXBUF
, /* Status pixbuf */
743 GDK_TYPE_PIXBUF
, /* Avatar pixbuf */
744 G_TYPE_BOOLEAN
, /* Avatar pixbuf visible */
745 G_TYPE_STRING
, /* Name */
746 G_TYPE_STRING
, /* Account name */
747 G_TYPE_STRING
, /* Display ID */
748 G_TYPE_UINT
, /* Presence type */
749 G_TYPE_STRING
, /* Status string */
750 FOLKS_TYPE_PERSONA
, /* Persona */
751 G_TYPE_BOOLEAN
, /* Is active */
752 G_TYPE_BOOLEAN
, /* Is online */
753 G_TYPE_BOOLEAN
, /* Can make audio calls */
754 G_TYPE_BOOLEAN
, /* Can make video calls */
757 priv
= GET_PRIV (self
);
759 gtk_list_store_set_column_types (GTK_LIST_STORE (self
),
760 EMPATHY_PERSONA_STORE_COL_COUNT
, types
);
763 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (self
),
764 EMPATHY_PERSONA_STORE_COL_NAME
, name_sort_func
, self
, NULL
);
765 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (self
),
766 EMPATHY_PERSONA_STORE_COL_STATUS
, state_sort_func
, self
, NULL
);
768 priv
->sort_criterion
= EMPATHY_PERSONA_STORE_SORT_NAME
;
769 empathy_persona_store_set_sort_criterion (self
, priv
->sort_criterion
);
773 empathy_persona_store_init (EmpathyPersonaStore
*self
)
775 EmpathyPersonaStorePriv
*priv
= G_TYPE_INSTANCE_GET_PRIVATE (self
,
776 EMPATHY_TYPE_PERSONA_STORE
, EmpathyPersonaStorePriv
);
780 priv
->show_avatars
= TRUE
;
781 priv
->show_protocols
= FALSE
;
782 priv
->inhibit_active
= g_timeout_add_seconds (ACTIVE_USER_WAIT_TO_ENABLE_TIME
,
783 (GSourceFunc
) inhibit_active_cb
, self
);
785 priv
->status_icons
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
,
787 priv
->personas
= g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
788 g_object_unref
, (GDestroyNotify
) gtk_tree_row_reference_free
);
794 get_property (GObject
*object
,
799 EmpathyPersonaStorePriv
*priv
= GET_PRIV (object
);
803 case PROP_INDIVIDUAL
:
804 g_value_set_object (value
, priv
->individual
);
806 case PROP_SHOW_AVATARS
:
807 g_value_set_boolean (value
, priv
->show_avatars
);
809 case PROP_SHOW_PROTOCOLS
:
810 g_value_set_boolean (value
, priv
->show_protocols
);
812 case PROP_SORT_CRITERION
:
813 g_value_set_enum (value
, priv
->sort_criterion
);
816 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
822 set_property (GObject
*object
,
827 EmpathyPersonaStore
*self
= EMPATHY_PERSONA_STORE (object
);
831 case PROP_INDIVIDUAL
:
832 empathy_persona_store_set_individual (self
, g_value_get_object (value
));
834 case PROP_SHOW_AVATARS
:
835 empathy_persona_store_set_show_avatars (self
,
836 g_value_get_boolean (value
));
838 case PROP_SHOW_PROTOCOLS
:
839 empathy_persona_store_set_show_protocols (self
,
840 g_value_get_boolean (value
));
842 case PROP_SORT_CRITERION
:
843 empathy_persona_store_set_sort_criterion (self
,
844 g_value_get_enum (value
));
847 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
853 dispose (GObject
*object
)
855 EmpathyPersonaStorePriv
*priv
= GET_PRIV (object
);
857 empathy_persona_store_set_individual (EMPATHY_PERSONA_STORE (object
), NULL
);
859 if (priv
->inhibit_active
!= 0)
861 g_source_remove (priv
->inhibit_active
);
862 priv
->inhibit_active
= 0;
865 if (priv
->setup_idle_id
!= 0)
867 g_source_remove (priv
->setup_idle_id
);
868 priv
->setup_idle_id
= 0;
871 G_OBJECT_CLASS (empathy_persona_store_parent_class
)->dispose (object
);
875 finalize (GObject
*object
)
877 EmpathyPersonaStorePriv
*priv
= GET_PRIV (object
);
879 g_hash_table_destroy (priv
->status_icons
);
880 g_hash_table_destroy (priv
->personas
);
882 G_OBJECT_CLASS (empathy_persona_store_parent_class
)->finalize (object
);
886 empathy_persona_store_class_init (EmpathyPersonaStoreClass
*klass
)
888 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
890 object_class
->get_property
= get_property
;
891 object_class
->set_property
= set_property
;
892 object_class
->dispose
= dispose
;
893 object_class
->finalize
= finalize
;
896 * EmpathyPersonaStore:individual:
898 * The #FolksIndividual whose personas should be listed by the store. This
899 * may be %NULL, which results in an empty store.
901 g_object_class_install_property (object_class
, PROP_INDIVIDUAL
,
902 g_param_spec_object ("individual",
904 "The FolksIndividual whose Personas should be listed by the store.",
905 FOLKS_TYPE_INDIVIDUAL
,
906 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
));
909 * EmpathyPersonaStore:show-avatars:
911 * Whether the store should display avatars for personas. This is a property
912 * of the store rather than of #EmpathyPersonaView for efficiency reasons.
914 g_object_class_install_property (object_class
, PROP_SHOW_AVATARS
,
915 g_param_spec_boolean ("show-avatars",
917 "Whether the store should display avatars for personas.",
919 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
));
922 * EmpathyPersonaStore:show-protocols:
924 * Whether the store should display protocol icons for personas. This is a
925 * property of the store rather than of #EmpathyPersonaView because it is
926 * closely tied in with #EmpathyPersonaStore:show-avatars.
928 g_object_class_install_property (object_class
, PROP_SHOW_PROTOCOLS
,
929 g_param_spec_boolean ("show-protocols",
931 "Whether the store should display protocol icons for personas.",
933 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
));
936 * EmpathyPersonaStore:sort-criterion:
938 * The criterion used to sort the personas in the store.
940 g_object_class_install_property (object_class
, PROP_SORT_CRITERION
,
941 g_param_spec_enum ("sort-criterion",
943 "The sort criterion to use for sorting the persona list",
944 EMPATHY_TYPE_PERSONA_STORE_SORT
,
945 EMPATHY_PERSONA_STORE_SORT_NAME
,
946 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
));
948 g_type_class_add_private (object_class
, sizeof (EmpathyPersonaStorePriv
));
952 * empathy_persona_store_new:
953 * @individual: the #FolksIndividual whose personas should be used in the store,
956 * Create a new #EmpathyPersonaStore with the personas from the given
959 * Return value: a new #EmpathyPersonaStore
961 EmpathyPersonaStore
*
962 empathy_persona_store_new (FolksIndividual
*individual
)
964 g_return_val_if_fail (individual
== NULL
|| FOLKS_IS_INDIVIDUAL (individual
),
967 return g_object_new (EMPATHY_TYPE_PERSONA_STORE
,
968 "individual", individual
, NULL
);
972 * empathy_persona_store_get_individual:
973 * @self: an #EmpathyPersonaStore
975 * Get the value of #EmpathyPersonaStore:individual.
977 * Return value: the individual being displayed by the store, or %NULL
980 empathy_persona_store_get_individual (EmpathyPersonaStore
*self
)
982 g_return_val_if_fail (EMPATHY_IS_PERSONA_STORE (self
), NULL
);
984 return GET_PRIV (self
)->individual
;
988 * empathy_persona_store_set_individual:
989 * @self: an #EmpathyPersonaStore
990 * @individual: the new individual to display in the store, or %NULL
992 * Set #EmpathyPersonaStore:individual to @individual, replacing the personas
993 * which were in the store with the personas belonging to @individual, or with
994 * nothing if @individual is %NULL.
997 empathy_persona_store_set_individual (EmpathyPersonaStore
*self
,
998 FolksIndividual
*individual
)
1000 EmpathyPersonaStorePriv
*priv
;
1002 g_return_if_fail (EMPATHY_IS_PERSONA_STORE (self
));
1003 g_return_if_fail (individual
== NULL
|| FOLKS_IS_INDIVIDUAL (individual
));
1005 priv
= GET_PRIV (self
);
1007 /* Remove the old individual */
1008 if (priv
->individual
!= NULL
)
1013 g_signal_handlers_disconnect_by_func (priv
->individual
,
1014 (GCallback
) individual_personas_changed_cb
, self
);
1016 /* Disconnect from and remove all personas belonging to this individual */
1017 personas
= folks_individual_get_personas (priv
->individual
);
1018 iter
= gee_iterable_iterator (GEE_ITERABLE (personas
));
1019 while (gee_iterator_next (iter
))
1021 FolksPersona
*persona
= gee_iterator_get (iter
);
1022 remove_persona_and_disconnect (self
, persona
);
1023 g_clear_object (&persona
);
1025 g_clear_object (&iter
);
1027 g_object_unref (priv
->individual
);
1030 priv
->individual
= individual
;
1032 /* Add the new individual */
1033 if (individual
!= NULL
)
1038 g_object_ref (individual
);
1040 g_signal_connect (individual
, "personas-changed",
1041 (GCallback
) individual_personas_changed_cb
, self
);
1043 /* Add pre-existing Personas */
1045 personas
= folks_individual_get_personas (individual
);
1046 iter
= gee_iterable_iterator (GEE_ITERABLE (personas
));
1047 while (gee_iterator_next (iter
))
1049 FolksPersona
*persona
= gee_iterator_get (iter
);
1050 add_persona_and_connect (self
, persona
);
1051 g_clear_object (&persona
);
1053 g_clear_object (&iter
);
1056 g_object_notify (G_OBJECT (self
), "individual");
1060 * empathy_persona_store_get_show_avatars:
1061 * @self: an #EmpathyPersonaStore
1063 * Get the value of #EmpathyPersonaStore:show-avatars.
1065 * Return value: %TRUE if avatars are made available by the store, %FALSE
1069 empathy_persona_store_get_show_avatars (EmpathyPersonaStore
*self
)
1071 g_return_val_if_fail (EMPATHY_IS_PERSONA_STORE (self
), TRUE
);
1073 return GET_PRIV (self
)->show_avatars
;
1077 * empathy_persona_store_set_show_avatars:
1078 * @self: an #EmpathyPersonaStore
1079 * @show_avatars: %TRUE to make avatars available through the store, %FALSE
1082 * Set #EmpathyPersonaStore:show-avatars to @show_avatars.
1085 empathy_persona_store_set_show_avatars (EmpathyPersonaStore
*self
,
1086 gboolean show_avatars
)
1088 EmpathyPersonaStorePriv
*priv
;
1090 g_return_if_fail (EMPATHY_IS_PERSONA_STORE (self
));
1092 priv
= GET_PRIV (self
);
1093 priv
->show_avatars
= show_avatars
;
1095 gtk_tree_model_foreach (GTK_TREE_MODEL (self
),
1096 (GtkTreeModelForeachFunc
) update_list_mode_foreach
, self
);
1098 g_object_notify (G_OBJECT (self
), "show-avatars");
1102 * empathy_persona_store_get_show_protocols:
1103 * @self: an #EmpathyPersonaStore
1105 * Get the value of #EmpathyPersonaStore:show-protocols.
1107 * Return value: %TRUE if protocol images are made available by the store,
1111 empathy_persona_store_get_show_protocols (EmpathyPersonaStore
*self
)
1113 g_return_val_if_fail (EMPATHY_IS_PERSONA_STORE (self
), TRUE
);
1115 return GET_PRIV (self
)->show_protocols
;
1119 * empathy_persona_store_set_show_protocols:
1120 * @self: an #EmpathyPersonaStore
1121 * @show_protocols: %TRUE to make protocol images available through the store,
1124 * Set #EmpathyPersonaStore:show-protocols to @show_protocols.
1127 empathy_persona_store_set_show_protocols (EmpathyPersonaStore
*self
,
1128 gboolean show_protocols
)
1130 EmpathyPersonaStorePriv
*priv
;
1132 g_return_if_fail (EMPATHY_IS_PERSONA_STORE (self
));
1134 priv
= GET_PRIV (self
);
1135 priv
->show_protocols
= show_protocols
;
1137 gtk_tree_model_foreach (GTK_TREE_MODEL (self
),
1138 (GtkTreeModelForeachFunc
) update_list_mode_foreach
, self
);
1140 g_object_notify (G_OBJECT (self
), "show-protocols");
1144 * empathy_persona_store_get_sort_criterion:
1145 * @self: an #EmpathyPersonaStore
1147 * Get the value of #EmpathyPersonaStore:sort-criterion.
1149 * Return value: the criterion used to sort the personas in the store
1151 EmpathyPersonaStoreSort
1152 empathy_persona_store_get_sort_criterion (EmpathyPersonaStore
*self
)
1154 g_return_val_if_fail (EMPATHY_IS_PERSONA_STORE (self
), 0);
1156 return GET_PRIV (self
)->sort_criterion
;
1160 * empathy_persona_store_set_sort_criterion:
1161 * @self: an #EmpathyPersonaStore
1162 * @show_avatars: a criterion to be used to sort personas in the store
1164 * Set #EmpathyPersonaStore:sort-criterion to @sort_criterion.
1167 empathy_persona_store_set_sort_criterion (EmpathyPersonaStore
*self
,
1168 EmpathyPersonaStoreSort sort_criterion
)
1170 EmpathyPersonaStorePriv
*priv
;
1172 g_return_if_fail (EMPATHY_IS_PERSONA_STORE (self
));
1174 priv
= GET_PRIV (self
);
1175 priv
->sort_criterion
= sort_criterion
;
1177 switch (sort_criterion
)
1179 case EMPATHY_PERSONA_STORE_SORT_STATE
:
1180 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (self
),
1181 EMPATHY_PERSONA_STORE_COL_STATUS
, GTK_SORT_ASCENDING
);
1183 case EMPATHY_PERSONA_STORE_SORT_NAME
:
1184 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (self
),
1185 EMPATHY_PERSONA_STORE_COL_NAME
, GTK_SORT_ASCENDING
);
1188 g_assert_not_reached ();
1192 g_object_notify (G_OBJECT (self
), "sort-criterion");