2 * Copyright (C) 2007-2010 Collabora Ltd.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 * Authors: Xavier Claessens <xclaesse@gmail.com>
19 * Philip Withnall <philip.withnall@collabora.co.uk>
28 #include <glib/gi18n-lib.h>
30 #include <telepathy-glib/util.h>
32 #include <folks/folks.h>
33 #include <folks/folks-telepathy.h>
35 #ifdef HAVE_LIBCHAMPLAIN
36 #include <champlain/champlain.h>
37 #include <champlain-gtk/champlain-gtk.h>
40 #include <libempathy/empathy-utils.h>
41 #include <libempathy/empathy-location.h>
42 #include <libempathy/empathy-time.h>
44 #include "empathy-avatar-image.h"
45 #include "empathy-groups-widget.h"
46 #include "empathy-gtk-enum-types.h"
47 #include "empathy-individual-widget.h"
48 #include "empathy-string-parser.h"
49 #include "empathy-ui-utils.h"
51 #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT
52 #include <libempathy/empathy-debug.h>
55 * SECTION:empathy-individual-widget
56 * @title:EmpathyIndividualWidget
57 * @short_description: A widget used to display and edit details about an
59 * @include: libempathy-empathy-individual-widget.h
61 * #EmpathyIndividualWidget is a widget which displays appropriate widgets
62 * with details about an individual, also allowing changing these details,
67 * EmpathyIndividualWidget:
68 * @parent: parent object
70 * Widget which displays appropriate widgets with details about an individual,
71 * also allowing changing these details, if desired.
74 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyIndividualWidget)
77 FolksIndividual
*individual
; /* owned */
78 EmpathyIndividualWidgetFlags flags
;
80 /* weak pointer to the contact whose contact details we're displaying */
83 /* unowned Persona (borrowed from priv->individual) -> GtkTable child */
84 GHashTable
*persona_tables
;
85 /* Table containing the information for the individual as whole, or NULL */
86 GtkTable
*individual_table
;
89 GtkWidget
*hbox_presence
;
90 GtkWidget
*vbox_individual_widget
;
91 GtkWidget
*scrolled_window_individual
;
92 GtkWidget
*viewport_individual
;
93 GtkWidget
*vbox_individual
;
96 GtkWidget
*vbox_location
;
97 GtkWidget
*subvbox_location
;
98 GtkWidget
*table_location
;
99 GtkWidget
*label_location
;
100 #ifdef HAVE_LIBCHAMPLAIN
101 GtkWidget
*viewport_map
;
102 GtkWidget
*map_view_embed
;
103 ChamplainView
*map_view
;
107 GtkWidget
*groups_widget
;
110 GtkWidget
*hbox_client_types
;
113 GtkWidget
*vbox_details
;
114 GtkWidget
*table_details
;
115 GtkWidget
*hbox_details_requested
;
116 GtkWidget
*details_spinner
;
117 GCancellable
*details_cancellable
; /* owned */
118 } EmpathyIndividualWidgetPriv
;
120 G_DEFINE_TYPE (EmpathyIndividualWidget
, empathy_individual_widget
,
128 static void client_types_update (EmpathyIndividualWidget
*self
);
129 static void remove_weak_contact (EmpathyIndividualWidget
*self
);
132 details_set_up (EmpathyIndividualWidget
*self
)
134 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
136 gtk_widget_hide (priv
->vbox_details
);
138 priv
->details_spinner
= gtk_spinner_new ();
139 gtk_box_pack_end (GTK_BOX (priv
->hbox_details_requested
),
140 priv
->details_spinner
, TRUE
, TRUE
, 0);
141 gtk_widget_show (priv
->details_spinner
);
146 const gchar
*field_name
;
151 static InfoFieldData info_field_data
[] =
153 { "fn", N_("Full name:"), FALSE
},
154 { "tel", N_("Phone number:"), FALSE
},
155 { "email", N_("E-mail address:"), TRUE
},
156 { "url", N_("Website:"), TRUE
},
157 { "bday", N_("Birthday:"), FALSE
},
161 static InfoFieldData
*
162 find_info_field_data (const gchar
*field_name
)
166 for (i
= 0; info_field_data
[i
].field_name
!= NULL
; i
++)
168 if (tp_strdiff (info_field_data
[i
].field_name
, field_name
) == FALSE
)
169 return info_field_data
+ i
;
175 contact_info_field_name_cmp (const gchar
*name1
,
180 if (tp_strdiff (name1
, name2
) == FALSE
)
183 /* We use the order of info_field_data */
184 for (i
= 0; info_field_data
[i
].field_name
!= NULL
; i
++)
186 if (tp_strdiff (info_field_data
[i
].field_name
, name1
) == FALSE
)
188 if (tp_strdiff (info_field_data
[i
].field_name
, name2
) == FALSE
)
192 return g_strcmp0 (name1
, name2
);
196 contact_info_field_cmp (TpContactInfoField
*field1
,
197 TpContactInfoField
*field2
)
199 return contact_info_field_name_cmp (field1
->field_name
, field2
->field_name
);
203 client_types_notify_cb (TpContact
*contact
,
205 EmpathyIndividualWidget
*self
)
207 client_types_update (self
);
211 update_weak_contact (EmpathyIndividualWidget
*self
)
213 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
214 TpContact
*tp_contact
= NULL
;
216 remove_weak_contact (self
);
218 if (priv
->individual
!= NULL
)
220 /* FIXME: We take the most available TpContact we find and only
221 * use its details. It would be a lot better if we would get the
222 * details for every TpContact in the Individual and merge them
223 * all, but that requires vCard support in libfolks for it to
224 * not be hideously complex. (bgo#627399) */
227 FolksPresenceType presence_type
= FOLKS_PRESENCE_TYPE_UNSET
;
229 personas
= folks_individual_get_personas (priv
->individual
);
230 iter
= gee_iterable_iterator (GEE_ITERABLE (personas
));
231 while (gee_iterator_next (iter
))
233 FolksPersona
*persona
= gee_iterator_get (iter
);
235 /* We only want personas which have presence and a TpContact */
236 if (empathy_folks_persona_is_interesting (FOLKS_PERSONA (persona
)))
238 FolksPresenceDetails
*presence
;
239 FolksPresenceType presence_type_cur
;
241 presence
= FOLKS_PRESENCE_DETAILS (persona
);
242 presence_type_cur
= folks_presence_details_get_presence_type (
245 if (folks_presence_details_typecmp (
246 presence_type_cur
, presence_type
) > 0)
248 presence_type
= presence_type_cur
;
249 tp_contact
= tpf_persona_get_contact (TPF_PERSONA (persona
));
253 g_clear_object (&persona
);
255 g_clear_object (&iter
);
258 if (tp_contact
!= NULL
)
260 priv
->contact
= tp_contact
;
261 g_object_add_weak_pointer (G_OBJECT (tp_contact
),
262 (gpointer
*) &priv
->contact
);
264 g_signal_connect (priv
->contact
, "notify::client-types",
265 (GCallback
) client_types_notify_cb
, self
);
270 EmpathyIndividualWidget
*widget
; /* weak */
271 TpContact
*contact
; /* owned */
275 details_data_free (DetailsData
*data
)
277 if (data
->widget
!= NULL
)
279 g_object_remove_weak_pointer (G_OBJECT (data
->widget
),
280 (gpointer
*) &data
->widget
);
282 g_object_unref (data
->contact
);
283 g_slice_free (DetailsData
, data
);
287 details_update_show (EmpathyIndividualWidget
*self
,
290 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
294 info
= tp_contact_get_contact_info (contact
);
295 info
= g_list_sort (info
, (GCompareFunc
) contact_info_field_cmp
);
296 for (l
= info
; l
!= NULL
; l
= l
->next
)
298 TpContactInfoField
*field
= l
->data
;
299 InfoFieldData
*field_data
;
303 if (field
->field_value
== NULL
|| field
->field_value
[0] == NULL
)
306 value
= field
->field_value
[0];
308 field_data
= find_info_field_data (field
->field_name
);
309 if (field_data
== NULL
)
311 DEBUG ("Unhandled ContactInfo field: %s", field
->field_name
);
316 w
= gtk_label_new (_(field_data
->title
));
317 gtk_table_attach (GTK_TABLE (priv
->table_details
),
318 w
, 0, 1, n_rows
, n_rows
+ 1, GTK_FILL
, 0, 0, 0);
319 gtk_misc_set_alignment (GTK_MISC (w
), 0, 0.5);
323 w
= gtk_label_new (value
);
324 if (field_data
->linkify
== TRUE
)
328 markup
= empathy_add_link_markup (value
);
329 gtk_label_set_markup (GTK_LABEL (w
), markup
);
333 gtk_label_set_selectable (GTK_LABEL (w
),
334 (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_FOR_TOOLTIP
) ? FALSE
: TRUE
);
336 gtk_table_attach_defaults (GTK_TABLE (priv
->table_details
),
337 w
, 1, 2, n_rows
, n_rows
+ 1);
338 gtk_misc_set_alignment (GTK_MISC (w
), 0, 0.5);
349 details_notify_cb (TpContact
*contact
,
351 EmpathyIndividualWidget
*self
)
353 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
356 gtk_container_foreach (GTK_CONTAINER (priv
->table_details
),
357 (GtkCallback
) gtk_widget_destroy
, NULL
);
359 n_rows
= details_update_show (self
, contact
);
363 gtk_widget_show (priv
->vbox_details
);
364 gtk_widget_show (priv
->table_details
);
368 gtk_widget_hide (priv
->vbox_details
);
371 gtk_widget_hide (priv
->hbox_details_requested
);
372 gtk_spinner_stop (GTK_SPINNER (priv
->details_spinner
));
376 details_request_cb (TpContact
*contact
,
380 EmpathyIndividualWidget
*self
= data
->widget
;
381 gboolean hide_widget
= FALSE
;
382 GError
*error
= NULL
;
384 if (tp_contact_request_contact_info_finish (contact
, res
, &error
) == TRUE
)
385 details_notify_cb (contact
, NULL
, self
);
389 g_clear_error (&error
);
393 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
395 if (hide_widget
== TRUE
)
396 gtk_widget_hide (GET_PRIV (self
)->vbox_details
);
398 tp_clear_object (&priv
->details_cancellable
);
400 g_signal_connect (contact
, "notify::contact-info",
401 (GCallback
) details_notify_cb
, self
);
404 details_data_free (data
);
408 details_feature_prepared_cb (TpConnection
*connection
,
412 EmpathyIndividualWidget
*self
= data
->widget
;
413 EmpathyIndividualWidgetPriv
*priv
= NULL
;
415 if (tp_proxy_prepare_finish (connection
, res
, NULL
) == FALSE
|| self
== NULL
)
418 gtk_widget_hide (GET_PRIV (self
)->vbox_details
);
419 details_data_free (data
);
423 priv
= GET_PRIV (self
);
425 /* Request the Individual's info */
426 gtk_widget_show (priv
->vbox_details
);
427 gtk_widget_show (priv
->hbox_details_requested
);
428 gtk_widget_hide (priv
->table_details
);
429 gtk_spinner_start (GTK_SPINNER (priv
->details_spinner
));
431 if (priv
->details_cancellable
== NULL
)
433 priv
->details_cancellable
= g_cancellable_new ();
434 tp_contact_request_contact_info_async (data
->contact
,
435 priv
->details_cancellable
, (GAsyncReadyCallback
) details_request_cb
,
441 details_update (EmpathyIndividualWidget
*self
)
443 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
445 if (!(priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_SHOW_DETAILS
))
448 gtk_widget_hide (priv
->vbox_details
);
450 if (priv
->contact
== NULL
)
451 update_weak_contact (self
);
453 if (priv
->contact
!= NULL
)
455 GQuark features
[] = { TP_CONNECTION_FEATURE_CONTACT_INFO
, 0 };
456 TpConnection
*connection
;
459 data
= g_slice_new (DetailsData
);
461 g_object_add_weak_pointer (G_OBJECT (self
), (gpointer
*) &data
->widget
);
462 data
->contact
= g_object_ref (priv
->contact
);
464 /* First, make sure the CONTACT_INFO feature is ready on the connection */
465 connection
= tp_contact_get_connection (priv
->contact
);
466 tp_proxy_prepare_async (connection
, features
,
467 (GAsyncReadyCallback
) details_feature_prepared_cb
, data
);
472 groups_update (EmpathyIndividualWidget
*self
)
474 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
476 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_EDIT_GROUPS
&&
477 priv
->individual
!= NULL
)
479 empathy_groups_widget_set_group_details (
480 EMPATHY_GROUPS_WIDGET (priv
->groups_widget
),
481 FOLKS_GROUP_DETAILS (priv
->individual
));
482 gtk_widget_show (priv
->groups_widget
);
486 gtk_widget_hide (priv
->groups_widget
);
490 /* Converts the Location's GHashTable's key to a user readable string */
492 location_key_to_label (const gchar
*key
)
494 if (tp_strdiff (key
, EMPATHY_LOCATION_COUNTRY_CODE
) == FALSE
)
495 return _("Country ISO Code:");
496 else if (tp_strdiff (key
, EMPATHY_LOCATION_COUNTRY
) == FALSE
)
497 return _("Country:");
498 else if (tp_strdiff (key
, EMPATHY_LOCATION_REGION
) == FALSE
)
500 else if (tp_strdiff (key
, EMPATHY_LOCATION_LOCALITY
) == FALSE
)
502 else if (tp_strdiff (key
, EMPATHY_LOCATION_AREA
) == FALSE
)
504 else if (tp_strdiff (key
, EMPATHY_LOCATION_POSTAL_CODE
) == FALSE
)
505 return _("Postal Code:");
506 else if (tp_strdiff (key
, EMPATHY_LOCATION_STREET
) == FALSE
)
508 else if (tp_strdiff (key
, EMPATHY_LOCATION_BUILDING
) == FALSE
)
509 return _("Building:");
510 else if (tp_strdiff (key
, EMPATHY_LOCATION_FLOOR
) == FALSE
)
512 else if (tp_strdiff (key
, EMPATHY_LOCATION_ROOM
) == FALSE
)
514 else if (tp_strdiff (key
, EMPATHY_LOCATION_TEXT
) == FALSE
)
516 else if (tp_strdiff (key
, EMPATHY_LOCATION_DESCRIPTION
) == FALSE
)
517 return _("Description:");
518 else if (tp_strdiff (key
, EMPATHY_LOCATION_URI
) == FALSE
)
520 else if (tp_strdiff (key
, EMPATHY_LOCATION_ACCURACY_LEVEL
) == FALSE
)
521 return _("Accuracy Level:");
522 else if (tp_strdiff (key
, EMPATHY_LOCATION_ERROR
) == FALSE
)
524 else if (tp_strdiff (key
, EMPATHY_LOCATION_VERTICAL_ERROR_M
) == FALSE
)
525 return _("Vertical Error (meters):");
526 else if (tp_strdiff (key
, EMPATHY_LOCATION_HORIZONTAL_ERROR_M
) == FALSE
)
527 return _("Horizontal Error (meters):");
528 else if (tp_strdiff (key
, EMPATHY_LOCATION_SPEED
) == FALSE
)
530 else if (tp_strdiff (key
, EMPATHY_LOCATION_BEARING
) == FALSE
)
531 return _("Bearing:");
532 else if (tp_strdiff (key
, EMPATHY_LOCATION_CLIMB
) == FALSE
)
533 return _("Climb Speed:");
534 else if (tp_strdiff (key
, EMPATHY_LOCATION_TIMESTAMP
) == FALSE
)
535 return _("Last Updated on:");
536 else if (tp_strdiff (key
, EMPATHY_LOCATION_LON
) == FALSE
)
537 return _("Longitude:");
538 else if (tp_strdiff (key
, EMPATHY_LOCATION_LAT
) == FALSE
)
539 return _("Latitude:");
540 else if (tp_strdiff (key
, EMPATHY_LOCATION_ALT
) == FALSE
)
541 return _("Altitude:");
544 DEBUG ("Unexpected Location key: %s", key
);
550 location_update (EmpathyIndividualWidget
*self
)
552 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
553 EmpathyContact
*contact
= NULL
;
554 GHashTable
*location
= NULL
;
558 static const gchar
* ordered_geolocation_keys
[] = {
559 EMPATHY_LOCATION_TEXT
,
560 EMPATHY_LOCATION_URI
,
561 EMPATHY_LOCATION_DESCRIPTION
,
562 EMPATHY_LOCATION_BUILDING
,
563 EMPATHY_LOCATION_FLOOR
,
564 EMPATHY_LOCATION_ROOM
,
565 EMPATHY_LOCATION_STREET
,
566 EMPATHY_LOCATION_AREA
,
567 EMPATHY_LOCATION_LOCALITY
,
568 EMPATHY_LOCATION_REGION
,
569 EMPATHY_LOCATION_COUNTRY
,
574 gboolean display_map
= FALSE
;
578 if (!(priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_SHOW_LOCATION
) ||
579 priv
->individual
== NULL
)
581 gtk_widget_hide (priv
->vbox_location
);
585 /* FIXME: For the moment, we just display the first location data we can
586 * find amongst the Individual's Personas. Once libfolks grows a location
587 * interface, we can use that. (bgo#627400) */
589 personas
= folks_individual_get_personas (priv
->individual
);
590 iter
= gee_iterable_iterator (GEE_ITERABLE (personas
));
591 while (location
== NULL
&& gee_iterator_next (iter
))
593 FolksPersona
*persona
= gee_iterator_get (iter
);
595 if (empathy_folks_persona_is_interesting (persona
))
597 TpContact
*tp_contact
;
599 /* Get the contact. If it turns out to have location information, we
600 * have to keep it alive for the duration of the function, since we're
601 * accessing its private data. */
602 tp_contact
= tpf_persona_get_contact (TPF_PERSONA (persona
));
603 contact
= empathy_contact_dup_from_tp_contact (tp_contact
);
604 empathy_contact_set_persona (contact
, persona
);
606 /* Try and get a location */
607 location
= empathy_contact_get_location (contact
);
608 /* if location isn't fully valid, treat the contact as insufficient */
609 if (location
!= NULL
&& g_hash_table_size (location
) <= 0)
612 g_clear_object (&contact
);
615 g_clear_object (&persona
);
617 g_clear_object (&iter
);
619 if (contact
== NULL
|| location
== NULL
)
621 gtk_widget_hide (priv
->vbox_location
);
622 tp_clear_object (&contact
);
626 value
= g_hash_table_lookup (location
, EMPATHY_LOCATION_TIMESTAMP
);
629 gchar
*loc
= g_strdup_printf ("<b>%s</b>", _("Location"));
630 gtk_label_set_markup (GTK_LABEL (priv
->label_location
), loc
);
640 stamp
= g_value_get_int64 (value
);
642 user_date
= empathy_time_to_string_relative (stamp
);
644 tmp
= g_strdup_printf ("<b>%s</b>", _("Location"));
645 /* translators: format is "Location, $date" */
646 text
= g_strdup_printf (_("%s, %s"), tmp
, user_date
);
648 gtk_label_set_markup (GTK_LABEL (priv
->label_location
), text
);
653 /* Prepare the location information table */
654 if (priv
->table_location
!= NULL
)
655 gtk_widget_destroy (priv
->table_location
);
657 priv
->table_location
= gtk_table_new (1, 2, FALSE
);
658 gtk_box_pack_start (GTK_BOX (priv
->subvbox_location
),
659 priv
->table_location
, FALSE
, FALSE
, 5);
662 for (i
= 0; (skey
= ordered_geolocation_keys
[i
]); i
++)
664 const gchar
* user_label
;
668 gvalue
= g_hash_table_lookup (location
, (gpointer
) skey
);
672 user_label
= location_key_to_label (skey
);
674 label
= gtk_label_new (user_label
);
675 gtk_misc_set_alignment (GTK_MISC (label
), 0, 0.5);
676 gtk_table_attach (GTK_TABLE (priv
->table_location
),
677 label
, 0, 1, row
, row
+ 1, GTK_FILL
, GTK_FILL
, 10, 0);
678 gtk_widget_show (label
);
680 if (G_VALUE_TYPE (gvalue
) == G_TYPE_DOUBLE
)
683 dvalue
= g_value_get_double (gvalue
);
684 svalue
= g_strdup_printf ("%f", dvalue
);
686 else if (G_VALUE_TYPE (gvalue
) == G_TYPE_STRING
)
688 svalue
= g_value_dup_string (gvalue
);
690 else if (G_VALUE_TYPE (gvalue
) == G_TYPE_INT64
)
694 time_
= g_value_get_int64 (value
);
695 svalue
= empathy_time_to_string_utc (time_
, _("%B %e, %Y at %R UTC"));
700 label
= gtk_label_new (svalue
);
701 gtk_table_attach_defaults (GTK_TABLE (priv
->table_location
),
702 label
, 1, 2, row
, row
+ 1);
703 gtk_misc_set_alignment (GTK_MISC (label
), 0, 0);
704 gtk_widget_show (label
);
706 gtk_label_set_selectable (GTK_LABEL (label
),
707 (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_FOR_TOOLTIP
) ? FALSE
:
715 tp_clear_object (&contact
);
717 #ifdef HAVE_LIBCHAMPLAIN
718 if ((g_hash_table_lookup (location
, EMPATHY_LOCATION_LAT
) != NULL
) &&
719 (g_hash_table_lookup (location
, EMPATHY_LOCATION_LON
) != NULL
) &&
720 !(priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_FOR_TOOLTIP
))
722 /* Cannot be displayed in tooltips until Clutter-Gtk can deal with such
730 /* We can display some fields */
731 gtk_widget_show (priv
->table_location
);
733 else if (display_map
== FALSE
)
735 /* Can't display either fields or map */
736 gtk_widget_hide (priv
->vbox_location
);
740 #ifdef HAVE_LIBCHAMPLAIN
741 if (display_map
== TRUE
)
743 ChamplainMarkerLayer
*layer
;
745 priv
->map_view_embed
= gtk_champlain_embed_new ();
746 priv
->map_view
= gtk_champlain_embed_get_view (
747 GTK_CHAMPLAIN_EMBED (priv
->map_view_embed
));
749 gtk_container_add (GTK_CONTAINER (priv
->viewport_map
),
750 priv
->map_view_embed
);
751 g_object_set (G_OBJECT (priv
->map_view
),
752 "kinetic-mode", TRUE
,
756 layer
= champlain_marker_layer_new ();
757 champlain_view_add_layer (priv
->map_view
, CHAMPLAIN_LAYER (layer
));
759 /* FIXME: For now, we have to do this manually. Once libfolks grows a
760 * location interface, we can use that. (bgo#627400) */
762 personas
= folks_individual_get_personas (priv
->individual
);
763 iter
= gee_iterable_iterator (GEE_ITERABLE (personas
));
764 while (gee_iterator_next (iter
))
766 FolksPersona
*persona
= gee_iterator_get (iter
);
768 if (empathy_folks_persona_is_interesting (persona
))
770 gdouble lat
= 0.0, lon
= 0.0;
771 ClutterActor
*marker
;
772 TpContact
*tp_contact
;
774 /* Get the contact */
775 tp_contact
= tpf_persona_get_contact (TPF_PERSONA (persona
));
776 contact
= empathy_contact_dup_from_tp_contact (tp_contact
);
777 empathy_contact_set_persona (contact
, persona
);
779 /* Try and get a location */
780 location
= empathy_contact_get_location (contact
);
781 if (location
== NULL
|| g_hash_table_size (location
) == 0)
784 /* Get this persona's latitude and longitude */
785 value
= g_hash_table_lookup (location
, EMPATHY_LOCATION_LAT
);
789 lat
= g_value_get_double (value
);
791 value
= g_hash_table_lookup (location
, EMPATHY_LOCATION_LON
);
795 lon
= g_value_get_double (value
);
797 /* Add a marker to the map */
798 marker
= champlain_label_new_with_text (
799 folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (persona
)),
801 champlain_location_set_location (CHAMPLAIN_LOCATION (marker
),
803 champlain_marker_layer_add_marker (layer
,
804 CHAMPLAIN_MARKER (marker
));
808 g_clear_object (&persona
);
809 g_clear_object (&contact
);
811 g_clear_object (&iter
);
813 /* Zoom to show all of the markers */
814 champlain_view_ensure_layers_visible (priv
->map_view
, FALSE
);
816 gtk_widget_show_all (priv
->viewport_map
);
820 gtk_widget_show (priv
->vbox_location
);
824 client_types_update (EmpathyIndividualWidget
*self
)
826 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
827 const gchar
* const *types
;
829 if (!(priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_SHOW_CLIENT_TYPES
) ||
830 priv
->individual
== NULL
)
832 gtk_widget_hide (priv
->hbox_client_types
);
836 if (priv
->contact
== NULL
)
837 update_weak_contact (self
);
839 /* let's try that again... */
840 if (priv
->contact
== NULL
)
843 types
= tp_contact_get_client_types (priv
->contact
);
846 && g_strv_length ((gchar
**) types
) > 0
847 && !tp_strdiff (types
[0], "phone"))
849 gtk_widget_show (priv
->hbox_client_types
);
853 gtk_widget_hide (priv
->hbox_client_types
);
859 remove_weak_contact (EmpathyIndividualWidget
*self
)
861 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
863 if (priv
->contact
== NULL
)
866 g_signal_handlers_disconnect_by_func (priv
->contact
, client_types_notify_cb
,
869 g_object_remove_weak_pointer (G_OBJECT (priv
->contact
),
870 (gpointer
*) &priv
->contact
);
871 priv
->contact
= NULL
;
874 static EmpathyAvatar
*
875 persona_dup_avatar (FolksPersona
*persona
)
877 TpContact
*tp_contact
;
878 EmpathyContact
*contact
;
879 EmpathyAvatar
*avatar
;
881 if (!empathy_folks_persona_is_interesting (persona
))
884 tp_contact
= tpf_persona_get_contact (TPF_PERSONA (persona
));
885 contact
= empathy_contact_dup_from_tp_contact (tp_contact
);
886 empathy_contact_set_persona (contact
, persona
);
888 avatar
= empathy_contact_get_avatar (contact
);
890 empathy_avatar_ref (avatar
);
891 g_object_unref (contact
);
896 static EmpathyAvatar
*
897 individual_dup_avatar (FolksIndividual
*individual
)
901 EmpathyAvatar
*avatar
= NULL
;
903 /* FIXME: We just choose the first Persona which has an avatar, and save that.
904 * The avatar handling in EmpathyContact needs to be moved into libfolks as
905 * much as possible, and this code rewritten to use FolksHasAvatar.
908 personas
= folks_individual_get_personas (individual
);
909 iter
= gee_iterable_iterator (GEE_ITERABLE (personas
));
910 while (avatar
== NULL
&& gee_iterator_next (iter
))
912 FolksPersona
*persona
= gee_iterator_get (iter
);
913 avatar
= persona_dup_avatar (persona
);
915 g_clear_object (&persona
);
917 g_clear_object (&iter
);
923 save_avatar_menu_activate_cb (GtkWidget
*widget
,
924 EmpathyIndividualWidget
*self
)
926 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
928 EmpathyAvatar
*avatar
;
929 gchar
*ext
= NULL
, *filename
;
931 dialog
= gtk_file_chooser_dialog_new (_("Save Avatar"),
933 GTK_FILE_CHOOSER_ACTION_SAVE
,
934 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
935 GTK_STOCK_SAVE
, GTK_RESPONSE_ACCEPT
,
938 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog
),
941 avatar
= individual_dup_avatar (priv
->individual
);
945 /* look for the avatar extension */
946 if (avatar
->format
!= NULL
)
950 splitted
= g_strsplit (avatar
->format
, "/", 2);
951 if (splitted
[0] != NULL
&& splitted
[1] != NULL
)
952 ext
= g_strdup (splitted
[1]);
954 g_strfreev (splitted
);
958 /* Avatar was loaded from the cache so was converted to PNG */
959 ext
= g_strdup ("png");
966 id
= tp_escape_as_identifier (folks_individual_get_id (priv
->individual
));
968 filename
= g_strdup_printf ("%s.%s", id
, ext
);
969 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog
), filename
);
976 if (gtk_dialog_run (GTK_DIALOG (dialog
)) == GTK_RESPONSE_ACCEPT
)
978 GError
*error
= NULL
;
980 filename
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog
));
982 if (empathy_avatar_save_to_file (avatar
, filename
, &error
) == FALSE
)
985 GtkWidget
*error_dialog
;
987 error_dialog
= gtk_message_dialog_new (NULL
, 0,
988 GTK_MESSAGE_ERROR
, GTK_BUTTONS_CLOSE
,
989 _("Unable to save avatar"));
991 gtk_message_dialog_format_secondary_text (
992 GTK_MESSAGE_DIALOG (error_dialog
), "%s", error
->message
);
994 g_signal_connect (error_dialog
, "response",
995 (GCallback
) gtk_widget_destroy
, NULL
);
997 gtk_window_present (GTK_WINDOW (error_dialog
));
999 g_clear_error (&error
);
1005 gtk_widget_destroy (dialog
);
1006 empathy_avatar_unref (avatar
);
1010 popup_avatar_menu (EmpathyIndividualWidget
*self
,
1012 GdkEventButton
*event
)
1014 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1015 GtkWidget
*menu
, *item
;
1016 EmpathyAvatar
*avatar
;
1017 gint button
, event_time
;
1019 if (priv
->individual
== NULL
)
1022 avatar
= individual_dup_avatar (priv
->individual
);
1025 empathy_avatar_unref (avatar
);
1027 menu
= empathy_context_menu_new (parent
);
1029 /* Add "Save as..." entry */
1030 item
= gtk_image_menu_item_new_from_stock (GTK_STOCK_SAVE_AS
, NULL
);
1031 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1032 gtk_widget_show (item
);
1034 g_signal_connect (item
, "activate",
1035 (GCallback
) save_avatar_menu_activate_cb
, self
);
1039 button
= event
->button
;
1040 event_time
= event
->time
;
1045 event_time
= gtk_get_current_event_time ();
1048 gtk_menu_popup (GTK_MENU (menu
), NULL
, NULL
, NULL
, NULL
, button
, event_time
);
1054 avatar_widget_popup_menu_cb (GtkWidget
*widget
,
1055 EmpathyIndividualWidget
*self
)
1057 return popup_avatar_menu (self
, widget
, NULL
);
1061 avatar_widget_button_press_event_cb (GtkWidget
*widget
,
1062 GdkEventButton
*event
,
1063 EmpathyIndividualWidget
*self
)
1065 /* Ignore double-clicks and triple-clicks */
1066 if (event
->button
== 3 && event
->type
== GDK_BUTTON_PRESS
)
1067 return popup_avatar_menu (self
, widget
, event
);
1072 /* Returns the TpAccount for the user as a convenience. Note that it has a ref
1075 individual_is_user (FolksIndividual
*individual
)
1079 TpAccount
*retval
= NULL
;
1081 /* FIXME: This should move into libfolks when libfolks grows a way of
1082 * determining "self". (bgo#627402) */
1083 personas
= folks_individual_get_personas (individual
);
1084 iter
= gee_iterable_iterator (GEE_ITERABLE (personas
));
1085 while (gee_iterator_next (iter
))
1087 FolksPersona
*persona
= gee_iterator_get (iter
);
1089 if (TPF_IS_PERSONA (persona
))
1091 TpContact
*tp_contact
;
1092 EmpathyContact
*contact
;
1094 /* Get the contact */
1095 tp_contact
= tpf_persona_get_contact (TPF_PERSONA (persona
));
1096 contact
= empathy_contact_dup_from_tp_contact (tp_contact
);
1097 empathy_contact_set_persona (contact
, persona
);
1099 /* Determine if the contact is the user */
1100 if (empathy_contact_is_user (contact
))
1101 retval
= g_object_ref (empathy_contact_get_account (contact
));
1103 g_object_unref (contact
);
1105 g_clear_object (&persona
);
1107 g_clear_object (&iter
);
1113 set_nickname_cb (TpAccount
*account
,
1114 GAsyncResult
*result
,
1117 GError
*error
= NULL
;
1119 if (tp_account_set_nickname_finish (account
, result
, &error
) == FALSE
)
1121 DEBUG ("Failed to set Account.Nickname: %s", error
->message
);
1122 g_error_free (error
);
1127 entry_alias_focus_event_cb (GtkEditable
*editable
,
1128 GdkEventFocus
*event
,
1129 EmpathyIndividualWidget
*self
)
1131 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1133 if (priv
->individual
!= NULL
)
1138 alias
= gtk_entry_get_text (GTK_ENTRY (editable
));
1139 account
= individual_is_user (priv
->individual
);
1141 if (account
!= NULL
)
1143 DEBUG ("Set Account.Nickname to %s", alias
);
1144 tp_account_set_nickname_async (account
, alias
,
1145 (GAsyncReadyCallback
) set_nickname_cb
, NULL
);
1146 g_object_unref (account
);
1150 folks_alias_details_set_alias (FOLKS_ALIAS_DETAILS (priv
->individual
),
1159 favourite_toggled_cb (GtkToggleButton
*button
,
1160 EmpathyIndividualWidget
*self
)
1162 gboolean active
= gtk_toggle_button_get_active (button
);
1163 folks_favourite_details_set_is_favourite (
1164 FOLKS_FAVOURITE_DETAILS (GET_PRIV (self
)->individual
), active
);
1168 notify_avatar_cb (gpointer folks_object
,
1170 EmpathyIndividualWidget
*self
)
1172 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1173 EmpathyAvatar
*avatar
= NULL
;
1175 GtkWidget
*avatar_widget
;
1177 if (FOLKS_IS_INDIVIDUAL (folks_object
))
1179 avatar
= individual_dup_avatar (FOLKS_INDIVIDUAL (folks_object
));
1180 table
= G_OBJECT (priv
->individual_table
);
1182 else if (FOLKS_IS_PERSONA (folks_object
))
1184 avatar
= persona_dup_avatar (FOLKS_PERSONA (folks_object
));
1185 table
= g_hash_table_lookup (priv
->persona_tables
, folks_object
);
1189 g_assert_not_reached ();
1195 avatar_widget
= g_object_get_data (table
, "avatar-widget");
1196 empathy_avatar_image_set (EMPATHY_AVATAR_IMAGE (avatar_widget
), avatar
);
1199 empathy_avatar_unref (avatar
);
1203 notify_alias_cb (gpointer folks_object
,
1205 EmpathyIndividualWidget
*self
)
1207 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1209 GtkWidget
*alias_widget
;
1211 if (FOLKS_IS_INDIVIDUAL (folks_object
))
1212 table
= G_OBJECT (priv
->individual_table
);
1213 else if (FOLKS_IS_PERSONA (folks_object
))
1214 table
= g_hash_table_lookup (priv
->persona_tables
, folks_object
);
1216 g_assert_not_reached ();
1221 alias_widget
= g_object_get_data (table
, "alias-widget");
1223 if (GTK_IS_ENTRY (alias_widget
))
1225 gtk_entry_set_text (GTK_ENTRY (alias_widget
),
1226 folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (folks_object
)));
1230 gtk_label_set_label (GTK_LABEL (alias_widget
),
1231 folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (folks_object
)));
1236 notify_presence_cb (gpointer folks_object
,
1238 EmpathyIndividualWidget
*self
)
1240 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1242 GtkWidget
*status_label
, *state_image
;
1243 const gchar
*message
;
1244 gchar
*markup_text
= NULL
;
1246 if (FOLKS_IS_INDIVIDUAL (folks_object
))
1247 table
= G_OBJECT (priv
->individual_table
);
1248 else if (FOLKS_IS_PERSONA (folks_object
))
1249 table
= g_hash_table_lookup (priv
->persona_tables
, folks_object
);
1251 g_assert_not_reached ();
1256 status_label
= g_object_get_data (table
, "status-label");
1257 state_image
= g_object_get_data (table
, "state-image");
1259 /* FIXME: Default messages should be moved into libfolks (bgo#627403) */
1260 message
= folks_presence_details_get_presence_message (
1261 FOLKS_PRESENCE_DETAILS (folks_object
));
1262 if (EMP_STR_EMPTY (message
))
1264 message
= empathy_presence_get_default_message (
1265 folks_presence_details_get_presence_type (
1266 FOLKS_PRESENCE_DETAILS (folks_object
)));
1269 if (message
!= NULL
)
1270 markup_text
= empathy_add_link_markup (message
);
1271 gtk_label_set_markup (GTK_LABEL (status_label
), markup_text
);
1272 g_free (markup_text
);
1274 gtk_image_set_from_icon_name (GTK_IMAGE (state_image
),
1275 empathy_icon_name_for_presence (
1276 folks_presence_details_get_presence_type (
1277 FOLKS_PRESENCE_DETAILS (folks_object
))),
1278 GTK_ICON_SIZE_BUTTON
);
1279 gtk_widget_show (state_image
);
1283 notify_is_favourite_cb (gpointer folks_object
,
1285 EmpathyIndividualWidget
*self
)
1287 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1289 GtkWidget
*favourite_widget
;
1291 if (FOLKS_IS_INDIVIDUAL (folks_object
))
1292 table
= G_OBJECT (priv
->individual_table
);
1293 else if (FOLKS_IS_PERSONA (folks_object
))
1294 table
= g_hash_table_lookup (priv
->persona_tables
, folks_object
);
1296 g_assert_not_reached ();
1301 favourite_widget
= g_object_get_data (table
, "favourite-widget");
1303 if (GTK_IS_TOGGLE_BUTTON (favourite_widget
))
1305 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (favourite_widget
),
1306 folks_favourite_details_get_is_favourite (
1307 FOLKS_FAVOURITE_DETAILS (folks_object
)));
1312 alias_presence_avatar_favourite_set_up (EmpathyIndividualWidget
*self
,
1316 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1317 GtkWidget
*label
, *alias
, *image
, *avatar
, *alignment
;
1318 guint current_row
= starting_row
;
1321 label
= gtk_label_new (_("Alias:"));
1322 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1323 gtk_table_attach (table
, label
, 0, 1, current_row
, current_row
+ 1, GTK_FILL
,
1325 gtk_widget_show (label
);
1327 /* Set up alias label/entry */
1328 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_EDIT_ALIAS
)
1330 alias
= gtk_entry_new ();
1332 g_signal_connect (alias
, "focus-out-event",
1333 (GCallback
) entry_alias_focus_event_cb
, self
);
1335 /* Make return activate the window default (the Close button) */
1336 gtk_entry_set_activates_default (GTK_ENTRY (alias
), TRUE
);
1340 alias
= gtk_label_new (NULL
);
1341 gtk_label_set_selectable (GTK_LABEL (alias
),
1342 (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_FOR_TOOLTIP
) ? FALSE
: TRUE
);
1343 gtk_misc_set_alignment (GTK_MISC (alias
), 0.0, 0.5);
1346 g_object_set_data (G_OBJECT (table
), "alias-widget", alias
);
1347 gtk_table_attach (table
, alias
, 1, 2, current_row
, current_row
+ 1,
1348 GTK_FILL
| GTK_EXPAND
, GTK_FILL
, 0, 0);
1349 gtk_widget_show (alias
);
1354 priv
->hbox_presence
= gtk_hbox_new (FALSE
, 6);
1356 /* Presence image */
1357 image
= gtk_image_new_from_stock (GTK_STOCK_MISSING_IMAGE
,
1358 GTK_ICON_SIZE_BUTTON
);
1359 g_object_set_data (G_OBJECT (table
), "state-image", image
);
1360 gtk_box_pack_start (GTK_BOX (priv
->hbox_presence
), image
, FALSE
,
1362 gtk_widget_show (image
);
1364 label
= gtk_label_new ("");
1365 gtk_label_set_line_wrap_mode (GTK_LABEL (label
), PANGO_WRAP_WORD_CHAR
);
1366 gtk_label_set_line_wrap (GTK_LABEL (label
), TRUE
);
1367 gtk_misc_set_alignment (GTK_MISC (label
), 0, 0.5);
1369 gtk_label_set_selectable (GTK_LABEL (label
),
1370 (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_FOR_TOOLTIP
) ? FALSE
: TRUE
);
1372 g_object_set_data (G_OBJECT (table
), "status-label", label
);
1373 gtk_box_pack_start (GTK_BOX (priv
->hbox_presence
), label
, TRUE
,
1375 gtk_widget_show (label
);
1377 gtk_table_attach (table
, priv
->hbox_presence
, 0, 2, current_row
,
1378 current_row
+ 1, GTK_FILL
| GTK_EXPAND
, GTK_FILL
, 0, 0);
1379 gtk_widget_show (priv
->hbox_presence
);
1383 /* Set up favourite toggle button */
1384 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_EDIT_FAVOURITE
)
1386 GtkWidget
*favourite
= gtk_check_button_new_with_label (_("Favorite"));
1388 g_signal_connect (favourite
, "toggled",
1389 (GCallback
) favourite_toggled_cb
, self
);
1391 g_object_set_data (G_OBJECT (table
), "favourite-widget", favourite
);
1392 gtk_table_attach (table
, favourite
, 0, 2, current_row
, current_row
+ 1,
1393 GTK_FILL
| GTK_EXPAND
, GTK_FILL
, 0, 0);
1394 gtk_widget_show (favourite
);
1399 /* Set up avatar display */
1400 avatar
= empathy_avatar_image_new ();
1402 if (!(priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_FOR_TOOLTIP
))
1404 g_signal_connect (avatar
, "popup-menu",
1405 (GCallback
) avatar_widget_popup_menu_cb
, self
);
1406 g_signal_connect (avatar
, "button-press-event",
1407 (GCallback
) avatar_widget_button_press_event_cb
, self
);
1410 g_object_set_data (G_OBJECT (table
), "avatar-widget", avatar
);
1412 alignment
= gtk_alignment_new (1.0, 0.0, 0.0, 0.0);
1413 gtk_container_add (GTK_CONTAINER (alignment
), avatar
);
1414 gtk_widget_show (avatar
);
1416 gtk_table_attach (table
, alignment
, 2, 3, 0, current_row
,
1417 GTK_FILL
| GTK_EXPAND
, GTK_FILL
| GTK_EXPAND
, 6, 6);
1418 gtk_widget_show (alignment
);
1422 update_persona (EmpathyIndividualWidget
*self
, FolksPersona
*persona
)
1424 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1425 TpContact
*tp_contact
;
1426 EmpathyContact
*contact
;
1433 table
= g_hash_table_lookup (priv
->persona_tables
, persona
);
1435 g_assert (table
!= NULL
);
1437 tp_contact
= tpf_persona_get_contact (TPF_PERSONA (persona
));
1438 contact
= empathy_contact_dup_from_tp_contact (tp_contact
);
1439 empathy_contact_set_persona (contact
, persona
);
1441 account
= empathy_contact_get_account (contact
);
1443 /* Update account widget */
1444 if (account
!= NULL
)
1448 label
= g_object_get_data (G_OBJECT (table
), "account-label");
1449 image
= g_object_get_data (G_OBJECT (table
), "account-image");
1451 name
= tp_account_get_display_name (account
);
1452 gtk_label_set_label (label
, name
);
1454 name
= tp_account_get_icon_name (account
);
1455 gtk_image_set_from_icon_name (image
, name
, GTK_ICON_SIZE_MENU
);
1458 /* Update id widget */
1459 label
= g_object_get_data (G_OBJECT (table
), "id-widget");
1460 id
= folks_persona_get_display_id (persona
);
1461 gtk_label_set_label (label
, (id
!= NULL
) ? id
: "");
1463 /* Update other widgets */
1464 notify_alias_cb (persona
, NULL
, self
);
1465 notify_presence_cb (persona
, NULL
, self
);
1466 notify_avatar_cb (persona
, NULL
, self
);
1468 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_EDIT_FAVOURITE
)
1469 notify_is_favourite_cb (persona
, NULL
, self
);
1471 g_object_unref (contact
);
1475 add_persona (EmpathyIndividualWidget
*self
,
1476 FolksPersona
*persona
)
1478 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1481 GtkWidget
*label
, *account_label
, *account_image
, *separator
;
1482 guint current_row
= 0;
1484 if (!empathy_folks_persona_is_interesting (persona
))
1487 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_EDIT_FAVOURITE
)
1488 table
= GTK_TABLE (gtk_table_new (5, 3, FALSE
));
1490 table
= GTK_TABLE (gtk_table_new (4, 3, FALSE
));
1491 gtk_table_set_row_spacings (table
, 6);
1492 gtk_table_set_col_spacings (table
, 6);
1494 /* Account and Identifier */
1495 label
= gtk_label_new (_("Account:"));
1496 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1497 gtk_table_attach (table
, label
, 0, 1, current_row
, current_row
+ 1,
1498 GTK_FILL
, GTK_FILL
, 0, 0);
1499 gtk_widget_show (label
);
1501 /* Pack the protocol icon with the account name in an hbox */
1502 hbox
= GTK_BOX (gtk_hbox_new (FALSE
, 6));
1504 account_label
= gtk_label_new (NULL
);
1505 gtk_label_set_selectable (GTK_LABEL (account_label
),
1506 (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_FOR_TOOLTIP
) ? FALSE
: TRUE
);
1507 gtk_misc_set_alignment (GTK_MISC (account_label
), 0.0, 0.5);
1508 gtk_widget_show (account_label
);
1510 account_image
= gtk_image_new ();
1511 gtk_widget_show (account_image
);
1513 gtk_box_pack_start (hbox
, account_image
, FALSE
, FALSE
, 0);
1514 gtk_box_pack_start (hbox
, account_label
, FALSE
, TRUE
, 0);
1516 g_object_set_data (G_OBJECT (table
), "account-image", account_image
);
1517 g_object_set_data (G_OBJECT (table
), "account-label", account_label
);
1518 gtk_table_attach (table
, GTK_WIDGET (hbox
), 1, 2, current_row
,
1519 current_row
+ 1, GTK_FILL
| GTK_EXPAND
, GTK_FILL
, 0, 0);
1520 gtk_widget_show (GTK_WIDGET (hbox
));
1524 /* Translators: Identifier to connect to Instant Messaging network */
1525 label
= gtk_label_new (_("Identifier:"));
1526 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1527 gtk_table_attach (table
, label
, 0, 1, current_row
, current_row
+ 1,
1528 GTK_FILL
, GTK_FILL
, 0, 0);
1529 gtk_widget_show (label
);
1531 /* Set up ID label */
1532 label
= gtk_label_new (NULL
);
1533 gtk_label_set_selectable (GTK_LABEL (label
),
1534 (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_FOR_TOOLTIP
) ? FALSE
: TRUE
);
1535 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1537 g_object_set_data (G_OBJECT (table
), "id-widget", label
);
1538 gtk_table_attach (table
, label
, 1, 2, current_row
, current_row
+ 1,
1539 GTK_FILL
| GTK_EXPAND
, GTK_FILL
, 0, 0);
1540 gtk_widget_show (label
);
1544 alias_presence_avatar_favourite_set_up (self
, table
, current_row
);
1546 /* Connect to signals and display the table */
1547 g_signal_connect (persona
, "notify::alias",
1548 (GCallback
) notify_alias_cb
, self
);
1549 g_signal_connect (persona
, "notify::avatar",
1550 (GCallback
) notify_avatar_cb
, self
);
1551 g_signal_connect (persona
, "notify::presence-type",
1552 (GCallback
) notify_presence_cb
, self
);
1553 g_signal_connect (persona
, "notify::presence-message",
1554 (GCallback
) notify_presence_cb
, self
);
1556 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_EDIT_FAVOURITE
)
1558 g_signal_connect (persona
, "notify::is-favourite",
1559 (GCallback
) notify_is_favourite_cb
, self
);
1562 gtk_box_pack_start (GTK_BOX (priv
->vbox_individual
),
1563 GTK_WIDGET (table
), FALSE
, TRUE
, 0);
1564 gtk_widget_show (GTK_WIDGET (table
));
1566 /* Pack a separator after the table */
1567 separator
= gtk_hseparator_new ();
1568 g_object_set_data (G_OBJECT (table
), "separator", separator
);
1569 gtk_box_pack_start (GTK_BOX (priv
->vbox_individual
), separator
, FALSE
, FALSE
,
1571 gtk_widget_show (separator
);
1573 g_hash_table_replace (priv
->persona_tables
, persona
, table
);
1575 /* Update the new widgets */
1576 update_persona (self
, persona
);
1580 remove_persona (EmpathyIndividualWidget
*self
,
1581 FolksPersona
*persona
)
1583 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1584 GtkWidget
*separator
;
1587 if (!empathy_folks_persona_is_interesting (persona
))
1590 table
= g_hash_table_lookup (priv
->persona_tables
, persona
);
1594 g_signal_handlers_disconnect_by_func (persona
, notify_alias_cb
, self
);
1595 g_signal_handlers_disconnect_by_func (persona
, notify_avatar_cb
, self
);
1596 g_signal_handlers_disconnect_by_func (persona
, notify_presence_cb
, self
);
1598 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_EDIT_FAVOURITE
)
1600 g_signal_handlers_disconnect_by_func (persona
, notify_is_favourite_cb
,
1604 /* Remove the separator */
1605 separator
= g_object_get_data (G_OBJECT (table
), "separator");
1606 if (separator
!= NULL
)
1607 gtk_container_remove (GTK_CONTAINER (priv
->vbox_individual
), separator
);
1609 /* Remove the widget */
1610 gtk_container_remove (GTK_CONTAINER (priv
->vbox_individual
),
1611 GTK_WIDGET (table
));
1613 g_hash_table_remove (priv
->persona_tables
, persona
);
1617 update_individual_table (EmpathyIndividualWidget
*self
)
1619 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1621 notify_alias_cb (priv
->individual
, NULL
, self
);
1622 notify_presence_cb (priv
->individual
, NULL
, self
);
1623 notify_avatar_cb (priv
->individual
, NULL
, self
);
1625 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_EDIT_FAVOURITE
)
1626 notify_is_favourite_cb (priv
->individual
, NULL
, self
);
1630 individual_table_set_up (EmpathyIndividualWidget
*self
)
1632 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1634 guint current_row
= 0;
1637 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_EDIT_FAVOURITE
)
1640 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_FOR_TOOLTIP
)
1643 table
= GTK_TABLE (gtk_table_new (nb_rows
, 3, FALSE
));
1644 gtk_table_set_row_spacings (table
, 6);
1645 gtk_table_set_col_spacings (table
, 6);
1647 /* We only display the number of personas in tooltips */
1648 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_FOR_TOOLTIP
)
1654 guint num_personas
= 0;
1656 /* Meta-contacts message displaying how many Telepathy personas we have */
1657 personas
= folks_individual_get_personas (priv
->individual
);
1658 iter
= gee_iterable_iterator (GEE_ITERABLE (personas
));
1659 while (gee_iterator_next (iter
))
1661 FolksPersona
*persona
= gee_iterator_get (iter
);
1662 if (empathy_folks_persona_is_interesting (persona
))
1665 g_clear_object (&persona
);
1667 g_clear_object (&iter
);
1669 /* Translators: the plurality applies to both instances of the word
1671 message
= g_strdup_printf (
1672 ngettext ("Linked contact containing %u contact",
1673 "Linked contacts containing %u contacts", num_personas
),
1675 label
= gtk_label_new (message
);
1676 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1679 gtk_table_attach (table
, label
, 0, 2, current_row
, current_row
+ 1,
1680 GTK_FILL
| GTK_EXPAND
, GTK_FILL
, 0, 0);
1681 gtk_widget_show (label
);
1686 alias_presence_avatar_favourite_set_up (self
, table
, current_row
);
1688 /* Display the table */
1689 gtk_box_pack_start (GTK_BOX (priv
->vbox_individual
), GTK_WIDGET (table
),
1691 gtk_widget_show (GTK_WIDGET (table
));
1693 priv
->individual_table
= table
;
1695 /* Update the table */
1696 update_individual_table (self
);
1700 individual_table_destroy (EmpathyIndividualWidget
*self
)
1702 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1704 if (priv
->individual_table
== NULL
)
1707 gtk_container_remove (GTK_CONTAINER (priv
->vbox_individual
),
1708 GTK_WIDGET (priv
->individual_table
));
1709 priv
->individual_table
= NULL
;
1713 personas_changed_cb (FolksIndividual
*individual
,
1716 EmpathyIndividualWidget
*self
)
1718 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1719 GList
*l
, *children
;
1722 gboolean show_personas
, was_showing_personas
, will_show_personas
, is_last
;
1723 guint old_num_personas
, new_num_personas
= 0;
1725 personas
= folks_individual_get_personas (individual
);
1726 /* we'll re-use this iterator throughout */
1727 iter
= gee_iterable_iterator (GEE_ITERABLE (personas
));
1729 /* Note that old_num_personas is the number of persona tables we were
1730 * displaying, not the number of Personas which were in the Individual
1732 old_num_personas
= g_hash_table_size (priv
->persona_tables
);
1734 while (gee_iterator_next (iter
))
1736 FolksPersona
*persona
= gee_iterator_get (iter
);
1737 if (empathy_folks_persona_is_interesting (persona
))
1740 g_clear_object (&persona
);
1744 * What we display for various conditions:
1745 * - "Personas": display the alias, avatar, presence account and identifier
1746 * for each of the Individual's Personas. (i.e. One table per
1748 * - "Individual": display the alias, avatar and presence for the Individual,
1749 * and a label saying "Meta-contact containing x contacts".
1750 * (i.e. One table in total.)
1752 * | SHOW_PERSONAS | !SHOW_PERSONAS
1753 * -------------+---------------+---------------
1754 * > 1 Persona | Personas | Individual
1755 * -------------+---------------+---------------
1756 * == 1 Persona | Personas | Personas
1758 show_personas
= (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_SHOW_PERSONAS
) != 0;
1759 was_showing_personas
= show_personas
|| old_num_personas
== 1;
1760 will_show_personas
= show_personas
|| new_num_personas
== 1;
1762 /* If both @added and @removed are NULL, we're being called manually, and we
1763 * need to set up the tables for the first time. We do this simply by
1764 * ensuring was_showing_personas and will_show_personas are different so that
1765 * the code resets the UI.
1767 if (added
== NULL
&& removed
== NULL
)
1768 was_showing_personas
= !will_show_personas
;
1770 if (was_showing_personas
&& will_show_personas
)
1772 GeeIterator
*iter_changed
;
1774 /* Remove outdated Personas */
1775 iter_changed
= gee_iterable_iterator (GEE_ITERABLE (removed
));
1776 while (gee_iterator_next (iter_changed
))
1778 FolksPersona
*persona
= gee_iterator_get (iter_changed
);
1779 remove_persona (self
, persona
);
1780 g_clear_object (&persona
);
1782 g_clear_object (&iter_changed
);
1784 /* Add new Personas */
1785 iter_changed
= gee_iterable_iterator (GEE_ITERABLE (added
));
1786 while (gee_iterator_next (iter_changed
))
1788 FolksPersona
*persona
= gee_iterator_get (iter_changed
);
1789 add_persona (self
, persona
);
1790 g_clear_object (&persona
);
1792 g_clear_object (&iter_changed
);
1794 else if (!was_showing_personas
&& will_show_personas
)
1798 /* Remove the old Individual table */
1799 individual_table_destroy (self
);
1801 /* Set up all the Persona tables instead */
1802 for (c
= gee_iterator_first (iter
); c
; c
= gee_iterator_next (iter
))
1804 FolksPersona
*persona
= gee_iterator_get (iter
);
1805 add_persona (self
, persona
);
1806 g_clear_object (&persona
);
1809 else if (was_showing_personas
&& !will_show_personas
)
1813 /* Remove all Personas */
1814 for (c
= gee_iterator_first (iter
); c
; c
= gee_iterator_next (iter
))
1816 FolksPersona
*persona
= gee_iterator_get (iter
);
1817 remove_persona (self
, persona
);
1818 g_clear_object (&persona
);
1821 if (removed
!= NULL
)
1823 GeeIterator
*iter_changed
;
1825 iter_changed
= gee_iterable_iterator (GEE_ITERABLE (removed
));
1826 while (gee_iterator_next (iter_changed
))
1828 FolksPersona
*persona
= gee_iterator_get (iter_changed
);
1829 remove_persona (self
, persona
);
1830 g_clear_object (&persona
);
1832 g_clear_object (&iter_changed
);
1835 /* Set up the Individual table instead */
1836 individual_table_set_up (self
);
1838 g_clear_object (&iter
);
1840 /* Hide the last separator and show the others */
1841 children
= gtk_container_get_children (GTK_CONTAINER (priv
->vbox_individual
));
1842 children
= g_list_reverse (children
);
1845 for (l
= children
; l
!= NULL
; l
= l
->next
)
1847 if (GTK_IS_SEPARATOR (l
->data
))
1849 gtk_widget_set_visible (GTK_WIDGET (l
->data
), !is_last
);
1854 g_list_free (children
);
1858 individual_removed_cb (FolksIndividual
*individual
,
1859 FolksIndividual
*replacement_individual
,
1860 EmpathyIndividualWidget
*self
)
1862 empathy_individual_widget_set_individual (self
, replacement_individual
);
1866 remove_individual (EmpathyIndividualWidget
*self
)
1868 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1869 if (priv
->individual
!= NULL
)
1874 g_signal_handlers_disconnect_by_func (priv
->individual
,
1875 notify_alias_cb
, self
);
1876 g_signal_handlers_disconnect_by_func (priv
->individual
,
1877 notify_presence_cb
, self
);
1878 g_signal_handlers_disconnect_by_func (priv
->individual
,
1879 notify_avatar_cb
, self
);
1880 g_signal_handlers_disconnect_by_func (priv
->individual
,
1881 personas_changed_cb
, self
);
1882 g_signal_handlers_disconnect_by_func (priv
->individual
,
1883 individual_removed_cb
, self
);
1885 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_EDIT_FAVOURITE
)
1887 g_signal_handlers_disconnect_by_func (priv
->individual
,
1888 notify_is_favourite_cb
, self
);
1891 personas
= folks_individual_get_personas (priv
->individual
);
1892 iter
= gee_iterable_iterator (GEE_ITERABLE (personas
));
1893 while (gee_iterator_next (iter
))
1895 FolksPersona
*persona
= gee_iterator_get (iter
);
1896 remove_persona (self
, persona
);
1897 g_clear_object (&persona
);
1899 g_clear_object (&iter
);
1900 individual_table_destroy (self
);
1902 if (priv
->contact
!= NULL
)
1903 remove_weak_contact (self
);
1905 tp_clear_object (&priv
->individual
);
1908 if (priv
->details_cancellable
!= NULL
)
1909 g_cancellable_cancel (priv
->details_cancellable
);
1913 individual_update (EmpathyIndividualWidget
*self
)
1915 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1917 /* Connect and get info from new Individual */
1918 if (priv
->individual
!= NULL
)
1920 g_signal_connect (priv
->individual
, "notify::alias",
1921 (GCallback
) notify_alias_cb
, self
);
1922 g_signal_connect (priv
->individual
, "notify::presence-type",
1923 (GCallback
) notify_presence_cb
, self
);
1924 g_signal_connect (priv
->individual
, "notify::presence-message",
1925 (GCallback
) notify_presence_cb
, self
);
1926 g_signal_connect (priv
->individual
, "notify::avatar",
1927 (GCallback
) notify_avatar_cb
, self
);
1928 g_signal_connect (priv
->individual
, "personas-changed",
1929 (GCallback
) personas_changed_cb
, self
);
1930 g_signal_connect (priv
->individual
, "removed",
1931 (GCallback
) individual_removed_cb
, self
);
1933 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_EDIT_FAVOURITE
)
1935 g_signal_connect (priv
->individual
, "notify::is-favourite",
1936 (GCallback
) notify_is_favourite_cb
, self
);
1939 /* Update individual table */
1940 personas_changed_cb (priv
->individual
, NULL
, NULL
, self
);
1943 if (priv
->individual
== NULL
)
1945 gtk_widget_hide (priv
->vbox_individual
);
1947 else if (priv
->individual_table
!= NULL
)
1949 /* We only need to update the details for the Individual as a whole */
1950 update_individual_table (self
);
1951 gtk_widget_show (priv
->vbox_individual
);
1955 /* We need to update the details for every Persona in the Individual */
1959 personas
= folks_individual_get_personas (priv
->individual
);
1960 iter
= gee_iterable_iterator (GEE_ITERABLE (personas
));
1961 while (gee_iterator_next (iter
))
1963 FolksPersona
*persona
= gee_iterator_get (iter
);
1965 if (empathy_folks_persona_is_interesting (persona
))
1966 update_persona (self
, persona
);
1968 g_clear_object (&persona
);
1970 g_clear_object (&iter
);
1972 gtk_widget_show (priv
->vbox_individual
);
1977 empathy_individual_widget_init (EmpathyIndividualWidget
*self
)
1979 EmpathyIndividualWidgetPriv
*priv
;
1983 priv
= G_TYPE_INSTANCE_GET_PRIVATE (self
,
1984 EMPATHY_TYPE_INDIVIDUAL_WIDGET
, EmpathyIndividualWidgetPriv
);
1987 gtk_orientable_set_orientation (GTK_ORIENTABLE (self
),
1988 GTK_ORIENTATION_VERTICAL
);
1990 filename
= empathy_file_lookup ("empathy-individual-widget.ui",
1992 gui
= empathy_builder_get_file (filename
,
1993 "scrolled_window_individual", &priv
->scrolled_window_individual
,
1994 "viewport_individual", &priv
->viewport_individual
,
1995 "vbox_individual_widget", &priv
->vbox_individual_widget
,
1996 "vbox_individual", &priv
->vbox_individual
,
1997 "vbox_location", &priv
->vbox_location
,
1998 "subvbox_location", &priv
->subvbox_location
,
1999 "label_location", &priv
->label_location
,
2000 #ifdef HAVE_LIBCHAMPLAIN
2001 "viewport_map", &priv
->viewport_map
,
2003 "groups_widget", &priv
->groups_widget
,
2004 "vbox_details", &priv
->vbox_details
,
2005 "table_details", &priv
->table_details
,
2006 "hbox_details_requested", &priv
->hbox_details_requested
,
2007 "hbox_client_types", &priv
->hbox_client_types
,
2011 priv
->table_location
= NULL
;
2013 gtk_box_pack_start (GTK_BOX (self
), priv
->vbox_individual_widget
, TRUE
, TRUE
,
2015 gtk_widget_show (priv
->vbox_individual_widget
);
2017 priv
->persona_tables
= g_hash_table_new (NULL
, NULL
);
2018 priv
->individual_table
= NULL
;
2020 /* Create widgets */
2021 details_set_up (self
);
2023 g_object_unref (gui
);
2027 constructed (GObject
*object
)
2029 GObjectClass
*klass
= G_OBJECT_CLASS (empathy_individual_widget_parent_class
);
2030 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (object
);
2031 GtkScrolledWindow
*scrolled_window
=
2032 GTK_SCROLLED_WINDOW (priv
->scrolled_window_individual
);
2034 /* Allow scrolling of the list of Personas if we're showing Personas. */
2035 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_SHOW_PERSONAS
)
2037 gtk_scrolled_window_set_shadow_type (scrolled_window
, GTK_SHADOW_IN
);
2038 gtk_scrolled_window_set_policy (scrolled_window
,
2039 GTK_POLICY_NEVER
, GTK_POLICY_AUTOMATIC
);
2040 gtk_box_set_child_packing (GTK_BOX (priv
->vbox_individual_widget
),
2041 priv
->scrolled_window_individual
, TRUE
, TRUE
, 0, GTK_PACK_START
);
2043 gtk_container_set_border_width (GTK_CONTAINER (priv
->viewport_individual
),
2045 gtk_widget_set_size_request (GTK_WIDGET (scrolled_window
), -1, 100);
2049 gtk_scrolled_window_set_shadow_type (scrolled_window
, GTK_SHADOW_NONE
);
2050 gtk_scrolled_window_set_policy (scrolled_window
,
2051 GTK_POLICY_NEVER
, GTK_POLICY_NEVER
);
2052 gtk_box_set_child_packing (GTK_BOX (priv
->vbox_individual_widget
),
2053 priv
->scrolled_window_individual
, FALSE
, TRUE
, 0, GTK_PACK_START
);
2055 gtk_container_set_border_width (GTK_CONTAINER (priv
->viewport_individual
),
2060 if (klass
->constructed
!= NULL
)
2061 klass
->constructed (object
);
2065 get_property (GObject
*object
,
2070 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (object
);
2074 case PROP_INDIVIDUAL
:
2075 g_value_set_object (value
, priv
->individual
);
2078 g_value_set_flags (value
, priv
->flags
);
2081 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
2087 set_property (GObject
*object
,
2089 const GValue
*value
,
2092 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (object
);
2096 case PROP_INDIVIDUAL
:
2097 empathy_individual_widget_set_individual (
2098 EMPATHY_INDIVIDUAL_WIDGET (object
), g_value_get_object (value
));
2101 priv
->flags
= g_value_get_flags (value
);
2104 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
2110 dispose (GObject
*object
)
2112 remove_individual (EMPATHY_INDIVIDUAL_WIDGET (object
));
2114 G_OBJECT_CLASS (empathy_individual_widget_parent_class
)->dispose (object
);
2118 finalize (GObject
*object
)
2120 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (object
);
2122 g_hash_table_destroy (priv
->persona_tables
);
2124 G_OBJECT_CLASS (empathy_individual_widget_parent_class
)->finalize (object
);
2128 empathy_individual_widget_class_init (EmpathyIndividualWidgetClass
*klass
)
2130 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
2132 object_class
->constructed
= constructed
;
2133 object_class
->get_property
= get_property
;
2134 object_class
->set_property
= set_property
;
2135 object_class
->dispose
= dispose
;
2136 object_class
->finalize
= finalize
;
2139 * EmpathyIndividualWidget:individual:
2141 * The #FolksIndividual to display in the widget.
2143 g_object_class_install_property (object_class
, PROP_INDIVIDUAL
,
2144 g_param_spec_object ("individual",
2146 "The #FolksIndividual to display in the widget.",
2147 FOLKS_TYPE_INDIVIDUAL
,
2148 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
));
2151 * EmpathyIndividualWidget:flags:
2153 * A set of flags which affect the widget's behaviour.
2155 g_object_class_install_property (object_class
, PROP_FLAGS
,
2156 g_param_spec_flags ("flags",
2158 "A set of flags which affect the widget's behaviour.",
2159 EMPATHY_TYPE_INDIVIDUAL_WIDGET_FLAGS
,
2160 EMPATHY_INDIVIDUAL_WIDGET_NONE
,
2161 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
| G_PARAM_CONSTRUCT_ONLY
));
2163 g_type_class_add_private (object_class
, sizeof (EmpathyIndividualWidgetPriv
));
2167 * empathy_individual_widget_new:
2168 * @individual: the #FolksIndividual to display
2169 * @flags: flags affecting how the widget behaves and what it displays
2171 * Creates a new #EmpathyIndividualWidget.
2173 * Return value: a new #EmpathyIndividualWidget
2176 empathy_individual_widget_new (FolksIndividual
*individual
,
2177 EmpathyIndividualWidgetFlags flags
)
2179 g_return_val_if_fail (individual
== NULL
|| FOLKS_IS_INDIVIDUAL (individual
),
2182 return g_object_new (EMPATHY_TYPE_INDIVIDUAL_WIDGET
,
2183 "individual", individual
,
2189 * empathy_individual_widget_get_individual:
2190 * @self: an #EmpathyIndividualWidget
2192 * Returns the #FolksIndividual being displayed by the widget.
2194 * Return value: the #FolksIndividual being displayed, or %NULL
2197 empathy_individual_widget_get_individual (EmpathyIndividualWidget
*self
)
2199 g_return_val_if_fail (EMPATHY_IS_INDIVIDUAL_WIDGET (self
), NULL
);
2201 return GET_PRIV (self
)->individual
;
2205 * empathy_individual_widget_set_individual:
2206 * @self: an #EmpathyIndividualWidget
2207 * @individual: the #FolksIndividual to display, or %NULL
2209 * Set the #FolksIndividual to be displayed by the widget:
2210 * #EmpathyIndividualWidget:individual.
2212 * The @individual may be %NULL in order to display nothing in the widget.
2215 empathy_individual_widget_set_individual (EmpathyIndividualWidget
*self
,
2216 FolksIndividual
*individual
)
2218 EmpathyIndividualWidgetPriv
*priv
;
2220 g_return_if_fail (EMPATHY_IS_INDIVIDUAL_WIDGET (self
));
2221 g_return_if_fail (individual
== NULL
|| FOLKS_IS_INDIVIDUAL (individual
));
2223 priv
= GET_PRIV (self
);
2225 if (individual
== priv
->individual
)
2228 /* Out with the old… */
2229 remove_individual (self
);
2231 /* …and in with the new. */
2232 if (individual
!= NULL
)
2233 g_object_ref (individual
);
2234 priv
->individual
= individual
;
2236 /* Update information for widgets */
2237 individual_update (self
);
2238 groups_update (self
);
2239 details_update (self
);
2240 location_update (self
);
2241 client_types_update (self
);