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>
23 #include "empathy-individual-widget.h"
25 #include <glib/gi18n-lib.h>
26 #include <tp-account-widgets/tpaw-builder.h>
27 #include <tp-account-widgets/tpaw-contactinfo-utils.h>
28 #include <tp-account-widgets/tpaw-time.h>
29 #include <tp-account-widgets/tpaw-utils.h>
30 #include <telepathy-glib/telepathy-glib-dbus.h>
32 #ifdef HAVE_LIBCHAMPLAIN
33 #include <champlain/champlain.h>
34 #include <champlain-gtk/champlain-gtk.h>
37 #include "empathy-avatar-image.h"
38 #include "empathy-groups-widget.h"
39 #include "empathy-gtk-enum-types.h"
40 #include "empathy-location.h"
41 #include "empathy-request-util.h"
42 #include "empathy-ui-utils.h"
43 #include "empathy-utils.h"
45 #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT
46 #include "empathy-debug.h"
49 * SECTION:empathy-individual-widget
50 * @title:EmpathyIndividualWidget
51 * @short_description: A widget used to display and edit details about an
53 * @include: libempathy-empathy-individual-widget.h
55 * #EmpathyIndividualWidget is a widget which displays appropriate widgets
56 * with details about an individual, also allowing changing these details,
61 * EmpathyIndividualWidget:
62 * @parent: parent object
64 * Widget which displays appropriate widgets with details about an individual,
65 * also allowing changing these details, if desired.
68 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyIndividualWidget)
71 FolksIndividual
*individual
; /* owned */
72 EmpathyIndividualWidgetFlags flags
;
74 /* weak pointer to the contact whose contact details we're displaying */
77 /* unowned Persona (borrowed from priv->individual) -> GtkGrid child */
78 GHashTable
*persona_grids
;
79 /* Table containing the information for the individual as whole, or NULL */
80 GtkGrid
*individual_grid
;
83 GtkWidget
*hbox_presence
;
84 GtkWidget
*vbox_individual_widget
;
85 GtkWidget
*scrolled_window_individual
;
86 GtkWidget
*viewport_individual
;
87 GtkWidget
*vbox_individual
;
90 GtkWidget
*vbox_location
;
91 GtkWidget
*subvbox_location
;
92 GtkWidget
*grid_location
;
93 GtkWidget
*label_location
;
94 #ifdef HAVE_LIBCHAMPLAIN
95 GtkWidget
*viewport_map
;
96 GtkWidget
*map_view_embed
;
97 ChamplainView
*map_view
;
101 GtkWidget
*groups_widget
;
104 GtkWidget
*hbox_client_types
;
107 GtkWidget
*vbox_details
;
108 GtkWidget
*grid_details
;
109 GtkWidget
*hbox_details_requested
;
110 GtkWidget
*details_spinner
;
111 GCancellable
*details_cancellable
; /* owned */
112 } EmpathyIndividualWidgetPriv
;
114 G_DEFINE_TYPE (EmpathyIndividualWidget
, empathy_individual_widget
,
122 static void client_types_update (EmpathyIndividualWidget
*self
);
123 static void remove_weak_contact (EmpathyIndividualWidget
*self
);
126 details_set_up (EmpathyIndividualWidget
*self
)
128 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
130 gtk_widget_hide (priv
->vbox_details
);
132 priv
->details_spinner
= gtk_spinner_new ();
133 gtk_box_pack_end (GTK_BOX (priv
->hbox_details_requested
),
134 priv
->details_spinner
, TRUE
, TRUE
, 0);
135 gtk_widget_show (priv
->details_spinner
);
139 client_types_notify_cb (TpContact
*contact
,
141 EmpathyIndividualWidget
*self
)
143 client_types_update (self
);
147 EmpathyIndividualWidget
*widget
; /* weak */
148 TpContact
*contact
; /* owned */
152 update_weak_contact (EmpathyIndividualWidget
*self
)
154 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
155 TpContact
*tp_contact
= NULL
;
157 remove_weak_contact (self
);
159 if (priv
->individual
!= NULL
)
161 /* FIXME: We take the most available TpContact we find and only
162 * use its details. It would be a lot better if we would get the
163 * details for every TpContact in the Individual and merge them
164 * all, but that requires vCard support in libfolks for it to
165 * not be hideously complex. (bgo#627399) */
168 FolksPresenceType presence_type
= FOLKS_PRESENCE_TYPE_UNSET
;
170 personas
= folks_individual_get_personas (priv
->individual
);
171 iter
= gee_iterable_iterator (GEE_ITERABLE (personas
));
172 while (gee_iterator_next (iter
))
174 FolksPersona
*persona
= gee_iterator_get (iter
);
176 /* We only want personas which have presence and a TpContact */
177 if (empathy_folks_persona_is_interesting (FOLKS_PERSONA (persona
)))
179 FolksPresenceDetails
*presence
;
180 FolksPresenceType presence_type_cur
;
182 presence
= FOLKS_PRESENCE_DETAILS (persona
);
183 presence_type_cur
= folks_presence_details_get_presence_type (
186 if (tp_contact
== NULL
|| folks_presence_details_typecmp (
187 presence_type_cur
, presence_type
) > 0)
189 presence_type
= presence_type_cur
;
190 tp_contact
= tpf_persona_get_contact (TPF_PERSONA (persona
));
194 g_clear_object (&persona
);
196 g_clear_object (&iter
);
199 if (tp_contact
!= NULL
)
201 priv
->contact
= tp_contact
;
202 g_object_add_weak_pointer (G_OBJECT (tp_contact
),
203 (gpointer
*) &priv
->contact
);
205 g_signal_connect (priv
->contact
, "notify::client-types",
206 (GCallback
) client_types_notify_cb
, self
);
211 add_row (GtkGrid
*grid
,
216 gtk_grid_attach (grid
, title
, 0, row
, 1, 1);
217 gtk_misc_set_alignment (GTK_MISC (title
), 0, 0.5);
218 gtk_widget_show (title
);
220 gtk_grid_attach (grid
, value
, 1, row
, 1, 1);
221 gtk_misc_set_alignment (GTK_MISC (value
), 0, 0.5);
222 gtk_widget_show (value
);
226 channel_name_activated_cb (
231 empathy_join_muc (account
, uri
, empathy_get_current_action_time ());
236 create_channel_list_label (TpAccount
*account
,
240 GtkWidget
*label
= NULL
;
241 GString
*label_markup
= g_string_new ("");
246 /* Is there channels? */
247 channels
= g_ptr_array_new ();
249 for (l
= info
; l
!= NULL
; l
= l
->next
)
251 TpContactInfoField
*field
= l
->data
;
253 if (!tp_strdiff (field
->field_name
, "x-irc-channel"))
254 g_ptr_array_add (channels
, (gpointer
) field
->field_value
[0]);
257 if (channels
->len
== 0)
260 for (i
= 0; i
< channels
->len
; i
++)
262 const gchar
*channel_name
= g_ptr_array_index (channels
, i
);
263 /* We abuse the URI of the link to hold the channel name. It seems to
264 * be okay to just use it essentially verbatim, rather than trying to
265 * ensure it's actually a valid URI. */
266 gchar
*escaped
= g_markup_escape_text (channel_name
, -1);
269 g_string_append (label_markup
, ", ");
271 g_string_append_printf (label_markup
, "<a href='%s'>%s</a>",
276 label
= gtk_label_new (NULL
);
277 gtk_label_set_markup (GTK_LABEL (label
), label_markup
->str
);
278 gtk_label_set_line_wrap (GTK_LABEL (label
), TRUE
);
280 g_signal_connect (label
, "activate-link",
281 (GCallback
) channel_name_activated_cb
, account
);
284 g_ptr_array_unref (channels
);
285 g_string_free (label_markup
, TRUE
);
290 details_update_show (EmpathyIndividualWidget
*self
,
293 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
296 GtkWidget
*channels_label
;
300 info
= tp_contact_dup_contact_info (contact
);
301 info
= g_list_sort (info
, (GCompareFunc
) tpaw_contact_info_field_cmp
);
302 for (l
= info
; l
!= NULL
; l
= l
->next
)
304 TpContactInfoField
*field
= l
->data
;
307 TpawContactInfoFormatFunc format
;
308 GtkWidget
*title_widget
, *value_widget
;
310 if (field
->field_value
== NULL
|| field
->field_value
[0] == NULL
)
313 value
= field
->field_value
[0];
315 if (!tpaw_contact_info_lookup_field (field
->field_name
,
318 DEBUG ("Unhandled ContactInfo field: %s", field
->field_name
);
322 /* Skip empty field */
323 if (tp_str_empty (value
))
327 title
= tpaw_contact_info_field_label (field
->field_name
,
328 field
->parameters
, TRUE
);
329 title_widget
= gtk_label_new (title
);
332 value_widget
= gtk_label_new (value
);
338 markup
= format (field
->field_value
);
339 gtk_label_set_markup (GTK_LABEL (value_widget
), markup
);
343 gtk_label_set_selectable (GTK_LABEL (value_widget
),
344 (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_FOR_TOOLTIP
) ? FALSE
: TRUE
);
346 add_row (GTK_GRID (priv
->grid_details
), n_rows
, title_widget
,
352 conn
= tp_contact_get_connection (contact
);
353 account
= tp_connection_get_account (conn
);
355 channels_label
= create_channel_list_label (account
, info
, n_rows
);
357 if (channels_label
!= NULL
)
359 GtkWidget
*title_widget
;
361 title_widget
= gtk_label_new (_("Channels:"));
363 add_row (GTK_GRID (priv
->grid_details
), n_rows
, title_widget
,
369 tp_contact_info_list_free (info
);
375 details_notify_cb (TpContact
*contact
,
377 EmpathyIndividualWidget
*self
)
379 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
382 gtk_container_foreach (GTK_CONTAINER (priv
->grid_details
),
383 (GtkCallback
) gtk_widget_destroy
, NULL
);
385 n_rows
= details_update_show (self
, contact
);
389 gtk_widget_show (priv
->vbox_details
);
390 gtk_widget_show (priv
->grid_details
);
394 gtk_widget_hide (priv
->vbox_details
);
397 gtk_widget_hide (priv
->hbox_details_requested
);
398 gtk_spinner_stop (GTK_SPINNER (priv
->details_spinner
));
402 details_request_cb (GObject
*source
,
406 EmpathyIndividualWidget
*self
= user_data
;
407 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
408 TpContact
*contact
= (TpContact
*) source
;
409 gboolean hide_widget
= FALSE
;
410 GError
*error
= NULL
;
412 if (tp_contact_request_contact_info_finish (contact
, res
, &error
) == TRUE
)
414 details_notify_cb (contact
, NULL
, self
);
418 /* If the request got cancelled it could mean the contact widget is
419 * destroyed, so we should not dereference information */
420 if (g_error_matches (error
, G_IO_ERROR
, G_IO_ERROR_CANCELLED
))
422 g_error_free (error
);
427 g_error_free (error
);
430 if (hide_widget
== TRUE
)
431 gtk_widget_hide (GET_PRIV (self
)->vbox_details
);
433 tp_clear_object (&priv
->details_cancellable
);
435 tp_g_signal_connect_object (contact
, "notify::contact-info",
436 (GCallback
) details_notify_cb
, self
, 0);
440 fetch_contact_information (EmpathyIndividualWidget
*self
)
442 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
443 TpConnection
*connection
;
445 connection
= tp_contact_get_connection (priv
->contact
);
447 if (!tp_proxy_has_interface_by_id (connection
,
448 TP_IFACE_QUARK_CONNECTION_INTERFACE_CONTACT_INFO
))
450 gtk_widget_hide (GET_PRIV (self
)->vbox_details
);
454 /* Request the Individual's info */
455 gtk_widget_show (priv
->vbox_details
);
456 gtk_widget_show (priv
->hbox_details_requested
);
457 gtk_widget_hide (priv
->grid_details
);
458 gtk_spinner_start (GTK_SPINNER (priv
->details_spinner
));
460 if (priv
->details_cancellable
== NULL
)
462 priv
->details_cancellable
= g_cancellable_new ();
464 tp_contact_request_contact_info_async (priv
->contact
,
465 priv
->details_cancellable
, details_request_cb
, self
);
470 details_update (EmpathyIndividualWidget
*self
)
472 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
474 if (!(priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_SHOW_DETAILS
))
477 gtk_widget_hide (priv
->vbox_details
);
479 if (priv
->contact
== NULL
)
480 update_weak_contact (self
);
482 if (priv
->contact
!= NULL
)
484 fetch_contact_information (self
);
489 groups_update (EmpathyIndividualWidget
*self
)
491 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
493 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_EDIT_GROUPS
&&
494 priv
->individual
!= NULL
)
496 empathy_groups_widget_set_group_details (
497 EMPATHY_GROUPS_WIDGET (priv
->groups_widget
),
498 FOLKS_GROUP_DETAILS (priv
->individual
));
499 gtk_widget_show (priv
->groups_widget
);
503 gtk_widget_hide (priv
->groups_widget
);
507 /* Converts the Location's GHashTable's key to a user readable string */
509 location_key_to_label (const gchar
*key
)
511 if (tp_strdiff (key
, EMPATHY_LOCATION_COUNTRY_CODE
) == FALSE
)
512 return _("Country ISO Code:");
513 else if (tp_strdiff (key
, EMPATHY_LOCATION_COUNTRY
) == FALSE
)
514 return _("Country:");
515 else if (tp_strdiff (key
, EMPATHY_LOCATION_REGION
) == FALSE
)
517 else if (tp_strdiff (key
, EMPATHY_LOCATION_LOCALITY
) == FALSE
)
519 else if (tp_strdiff (key
, EMPATHY_LOCATION_AREA
) == FALSE
)
521 else if (tp_strdiff (key
, EMPATHY_LOCATION_POSTAL_CODE
) == FALSE
)
522 return _("Postal Code:");
523 else if (tp_strdiff (key
, EMPATHY_LOCATION_STREET
) == FALSE
)
525 else if (tp_strdiff (key
, EMPATHY_LOCATION_BUILDING
) == FALSE
)
526 return _("Building:");
527 else if (tp_strdiff (key
, EMPATHY_LOCATION_FLOOR
) == FALSE
)
529 else if (tp_strdiff (key
, EMPATHY_LOCATION_ROOM
) == FALSE
)
531 else if (tp_strdiff (key
, EMPATHY_LOCATION_TEXT
) == FALSE
)
533 else if (tp_strdiff (key
, EMPATHY_LOCATION_DESCRIPTION
) == FALSE
)
534 return _("Description:");
535 else if (tp_strdiff (key
, EMPATHY_LOCATION_URI
) == FALSE
)
537 else if (tp_strdiff (key
, EMPATHY_LOCATION_ACCURACY_LEVEL
) == FALSE
)
538 return _("Accuracy Level:");
539 else if (tp_strdiff (key
, EMPATHY_LOCATION_ERROR
) == FALSE
)
541 else if (tp_strdiff (key
, EMPATHY_LOCATION_VERTICAL_ERROR_M
) == FALSE
)
542 return _("Vertical Error (meters):");
543 else if (tp_strdiff (key
, EMPATHY_LOCATION_HORIZONTAL_ERROR_M
) == FALSE
)
544 return _("Horizontal Error (meters):");
545 else if (tp_strdiff (key
, EMPATHY_LOCATION_SPEED
) == FALSE
)
547 else if (tp_strdiff (key
, EMPATHY_LOCATION_BEARING
) == FALSE
)
548 return _("Bearing:");
549 else if (tp_strdiff (key
, EMPATHY_LOCATION_CLIMB
) == FALSE
)
550 return _("Climb Speed:");
551 else if (tp_strdiff (key
, EMPATHY_LOCATION_TIMESTAMP
) == FALSE
)
552 return _("Last Updated on:");
553 else if (tp_strdiff (key
, EMPATHY_LOCATION_LON
) == FALSE
)
554 return _("Longitude:");
555 else if (tp_strdiff (key
, EMPATHY_LOCATION_LAT
) == FALSE
)
556 return _("Latitude:");
557 else if (tp_strdiff (key
, EMPATHY_LOCATION_ALT
) == FALSE
)
558 return _("Altitude:");
561 DEBUG ("Unexpected Location key: %s", key
);
567 location_update (EmpathyIndividualWidget
*self
)
569 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
570 EmpathyContact
*contact
= NULL
;
571 GHashTable
*location
= NULL
;
575 static const gchar
* ordered_geolocation_keys
[] = {
576 EMPATHY_LOCATION_TEXT
,
577 EMPATHY_LOCATION_URI
,
578 EMPATHY_LOCATION_DESCRIPTION
,
579 EMPATHY_LOCATION_BUILDING
,
580 EMPATHY_LOCATION_FLOOR
,
581 EMPATHY_LOCATION_ROOM
,
582 EMPATHY_LOCATION_STREET
,
583 EMPATHY_LOCATION_AREA
,
584 EMPATHY_LOCATION_LOCALITY
,
585 EMPATHY_LOCATION_REGION
,
586 EMPATHY_LOCATION_COUNTRY
,
591 gboolean display_map
= FALSE
;
595 if (!(priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_SHOW_LOCATION
) ||
596 priv
->individual
== NULL
)
598 gtk_widget_hide (priv
->vbox_location
);
602 /* FIXME: For the moment, we just display the first location data we can
603 * find amongst the Individual's Personas. Once libfolks grows a location
604 * interface, we can use that. (bgo#627400) */
606 personas
= folks_individual_get_personas (priv
->individual
);
607 iter
= gee_iterable_iterator (GEE_ITERABLE (personas
));
608 while (location
== NULL
&& gee_iterator_next (iter
))
610 FolksPersona
*persona
= gee_iterator_get (iter
);
612 if (empathy_folks_persona_is_interesting (persona
))
614 TpContact
*tp_contact
;
616 /* Get the contact. If it turns out to have location information, we
617 * have to keep it alive for the duration of the function, since we're
618 * accessing its private data. */
619 tp_contact
= tpf_persona_get_contact (TPF_PERSONA (persona
));
620 if (tp_contact
!= NULL
)
622 contact
= empathy_contact_dup_from_tp_contact (tp_contact
);
623 empathy_contact_set_persona (contact
, persona
);
625 /* Try and get a location */
626 location
= empathy_contact_get_location (contact
);
627 /* if location isn't fully valid, treat the contact as
629 if (location
!= NULL
&& g_hash_table_size (location
) <= 0)
632 g_clear_object (&contact
);
636 g_clear_object (&persona
);
638 g_clear_object (&iter
);
640 if (contact
== NULL
|| location
== NULL
)
642 gtk_widget_hide (priv
->vbox_location
);
643 tp_clear_object (&contact
);
647 value
= g_hash_table_lookup (location
, EMPATHY_LOCATION_TIMESTAMP
);
650 gchar
*loc
= g_strdup_printf ("<b>%s</b>", _("Location"));
651 gtk_label_set_markup (GTK_LABEL (priv
->label_location
), loc
);
661 stamp
= g_value_get_int64 (value
);
663 user_date
= tpaw_time_to_string_relative (stamp
);
665 tmp
= g_strdup_printf ("<b>%s</b>", _("Location"));
666 /* translators: format is "Location, $date" */
667 text
= g_strdup_printf (_("%s, %s"), tmp
, user_date
);
669 gtk_label_set_markup (GTK_LABEL (priv
->label_location
), text
);
674 /* Prepare the location information table */
675 if (priv
->grid_location
!= NULL
)
676 gtk_widget_destroy (priv
->grid_location
);
678 priv
->grid_location
= gtk_grid_new ();
679 gtk_box_pack_start (GTK_BOX (priv
->subvbox_location
),
680 priv
->grid_location
, FALSE
, FALSE
, 5);
683 for (i
= 0; (skey
= ordered_geolocation_keys
[i
]); i
++)
685 const gchar
* user_label
;
689 gvalue
= g_hash_table_lookup (location
, (gpointer
) skey
);
693 user_label
= location_key_to_label (skey
);
695 label
= gtk_label_new (user_label
);
696 gtk_misc_set_alignment (GTK_MISC (label
), 0, 0.5);
697 gtk_grid_attach (GTK_GRID (priv
->grid_location
),
698 label
, 0, row
, 1, 1);
699 gtk_widget_show (label
);
701 if (G_VALUE_TYPE (gvalue
) == G_TYPE_DOUBLE
)
704 dvalue
= g_value_get_double (gvalue
);
705 svalue
= g_strdup_printf ("%f", dvalue
);
707 else if (G_VALUE_TYPE (gvalue
) == G_TYPE_STRING
)
709 svalue
= g_value_dup_string (gvalue
);
711 else if (G_VALUE_TYPE (gvalue
) == G_TYPE_INT64
)
715 time_
= g_value_get_int64 (value
);
716 svalue
= tpaw_time_to_string_utc (time_
, _("%B %e, %Y at %R UTC"));
721 label
= gtk_label_new (svalue
);
722 gtk_grid_attach (GTK_GRID (priv
->grid_location
),
723 label
, 1, row
, 1, 1);
724 gtk_misc_set_alignment (GTK_MISC (label
), 0, 0);
725 gtk_widget_show (label
);
727 gtk_label_set_selectable (GTK_LABEL (label
),
728 (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_FOR_TOOLTIP
) ? FALSE
:
736 tp_clear_object (&contact
);
738 #ifdef HAVE_LIBCHAMPLAIN
739 if ((g_hash_table_lookup (location
, EMPATHY_LOCATION_LAT
) != NULL
) &&
740 (g_hash_table_lookup (location
, EMPATHY_LOCATION_LON
) != NULL
))
742 /* Cannot be displayed in tooltips until Clutter-Gtk can deal with such
750 /* We can display some fields */
751 gtk_widget_show (priv
->grid_location
);
753 else if (display_map
== FALSE
)
755 /* Can't display either fields or map */
756 gtk_widget_hide (priv
->vbox_location
);
760 #ifdef HAVE_LIBCHAMPLAIN
761 if (display_map
== TRUE
)
763 ChamplainMarkerLayer
*layer
;
765 priv
->map_view_embed
= gtk_champlain_embed_new ();
766 priv
->map_view
= gtk_champlain_embed_get_view (
767 GTK_CHAMPLAIN_EMBED (priv
->map_view_embed
));
769 gtk_container_add (GTK_CONTAINER (priv
->viewport_map
),
770 priv
->map_view_embed
);
771 g_object_set (G_OBJECT (priv
->map_view
),
772 "kinetic-mode", TRUE
,
776 layer
= champlain_marker_layer_new ();
777 champlain_view_add_layer (priv
->map_view
, CHAMPLAIN_LAYER (layer
));
779 /* FIXME: For now, we have to do this manually. Once libfolks grows a
780 * location interface, we can use that. (bgo#627400) */
782 personas
= folks_individual_get_personas (priv
->individual
);
783 iter
= gee_iterable_iterator (GEE_ITERABLE (personas
));
784 while (gee_iterator_next (iter
))
786 FolksPersona
*persona
= gee_iterator_get (iter
);
788 if (empathy_folks_persona_is_interesting (persona
))
790 gdouble lat
= 0.0, lon
= 0.0;
791 ClutterActor
*marker
;
792 TpContact
*tp_contact
;
794 /* Get the contact */
795 tp_contact
= tpf_persona_get_contact (TPF_PERSONA (persona
));
796 if (tp_contact
== NULL
)
799 contact
= empathy_contact_dup_from_tp_contact (tp_contact
);
800 empathy_contact_set_persona (contact
, persona
);
802 /* Try and get a location */
803 location
= empathy_contact_get_location (contact
);
804 if (location
== NULL
|| g_hash_table_size (location
) == 0)
807 /* Get this persona's latitude and longitude */
808 value
= g_hash_table_lookup (location
, EMPATHY_LOCATION_LAT
);
812 lat
= g_value_get_double (value
);
814 value
= g_hash_table_lookup (location
, EMPATHY_LOCATION_LON
);
818 lon
= g_value_get_double (value
);
820 /* Add a marker to the map */
821 marker
= champlain_label_new_with_text (
822 folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (persona
)),
824 champlain_location_set_location (CHAMPLAIN_LOCATION (marker
),
826 champlain_marker_layer_add_marker (layer
,
827 CHAMPLAIN_MARKER (marker
));
831 g_clear_object (&persona
);
832 g_clear_object (&contact
);
834 g_clear_object (&iter
);
836 /* Zoom to show all of the markers */
837 champlain_view_ensure_layers_visible (priv
->map_view
, FALSE
);
839 gtk_widget_show_all (priv
->viewport_map
);
843 gtk_widget_show (priv
->vbox_location
);
847 client_types_update (EmpathyIndividualWidget
*self
)
849 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
850 const gchar
* const *types
;
852 if (!(priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_SHOW_CLIENT_TYPES
) ||
853 priv
->individual
== NULL
)
855 gtk_widget_hide (priv
->hbox_client_types
);
859 if (priv
->contact
== NULL
)
860 update_weak_contact (self
);
862 /* let's try that again... */
863 if (priv
->contact
== NULL
)
866 types
= tp_contact_get_client_types (priv
->contact
);
868 if (empathy_client_types_contains_mobile_device ((GStrv
) types
))
870 gtk_widget_show (priv
->hbox_client_types
);
874 gtk_widget_hide (priv
->hbox_client_types
);
880 remove_weak_contact (EmpathyIndividualWidget
*self
)
882 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
884 if (priv
->contact
== NULL
)
887 g_signal_handlers_disconnect_by_func (priv
->contact
, client_types_notify_cb
,
890 g_object_remove_weak_pointer (G_OBJECT (priv
->contact
),
891 (gpointer
*) &priv
->contact
);
892 priv
->contact
= NULL
;
895 static EmpathyAvatar
*
896 persona_dup_avatar (FolksPersona
*persona
)
898 TpContact
*tp_contact
;
899 EmpathyContact
*contact
;
900 EmpathyAvatar
*avatar
;
902 if (!empathy_folks_persona_is_interesting (persona
))
905 tp_contact
= tpf_persona_get_contact (TPF_PERSONA (persona
));
906 if (tp_contact
== NULL
)
909 contact
= empathy_contact_dup_from_tp_contact (tp_contact
);
910 empathy_contact_set_persona (contact
, persona
);
912 avatar
= empathy_contact_get_avatar (contact
);
914 empathy_avatar_ref (avatar
);
915 g_object_unref (contact
);
920 static EmpathyAvatar
*
921 individual_dup_avatar (FolksIndividual
*individual
)
925 EmpathyAvatar
*avatar
= NULL
;
927 /* FIXME: We just choose the first Persona which has an avatar, and save that.
928 * The avatar handling in EmpathyContact needs to be moved into libfolks as
929 * much as possible, and this code rewritten to use FolksHasAvatar.
932 personas
= folks_individual_get_personas (individual
);
933 iter
= gee_iterable_iterator (GEE_ITERABLE (personas
));
934 while (avatar
== NULL
&& gee_iterator_next (iter
))
936 FolksPersona
*persona
= gee_iterator_get (iter
);
937 avatar
= persona_dup_avatar (persona
);
939 g_clear_object (&persona
);
941 g_clear_object (&iter
);
947 save_avatar_menu_activate_cb (GtkWidget
*widget
,
948 EmpathyIndividualWidget
*self
)
950 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
952 EmpathyAvatar
*avatar
;
953 gchar
*ext
= NULL
, *filename
;
955 dialog
= gtk_file_chooser_dialog_new (_("Save Avatar"),
957 GTK_FILE_CHOOSER_ACTION_SAVE
,
958 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
959 GTK_STOCK_SAVE
, GTK_RESPONSE_ACCEPT
,
962 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog
),
965 avatar
= individual_dup_avatar (priv
->individual
);
969 /* look for the avatar extension */
970 if (avatar
->format
!= NULL
)
974 splitted
= g_strsplit (avatar
->format
, "/", 2);
975 if (splitted
[0] != NULL
&& splitted
[1] != NULL
)
976 ext
= g_strdup (splitted
[1]);
978 g_strfreev (splitted
);
982 /* Avatar was loaded from the cache so was converted to PNG */
983 ext
= g_strdup ("png");
990 id
= tp_escape_as_identifier (folks_individual_get_id (priv
->individual
));
992 filename
= g_strdup_printf ("%s.%s", id
, ext
);
993 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog
), filename
);
1000 if (gtk_dialog_run (GTK_DIALOG (dialog
)) == GTK_RESPONSE_ACCEPT
)
1002 GError
*error
= NULL
;
1004 filename
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog
));
1006 if (empathy_avatar_save_to_file (avatar
, filename
, &error
) == FALSE
)
1009 GtkWidget
*error_dialog
;
1011 error_dialog
= gtk_message_dialog_new (NULL
, 0,
1012 GTK_MESSAGE_ERROR
, GTK_BUTTONS_CLOSE
,
1013 _("Unable to save avatar"));
1015 gtk_message_dialog_format_secondary_text (
1016 GTK_MESSAGE_DIALOG (error_dialog
), "%s", error
->message
);
1018 g_signal_connect (error_dialog
, "response",
1019 (GCallback
) gtk_widget_destroy
, NULL
);
1021 gtk_window_present (GTK_WINDOW (error_dialog
));
1023 g_clear_error (&error
);
1029 gtk_widget_destroy (dialog
);
1030 empathy_avatar_unref (avatar
);
1034 popup_avatar_menu (EmpathyIndividualWidget
*self
,
1036 GdkEventButton
*event
)
1038 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1039 GtkWidget
*menu
, *item
;
1040 EmpathyAvatar
*avatar
;
1041 gint button
, event_time
;
1043 if (priv
->individual
== NULL
)
1046 avatar
= individual_dup_avatar (priv
->individual
);
1049 empathy_avatar_unref (avatar
);
1051 menu
= empathy_context_menu_new (parent
);
1053 /* Add "Save as..." entry */
1054 item
= gtk_image_menu_item_new_from_stock (GTK_STOCK_SAVE_AS
, NULL
);
1055 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1056 gtk_widget_show (item
);
1058 g_signal_connect (item
, "activate",
1059 (GCallback
) save_avatar_menu_activate_cb
, self
);
1063 button
= event
->button
;
1064 event_time
= event
->time
;
1069 event_time
= gtk_get_current_event_time ();
1072 gtk_menu_popup (GTK_MENU (menu
), NULL
, NULL
, NULL
, NULL
, button
, event_time
);
1078 avatar_widget_popup_menu_cb (GtkWidget
*widget
,
1079 EmpathyIndividualWidget
*self
)
1081 return popup_avatar_menu (self
, widget
, NULL
);
1085 avatar_widget_button_press_event_cb (GtkWidget
*widget
,
1086 GdkEventButton
*event
,
1087 EmpathyIndividualWidget
*self
)
1089 /* Ignore double-clicks and triple-clicks */
1090 if (event
->button
== 3 && event
->type
== GDK_BUTTON_PRESS
)
1091 return popup_avatar_menu (self
, widget
, event
);
1096 /* Returns the TpAccount for the user as a convenience. Note that it has a ref
1099 individual_is_user (FolksIndividual
*individual
)
1103 TpAccount
*retval
= NULL
;
1105 /* FIXME: This should move into libfolks when libfolks grows a way of
1106 * determining "self". (bgo#627402) */
1107 personas
= folks_individual_get_personas (individual
);
1108 iter
= gee_iterable_iterator (GEE_ITERABLE (personas
));
1109 while (gee_iterator_next (iter
))
1111 FolksPersona
*persona
= gee_iterator_get (iter
);
1113 if (TPF_IS_PERSONA (persona
))
1115 TpContact
*tp_contact
;
1116 EmpathyContact
*contact
= NULL
;
1118 /* Get the contact */
1119 tp_contact
= tpf_persona_get_contact (TPF_PERSONA (persona
));
1120 if (tp_contact
!= NULL
)
1122 contact
= empathy_contact_dup_from_tp_contact (tp_contact
);
1123 empathy_contact_set_persona (contact
, persona
);
1125 /* Determine if the contact is the user */
1126 if (empathy_contact_is_user (contact
))
1127 retval
= g_object_ref (empathy_contact_get_account (contact
));
1130 g_object_unref (contact
);
1132 g_clear_object (&persona
);
1134 g_clear_object (&iter
);
1140 set_nickname_cb (TpAccount
*account
,
1141 GAsyncResult
*result
,
1144 GError
*error
= NULL
;
1146 if (tp_account_set_nickname_finish (account
, result
, &error
) == FALSE
)
1148 DEBUG ("Failed to set Account.Nickname: %s", error
->message
);
1149 g_error_free (error
);
1154 entry_alias_focus_event_cb (GtkEditable
*editable
,
1155 GdkEventFocus
*event
,
1156 EmpathyIndividualWidget
*self
)
1158 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1160 if (priv
->individual
!= NULL
)
1165 alias
= gtk_entry_get_text (GTK_ENTRY (editable
));
1166 account
= individual_is_user (priv
->individual
);
1168 if (account
!= NULL
)
1170 DEBUG ("Set Account.Nickname to %s", alias
);
1171 tp_account_set_nickname_async (account
, alias
,
1172 (GAsyncReadyCallback
) set_nickname_cb
, NULL
);
1173 g_object_unref (account
);
1177 folks_alias_details_set_alias (FOLKS_ALIAS_DETAILS (priv
->individual
),
1186 favourite_toggled_cb (GtkToggleButton
*button
,
1187 EmpathyIndividualWidget
*self
)
1189 gboolean active
= gtk_toggle_button_get_active (button
);
1190 folks_favourite_details_set_is_favourite (
1191 FOLKS_FAVOURITE_DETAILS (GET_PRIV (self
)->individual
), active
);
1195 notify_avatar_cb (gpointer folks_object
,
1197 EmpathyIndividualWidget
*self
)
1199 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1200 EmpathyAvatar
*avatar
= NULL
;
1202 GtkWidget
*avatar_widget
;
1204 if (FOLKS_IS_INDIVIDUAL (folks_object
))
1206 avatar
= individual_dup_avatar (FOLKS_INDIVIDUAL (folks_object
));
1207 grid
= G_OBJECT (priv
->individual_grid
);
1209 else if (FOLKS_IS_PERSONA (folks_object
))
1211 avatar
= persona_dup_avatar (FOLKS_PERSONA (folks_object
));
1212 grid
= g_hash_table_lookup (priv
->persona_grids
, folks_object
);
1216 g_assert_not_reached ();
1222 avatar_widget
= g_object_get_data (grid
, "avatar-widget");
1223 empathy_avatar_image_set (EMPATHY_AVATAR_IMAGE (avatar_widget
), avatar
);
1226 empathy_avatar_unref (avatar
);
1230 notify_alias_cb (gpointer folks_object
,
1232 EmpathyIndividualWidget
*self
)
1234 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1236 GtkWidget
*alias_widget
;
1238 if (FOLKS_IS_INDIVIDUAL (folks_object
))
1239 grid
= G_OBJECT (priv
->individual_grid
);
1240 else if (FOLKS_IS_PERSONA (folks_object
))
1241 grid
= g_hash_table_lookup (priv
->persona_grids
, folks_object
);
1243 g_assert_not_reached ();
1248 alias_widget
= g_object_get_data (grid
, "alias-widget");
1250 if (GTK_IS_ENTRY (alias_widget
))
1252 gtk_entry_set_text (GTK_ENTRY (alias_widget
),
1253 folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (folks_object
)));
1257 gtk_label_set_label (GTK_LABEL (alias_widget
),
1258 folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (folks_object
)));
1263 notify_presence_cb (gpointer folks_object
,
1265 EmpathyIndividualWidget
*self
)
1267 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1269 GtkWidget
*status_label
, *state_image
;
1270 const gchar
*message
;
1271 gchar
*markup_text
= NULL
;
1272 FolksPresenceType presence
;
1273 gboolean visible
= TRUE
;
1275 if (FOLKS_IS_INDIVIDUAL (folks_object
))
1276 grid
= G_OBJECT (priv
->individual_grid
);
1277 else if (FOLKS_IS_PERSONA (folks_object
))
1278 grid
= g_hash_table_lookup (priv
->persona_grids
, folks_object
);
1280 g_assert_not_reached ();
1285 status_label
= g_object_get_data (grid
, "status-label");
1286 state_image
= g_object_get_data (grid
, "state-image");
1288 presence
= folks_presence_details_get_presence_type (
1289 FOLKS_PRESENCE_DETAILS (folks_object
));
1290 if (presence
== FOLKS_PRESENCE_TYPE_UNKNOWN
||
1291 presence
== FOLKS_PRESENCE_TYPE_ERROR
)
1293 /* Don't display anything if we don't know the presence */
1298 message
= folks_presence_details_get_presence_message (
1299 FOLKS_PRESENCE_DETAILS (folks_object
));
1300 if (TPAW_STR_EMPTY (message
))
1302 message
= folks_presence_details_get_default_message_from_type (presence
);
1305 if (message
!= NULL
)
1306 markup_text
= tpaw_add_link_markup (message
);
1307 gtk_label_set_markup (GTK_LABEL (status_label
), markup_text
);
1308 g_free (markup_text
);
1310 gtk_image_set_from_icon_name (GTK_IMAGE (state_image
),
1311 empathy_icon_name_for_presence (
1312 empathy_folks_presence_type_to_tp (presence
)),
1313 GTK_ICON_SIZE_BUTTON
);
1316 gtk_widget_set_visible (status_label
, visible
);
1317 gtk_widget_set_visible (state_image
, visible
);
1321 notify_is_favourite_cb (gpointer folks_object
,
1323 EmpathyIndividualWidget
*self
)
1325 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1327 GtkWidget
*favourite_widget
;
1329 if (FOLKS_IS_INDIVIDUAL (folks_object
))
1330 grid
= G_OBJECT (priv
->individual_grid
);
1331 else if (FOLKS_IS_PERSONA (folks_object
))
1332 grid
= g_hash_table_lookup (priv
->persona_grids
, folks_object
);
1334 g_assert_not_reached ();
1339 favourite_widget
= g_object_get_data (grid
, "favourite-widget");
1341 if (GTK_IS_TOGGLE_BUTTON (favourite_widget
))
1343 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (favourite_widget
),
1344 folks_favourite_details_get_is_favourite (
1345 FOLKS_FAVOURITE_DETAILS (folks_object
)));
1350 alias_presence_avatar_favourite_set_up (EmpathyIndividualWidget
*self
,
1354 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1355 GtkWidget
*label
, *alias
, *image
, *avatar
;
1356 guint current_row
= starting_row
;
1359 label
= gtk_label_new (_("Alias:"));
1360 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1361 gtk_grid_attach (grid
, label
, 0, current_row
, 1, 1);
1362 gtk_widget_show (label
);
1364 /* Set up alias label/entry */
1365 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_EDIT_ALIAS
)
1367 alias
= gtk_entry_new ();
1369 g_signal_connect (alias
, "focus-out-event",
1370 (GCallback
) entry_alias_focus_event_cb
, self
);
1372 /* Make return activate the window default (the Close button) */
1373 gtk_entry_set_activates_default (GTK_ENTRY (alias
), TRUE
);
1377 alias
= gtk_label_new (NULL
);
1378 gtk_label_set_selectable (GTK_LABEL (alias
),
1379 (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_FOR_TOOLTIP
) ? FALSE
: TRUE
);
1380 gtk_misc_set_alignment (GTK_MISC (alias
), 0.0, 0.5);
1383 g_object_set_data (G_OBJECT (grid
), "alias-widget", alias
);
1384 gtk_grid_attach_next_to (grid
, alias
, label
,
1385 GTK_POS_RIGHT
, 1, 1);
1386 gtk_widget_show (alias
);
1391 priv
->hbox_presence
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 6);
1393 /* Presence image */
1394 image
= gtk_image_new_from_stock (GTK_STOCK_MISSING_IMAGE
,
1395 GTK_ICON_SIZE_BUTTON
);
1396 g_object_set_data (G_OBJECT (grid
), "state-image", image
);
1397 gtk_box_pack_start (GTK_BOX (priv
->hbox_presence
), image
, FALSE
,
1399 gtk_widget_show (image
);
1401 label
= gtk_label_new ("");
1402 gtk_label_set_line_wrap_mode (GTK_LABEL (label
), PANGO_WRAP_WORD_CHAR
);
1403 gtk_label_set_line_wrap (GTK_LABEL (label
), TRUE
);
1404 gtk_misc_set_alignment (GTK_MISC (label
), 0, 0.5);
1406 gtk_label_set_selectable (GTK_LABEL (label
),
1407 (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_FOR_TOOLTIP
) ? FALSE
: TRUE
);
1409 g_object_set_data (G_OBJECT (grid
), "status-label", label
);
1410 gtk_box_pack_start (GTK_BOX (priv
->hbox_presence
), label
, FALSE
,
1412 gtk_widget_show (label
);
1414 gtk_grid_attach (grid
, priv
->hbox_presence
,
1415 0, current_row
, 2, 1);
1416 gtk_widget_show (priv
->hbox_presence
);
1420 /* Set up favourite toggle button */
1421 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_EDIT_FAVOURITE
)
1423 GtkWidget
*favourite
= gtk_check_button_new_with_label (_("Favorite"));
1425 g_signal_connect (favourite
, "toggled",
1426 (GCallback
) favourite_toggled_cb
, self
);
1428 g_object_set_data (G_OBJECT (grid
), "favourite-widget", favourite
);
1429 gtk_grid_attach (grid
, favourite
,
1430 0, current_row
, 2, 1);
1431 gtk_widget_show (favourite
);
1436 /* Set up avatar display */
1437 avatar
= empathy_avatar_image_new ();
1439 if (!(priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_FOR_TOOLTIP
))
1441 g_signal_connect (avatar
, "popup-menu",
1442 (GCallback
) avatar_widget_popup_menu_cb
, self
);
1443 g_signal_connect (avatar
, "button-press-event",
1444 (GCallback
) avatar_widget_button_press_event_cb
, self
);
1447 g_object_set_data (G_OBJECT (grid
), "avatar-widget", avatar
);
1448 g_object_set (avatar
,
1449 "valign", GTK_ALIGN_START
,
1456 gtk_grid_attach (grid
, avatar
,
1457 2, 0, 1, current_row
);
1458 gtk_widget_show (avatar
);
1462 update_persona (EmpathyIndividualWidget
*self
, FolksPersona
*persona
)
1464 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1465 TpContact
*tp_contact
;
1466 EmpathyContact
*contact
;
1473 grid
= g_hash_table_lookup (priv
->persona_grids
, persona
);
1475 g_assert (grid
!= NULL
);
1477 tp_contact
= tpf_persona_get_contact (TPF_PERSONA (persona
));
1478 if (tp_contact
== NULL
)
1481 contact
= empathy_contact_dup_from_tp_contact (tp_contact
);
1482 empathy_contact_set_persona (contact
, persona
);
1484 account
= empathy_contact_get_account (contact
);
1486 /* Update account widget */
1487 if (account
!= NULL
)
1491 label
= g_object_get_data (G_OBJECT (grid
), "account-label");
1492 image
= g_object_get_data (G_OBJECT (grid
), "account-image");
1494 name
= tp_account_get_display_name (account
);
1495 gtk_label_set_label (label
, name
);
1497 name
= tp_account_get_icon_name (account
);
1498 gtk_image_set_from_icon_name (image
, name
, GTK_ICON_SIZE_MENU
);
1501 /* Update id widget */
1502 label
= g_object_get_data (G_OBJECT (grid
), "id-widget");
1503 id
= folks_persona_get_display_id (persona
);
1504 gtk_label_set_label (label
, (id
!= NULL
) ? id
: "");
1506 /* Update other widgets */
1507 notify_alias_cb (persona
, NULL
, self
);
1508 notify_presence_cb (persona
, NULL
, self
);
1509 notify_avatar_cb (persona
, NULL
, self
);
1511 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_EDIT_FAVOURITE
)
1512 notify_is_favourite_cb (persona
, NULL
, self
);
1514 g_object_unref (contact
);
1518 add_persona (EmpathyIndividualWidget
*self
,
1519 FolksPersona
*persona
)
1521 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1524 GtkWidget
*label
, *account_label
, *account_image
, *separator
;
1525 guint current_row
= 0;
1527 if (!empathy_folks_persona_is_interesting (persona
))
1530 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_EDIT_FAVOURITE
)
1531 grid
= GTK_GRID (gtk_grid_new ());
1533 grid
= GTK_GRID (gtk_grid_new ());
1535 gtk_orientable_set_orientation (GTK_ORIENTABLE (grid
), GTK_ORIENTATION_VERTICAL
);
1536 gtk_grid_set_row_spacing (grid
, 6);
1537 gtk_grid_set_column_spacing (grid
, 6);
1539 /* Account and Identifier */
1540 label
= gtk_label_new (_("Account:"));
1541 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1542 gtk_grid_attach (grid
, label
, 0, current_row
, 1, 1);
1543 gtk_widget_show (label
);
1545 /* Pack the protocol icon with the account name in an hbox */
1546 hbox
= GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 6));
1548 account_label
= gtk_label_new (NULL
);
1549 gtk_label_set_selectable (GTK_LABEL (account_label
),
1550 (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_FOR_TOOLTIP
) ? FALSE
: TRUE
);
1551 gtk_misc_set_alignment (GTK_MISC (account_label
), 0.0, 0.5);
1552 gtk_widget_show (account_label
);
1554 account_image
= gtk_image_new ();
1555 gtk_widget_show (account_image
);
1557 gtk_box_pack_start (hbox
, account_image
, FALSE
, FALSE
, 0);
1558 gtk_box_pack_start (hbox
, account_label
, FALSE
, TRUE
, 0);
1560 g_object_set_data (G_OBJECT (grid
), "account-image", account_image
);
1561 g_object_set_data (G_OBJECT (grid
), "account-label", account_label
);
1562 gtk_grid_attach_next_to (grid
, GTK_WIDGET (hbox
), label
, GTK_POS_RIGHT
, 1, 1);
1563 gtk_widget_show (GTK_WIDGET (hbox
));
1567 /* Translators: Identifier to connect to Instant Messaging network */
1568 label
= gtk_label_new (_("Identifier:"));
1569 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1570 gtk_grid_attach (grid
, label
, 0, current_row
, 1, 1);
1571 gtk_widget_show (label
);
1573 /* Set up ID label */
1574 label
= gtk_label_new (NULL
);
1575 gtk_label_set_selectable (GTK_LABEL (label
),
1576 (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_FOR_TOOLTIP
) ? FALSE
: TRUE
);
1577 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1579 g_object_set_data (G_OBJECT (grid
), "id-widget", label
);
1580 gtk_grid_attach (grid
, label
, 1, current_row
, 1, 1);
1581 gtk_widget_show (label
);
1585 alias_presence_avatar_favourite_set_up (self
, grid
, current_row
);
1587 /* Connect to signals and display the grid */
1588 g_signal_connect (persona
, "notify::alias",
1589 (GCallback
) notify_alias_cb
, self
);
1590 g_signal_connect (persona
, "notify::avatar",
1591 (GCallback
) notify_avatar_cb
, self
);
1592 g_signal_connect (persona
, "notify::presence-type",
1593 (GCallback
) notify_presence_cb
, self
);
1594 g_signal_connect (persona
, "notify::presence-message",
1595 (GCallback
) notify_presence_cb
, self
);
1597 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_EDIT_FAVOURITE
)
1599 g_signal_connect (persona
, "notify::is-favourite",
1600 (GCallback
) notify_is_favourite_cb
, self
);
1603 gtk_box_pack_start (GTK_BOX (priv
->vbox_individual
),
1604 GTK_WIDGET (grid
), FALSE
, TRUE
, 0);
1605 gtk_widget_show (GTK_WIDGET (grid
));
1607 /* Pack a separator after the grid */
1608 separator
= gtk_separator_new (GTK_ORIENTATION_HORIZONTAL
);
1609 g_object_set_data (G_OBJECT (grid
), "separator", separator
);
1610 gtk_box_pack_start (GTK_BOX (priv
->vbox_individual
), separator
, FALSE
, FALSE
,
1612 gtk_widget_show (separator
);
1614 g_hash_table_replace (priv
->persona_grids
, persona
, grid
);
1616 /* Update the new widgets */
1617 update_persona (self
, persona
);
1621 remove_persona (EmpathyIndividualWidget
*self
,
1622 FolksPersona
*persona
)
1624 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1625 GtkWidget
*separator
;
1628 if (!empathy_folks_persona_is_interesting (persona
))
1631 grid
= g_hash_table_lookup (priv
->persona_grids
, persona
);
1635 g_signal_handlers_disconnect_by_func (persona
, notify_alias_cb
, self
);
1636 g_signal_handlers_disconnect_by_func (persona
, notify_avatar_cb
, self
);
1637 g_signal_handlers_disconnect_by_func (persona
, notify_presence_cb
, self
);
1639 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_EDIT_FAVOURITE
)
1641 g_signal_handlers_disconnect_by_func (persona
, notify_is_favourite_cb
,
1645 /* Remove the separator */
1646 separator
= g_object_get_data (G_OBJECT (grid
), "separator");
1647 if (separator
!= NULL
)
1648 gtk_container_remove (GTK_CONTAINER (priv
->vbox_individual
), separator
);
1650 /* Remove the widget */
1651 gtk_container_remove (GTK_CONTAINER (priv
->vbox_individual
),
1654 g_hash_table_remove (priv
->persona_grids
, persona
);
1658 update_individual_grid (EmpathyIndividualWidget
*self
)
1660 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1662 notify_alias_cb (priv
->individual
, NULL
, self
);
1663 notify_presence_cb (priv
->individual
, NULL
, self
);
1664 notify_avatar_cb (priv
->individual
, NULL
, self
);
1666 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_EDIT_FAVOURITE
)
1667 notify_is_favourite_cb (priv
->individual
, NULL
, self
);
1671 individual_grid_set_up (EmpathyIndividualWidget
*self
)
1673 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1674 guint current_row
= 0;
1677 grid
= GTK_GRID (gtk_grid_new ());
1678 gtk_orientable_set_orientation (GTK_ORIENTABLE (grid
), GTK_ORIENTATION_VERTICAL
);
1679 gtk_grid_set_row_spacing (grid
, 6);
1680 gtk_grid_set_column_spacing (grid
, 6);
1682 /* We only display the number of personas in tooltips */
1683 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_FOR_TOOLTIP
)
1689 guint num_personas
= 0;
1691 /* Meta-contacts message displaying how many Telepathy personas we have */
1692 personas
= folks_individual_get_personas (priv
->individual
);
1693 iter
= gee_iterable_iterator (GEE_ITERABLE (personas
));
1694 while (gee_iterator_next (iter
))
1696 FolksPersona
*persona
= gee_iterator_get (iter
);
1697 if (empathy_folks_persona_is_interesting (persona
))
1700 g_clear_object (&persona
);
1702 g_clear_object (&iter
);
1704 /* Translators: the plurality applies to both instances of the word
1706 message
= g_strdup_printf (
1707 ngettext ("Linked contact containing %u contact",
1708 "Linked contacts containing %u contacts", num_personas
),
1710 label
= gtk_label_new (message
);
1711 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1714 gtk_grid_attach (grid
, label
, 0, current_row
, 2, 1);
1715 gtk_widget_show (label
);
1720 alias_presence_avatar_favourite_set_up (self
, grid
, current_row
);
1722 /* Display the grid */
1723 gtk_box_pack_start (GTK_BOX (priv
->vbox_individual
), GTK_WIDGET (grid
),
1725 gtk_widget_show (GTK_WIDGET (grid
));
1727 priv
->individual_grid
= grid
;
1729 /* Update the grid */
1730 update_individual_grid (self
);
1734 individual_grid_destroy (EmpathyIndividualWidget
*self
)
1736 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1738 if (priv
->individual_grid
== NULL
)
1741 gtk_container_remove (GTK_CONTAINER (priv
->vbox_individual
),
1742 GTK_WIDGET (priv
->individual_grid
));
1744 #ifdef HAVE_LIBCHAMPLAIN
1745 if (priv
->map_view_embed
!= NULL
)
1747 gtk_container_remove (GTK_CONTAINER (priv
->viewport_map
),
1748 priv
->map_view_embed
);
1750 priv
->map_view_embed
= NULL
;
1754 priv
->individual_grid
= NULL
;
1758 personas_changed_cb (FolksIndividual
*individual
,
1761 EmpathyIndividualWidget
*self
)
1763 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1764 GList
*l
, *children
;
1767 gboolean show_personas
, was_showing_personas
, will_show_personas
, is_last
;
1768 guint old_num_personas
, new_num_personas
= 0;
1770 personas
= folks_individual_get_personas (individual
);
1771 /* we'll re-use this iterator throughout */
1772 iter
= gee_iterable_iterator (GEE_ITERABLE (personas
));
1774 /* Note that old_num_personas is the number of persona gridss we were
1775 * displaying, not the number of Personas which were in the Individual
1777 old_num_personas
= g_hash_table_size (priv
->persona_grids
);
1779 while (gee_iterator_next (iter
))
1781 FolksPersona
*persona
= gee_iterator_get (iter
);
1782 if (empathy_folks_persona_is_interesting (persona
))
1785 g_clear_object (&persona
);
1787 g_clear_object (&iter
);
1790 * What we display for various conditions:
1791 * - "Personas": display the alias, avatar, presence account and identifier
1792 * for each of the Individual's Personas. (i.e. One grid per
1794 * - "Individual": display the alias, avatar and presence for the Individual,
1795 * and a label saying "Meta-contact containing x contacts".
1796 * (i.e. One grid in total.)
1798 * | SHOW_PERSONAS | !SHOW_PERSONAS
1799 * -------------+---------------+---------------
1800 * > 1 Persona | Personas | Individual
1801 * -------------+---------------+---------------
1802 * == 1 Persona | Personas | Personas
1804 show_personas
= (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_SHOW_PERSONAS
) != 0;
1805 was_showing_personas
= show_personas
|| old_num_personas
== 1;
1806 will_show_personas
= show_personas
|| new_num_personas
== 1;
1808 /* If both @added and @removed are NULL, we're being called manually, and we
1809 * need to set up the gridss for the first time. We do this simply by
1810 * ensuring was_showing_personas and will_show_personas are different so that
1811 * the code resets the UI.
1813 if (added
== NULL
&& removed
== NULL
)
1814 was_showing_personas
= !will_show_personas
;
1816 if (was_showing_personas
&& will_show_personas
)
1818 GeeIterator
*iter_changed
;
1820 /* Remove outdated Personas */
1821 iter_changed
= gee_iterable_iterator (GEE_ITERABLE (removed
));
1822 while (gee_iterator_next (iter_changed
))
1824 FolksPersona
*persona
= gee_iterator_get (iter_changed
);
1825 remove_persona (self
, persona
);
1826 g_clear_object (&persona
);
1828 g_clear_object (&iter_changed
);
1830 /* Add new Personas */
1831 iter_changed
= gee_iterable_iterator (GEE_ITERABLE (added
));
1832 while (gee_iterator_next (iter_changed
))
1834 FolksPersona
*persona
= gee_iterator_get (iter_changed
);
1835 add_persona (self
, persona
);
1836 g_clear_object (&persona
);
1838 g_clear_object (&iter_changed
);
1840 else if (!was_showing_personas
&& will_show_personas
)
1842 /* Remove the old Individual grid */
1843 individual_grid_destroy (self
);
1845 /* Set up all the Persona grids instead */
1846 iter
= gee_iterable_iterator (GEE_ITERABLE (personas
));
1847 while (gee_iterator_next (iter
))
1849 FolksPersona
*persona
= gee_iterator_get (iter
);
1850 add_persona (self
, persona
);
1851 g_clear_object (&persona
);
1853 g_clear_object (&iter
);
1855 else if (was_showing_personas
&& !will_show_personas
)
1857 /* Remove all Personas */
1858 iter
= gee_iterable_iterator (GEE_ITERABLE (personas
));
1859 while (gee_iterator_next (iter
))
1861 FolksPersona
*persona
= gee_iterator_get (iter
);
1862 remove_persona (self
, persona
);
1863 g_clear_object (&persona
);
1865 g_clear_object (&iter
);
1867 if (removed
!= NULL
)
1869 GeeIterator
*iter_changed
;
1871 iter_changed
= gee_iterable_iterator (GEE_ITERABLE (removed
));
1872 while (gee_iterator_next (iter_changed
))
1874 FolksPersona
*persona
= gee_iterator_get (iter_changed
);
1875 remove_persona (self
, persona
);
1876 g_clear_object (&persona
);
1878 g_clear_object (&iter_changed
);
1881 /* Set up the Individual grid instead */
1882 individual_grid_set_up (self
);
1885 /* Hide the last separator and show the others */
1886 children
= gtk_container_get_children (GTK_CONTAINER (priv
->vbox_individual
));
1887 children
= g_list_reverse (children
);
1890 for (l
= children
; l
!= NULL
; l
= l
->next
)
1892 if (GTK_IS_SEPARATOR (l
->data
))
1894 gtk_widget_set_visible (GTK_WIDGET (l
->data
), !is_last
);
1899 g_list_free (children
);
1903 individual_removed_cb (FolksIndividual
*individual
,
1904 FolksIndividual
*replacement_individual
,
1905 EmpathyIndividualWidget
*self
)
1907 empathy_individual_widget_set_individual (self
, replacement_individual
);
1911 remove_individual (EmpathyIndividualWidget
*self
)
1913 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1914 if (priv
->individual
!= NULL
)
1919 g_signal_handlers_disconnect_by_func (priv
->individual
,
1920 notify_alias_cb
, self
);
1921 g_signal_handlers_disconnect_by_func (priv
->individual
,
1922 notify_presence_cb
, self
);
1923 g_signal_handlers_disconnect_by_func (priv
->individual
,
1924 notify_avatar_cb
, self
);
1925 g_signal_handlers_disconnect_by_func (priv
->individual
,
1926 personas_changed_cb
, self
);
1927 g_signal_handlers_disconnect_by_func (priv
->individual
,
1928 individual_removed_cb
, self
);
1930 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_EDIT_FAVOURITE
)
1932 g_signal_handlers_disconnect_by_func (priv
->individual
,
1933 notify_is_favourite_cb
, self
);
1936 personas
= folks_individual_get_personas (priv
->individual
);
1937 iter
= gee_iterable_iterator (GEE_ITERABLE (personas
));
1938 while (gee_iterator_next (iter
))
1940 FolksPersona
*persona
= gee_iterator_get (iter
);
1941 remove_persona (self
, persona
);
1942 g_clear_object (&persona
);
1944 g_clear_object (&iter
);
1945 individual_grid_destroy (self
);
1947 if (priv
->contact
!= NULL
)
1948 remove_weak_contact (self
);
1950 tp_clear_object (&priv
->individual
);
1953 if (priv
->details_cancellable
!= NULL
)
1954 g_cancellable_cancel (priv
->details_cancellable
);
1958 individual_update (EmpathyIndividualWidget
*self
)
1960 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (self
);
1962 /* Connect and get info from new Individual */
1963 if (priv
->individual
!= NULL
)
1965 g_signal_connect (priv
->individual
, "notify::alias",
1966 (GCallback
) notify_alias_cb
, self
);
1967 g_signal_connect (priv
->individual
, "notify::presence-type",
1968 (GCallback
) notify_presence_cb
, self
);
1969 g_signal_connect (priv
->individual
, "notify::presence-message",
1970 (GCallback
) notify_presence_cb
, self
);
1971 g_signal_connect (priv
->individual
, "notify::avatar",
1972 (GCallback
) notify_avatar_cb
, self
);
1973 g_signal_connect (priv
->individual
, "personas-changed",
1974 (GCallback
) personas_changed_cb
, self
);
1975 g_signal_connect (priv
->individual
, "removed",
1976 (GCallback
) individual_removed_cb
, self
);
1978 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_EDIT_FAVOURITE
)
1980 g_signal_connect (priv
->individual
, "notify::is-favourite",
1981 (GCallback
) notify_is_favourite_cb
, self
);
1984 /* Update individual grid */
1985 personas_changed_cb (priv
->individual
, NULL
, NULL
, self
);
1988 if (priv
->individual
== NULL
)
1990 gtk_widget_hide (priv
->vbox_individual
);
1992 else if (priv
->individual_grid
!= NULL
)
1994 /* We only need to update the details for the Individual as a whole */
1995 update_individual_grid (self
);
1996 gtk_widget_show (priv
->vbox_individual
);
2000 /* We need to update the details for every Persona in the Individual */
2004 personas
= folks_individual_get_personas (priv
->individual
);
2005 iter
= gee_iterable_iterator (GEE_ITERABLE (personas
));
2006 while (gee_iterator_next (iter
))
2008 FolksPersona
*persona
= gee_iterator_get (iter
);
2010 if (empathy_folks_persona_is_interesting (persona
))
2011 update_persona (self
, persona
);
2013 g_clear_object (&persona
);
2015 g_clear_object (&iter
);
2017 gtk_widget_show (priv
->vbox_individual
);
2022 empathy_individual_widget_init (EmpathyIndividualWidget
*self
)
2024 EmpathyIndividualWidgetPriv
*priv
;
2028 priv
= G_TYPE_INSTANCE_GET_PRIVATE (self
,
2029 EMPATHY_TYPE_INDIVIDUAL_WIDGET
, EmpathyIndividualWidgetPriv
);
2032 gtk_orientable_set_orientation (GTK_ORIENTABLE (self
),
2033 GTK_ORIENTATION_VERTICAL
);
2035 filename
= empathy_file_lookup ("empathy-individual-widget.ui",
2037 gui
= tpaw_builder_get_file (filename
,
2038 "scrolled_window_individual", &priv
->scrolled_window_individual
,
2039 "viewport_individual", &priv
->viewport_individual
,
2040 "vbox_individual_widget", &priv
->vbox_individual_widget
,
2041 "vbox_individual", &priv
->vbox_individual
,
2042 "vbox_location", &priv
->vbox_location
,
2043 "subvbox_location", &priv
->subvbox_location
,
2044 "label_location", &priv
->label_location
,
2045 #ifdef HAVE_LIBCHAMPLAIN
2046 "viewport_map", &priv
->viewport_map
,
2048 "groups_widget", &priv
->groups_widget
,
2049 "vbox_details", &priv
->vbox_details
,
2050 "grid_details", &priv
->grid_details
,
2051 "hbox_details_requested", &priv
->hbox_details_requested
,
2052 "hbox_client_types", &priv
->hbox_client_types
,
2056 priv
->grid_location
= NULL
;
2058 gtk_box_pack_start (GTK_BOX (self
), priv
->vbox_individual_widget
, TRUE
, TRUE
,
2060 gtk_widget_show (priv
->vbox_individual_widget
);
2062 priv
->persona_grids
= g_hash_table_new (NULL
, NULL
);
2063 priv
->individual_grid
= NULL
;
2065 /* Create widgets */
2066 details_set_up (self
);
2068 g_object_unref (gui
);
2072 constructed (GObject
*object
)
2074 GObjectClass
*klass
= G_OBJECT_CLASS (empathy_individual_widget_parent_class
);
2075 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (object
);
2076 GtkScrolledWindow
*scrolled_window
=
2077 GTK_SCROLLED_WINDOW (priv
->scrolled_window_individual
);
2079 /* Allow scrolling of the list of Personas if we're showing Personas. */
2080 if (priv
->flags
& EMPATHY_INDIVIDUAL_WIDGET_SHOW_PERSONAS
)
2082 gtk_scrolled_window_set_shadow_type (scrolled_window
, GTK_SHADOW_IN
);
2083 gtk_scrolled_window_set_policy (scrolled_window
,
2084 GTK_POLICY_NEVER
, GTK_POLICY_AUTOMATIC
);
2085 gtk_box_set_child_packing (GTK_BOX (priv
->vbox_individual_widget
),
2086 priv
->scrolled_window_individual
, TRUE
, TRUE
, 0, GTK_PACK_START
);
2088 gtk_container_set_border_width (GTK_CONTAINER (priv
->viewport_individual
),
2090 gtk_widget_set_size_request (GTK_WIDGET (scrolled_window
), -1, 100);
2094 gtk_scrolled_window_set_shadow_type (scrolled_window
, GTK_SHADOW_NONE
);
2095 gtk_scrolled_window_set_policy (scrolled_window
,
2096 GTK_POLICY_NEVER
, GTK_POLICY_NEVER
);
2097 gtk_box_set_child_packing (GTK_BOX (priv
->vbox_individual_widget
),
2098 priv
->scrolled_window_individual
, FALSE
, TRUE
, 0, GTK_PACK_START
);
2100 gtk_container_set_border_width (GTK_CONTAINER (priv
->viewport_individual
),
2105 if (klass
->constructed
!= NULL
)
2106 klass
->constructed (object
);
2110 get_property (GObject
*object
,
2115 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (object
);
2119 case PROP_INDIVIDUAL
:
2120 g_value_set_object (value
, priv
->individual
);
2123 g_value_set_flags (value
, priv
->flags
);
2126 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
2132 set_property (GObject
*object
,
2134 const GValue
*value
,
2137 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (object
);
2141 case PROP_INDIVIDUAL
:
2142 empathy_individual_widget_set_individual (
2143 EMPATHY_INDIVIDUAL_WIDGET (object
), g_value_get_object (value
));
2146 priv
->flags
= g_value_get_flags (value
);
2149 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
2155 dispose (GObject
*object
)
2157 remove_individual (EMPATHY_INDIVIDUAL_WIDGET (object
));
2159 G_OBJECT_CLASS (empathy_individual_widget_parent_class
)->dispose (object
);
2163 finalize (GObject
*object
)
2165 EmpathyIndividualWidgetPriv
*priv
= GET_PRIV (object
);
2167 g_hash_table_unref (priv
->persona_grids
);
2169 G_OBJECT_CLASS (empathy_individual_widget_parent_class
)->finalize (object
);
2173 empathy_individual_widget_class_init (EmpathyIndividualWidgetClass
*klass
)
2175 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
2177 object_class
->constructed
= constructed
;
2178 object_class
->get_property
= get_property
;
2179 object_class
->set_property
= set_property
;
2180 object_class
->dispose
= dispose
;
2181 object_class
->finalize
= finalize
;
2184 * EmpathyIndividualWidget:individual:
2186 * The #FolksIndividual to display in the widget.
2188 g_object_class_install_property (object_class
, PROP_INDIVIDUAL
,
2189 g_param_spec_object ("individual",
2191 "The #FolksIndividual to display in the widget.",
2192 FOLKS_TYPE_INDIVIDUAL
,
2193 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
));
2196 * EmpathyIndividualWidget:flags:
2198 * A set of flags which affect the widget's behaviour.
2200 g_object_class_install_property (object_class
, PROP_FLAGS
,
2201 g_param_spec_flags ("flags",
2203 "A set of flags which affect the widget's behaviour.",
2204 EMPATHY_TYPE_INDIVIDUAL_WIDGET_FLAGS
,
2205 EMPATHY_INDIVIDUAL_WIDGET_NONE
,
2206 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
| G_PARAM_CONSTRUCT_ONLY
));
2208 g_type_class_add_private (object_class
, sizeof (EmpathyIndividualWidgetPriv
));
2212 * empathy_individual_widget_new:
2213 * @individual: the #FolksIndividual to display
2214 * @flags: flags affecting how the widget behaves and what it displays
2216 * Creates a new #EmpathyIndividualWidget.
2218 * Return value: a new #EmpathyIndividualWidget
2221 empathy_individual_widget_new (FolksIndividual
*individual
,
2222 EmpathyIndividualWidgetFlags flags
)
2224 g_return_val_if_fail (individual
== NULL
|| FOLKS_IS_INDIVIDUAL (individual
),
2227 return g_object_new (EMPATHY_TYPE_INDIVIDUAL_WIDGET
,
2228 "individual", individual
,
2234 * empathy_individual_widget_get_individual:
2235 * @self: an #EmpathyIndividualWidget
2237 * Returns the #FolksIndividual being displayed by the widget.
2239 * Return value: the #FolksIndividual being displayed, or %NULL
2242 empathy_individual_widget_get_individual (EmpathyIndividualWidget
*self
)
2244 g_return_val_if_fail (EMPATHY_IS_INDIVIDUAL_WIDGET (self
), NULL
);
2246 return GET_PRIV (self
)->individual
;
2250 * empathy_individual_widget_set_individual:
2251 * @self: an #EmpathyIndividualWidget
2252 * @individual: the #FolksIndividual to display, or %NULL
2254 * Set the #FolksIndividual to be displayed by the widget:
2255 * #EmpathyIndividualWidget:individual.
2257 * The @individual may be %NULL in order to display nothing in the widget.
2260 empathy_individual_widget_set_individual (EmpathyIndividualWidget
*self
,
2261 FolksIndividual
*individual
)
2263 EmpathyIndividualWidgetPriv
*priv
;
2265 g_return_if_fail (EMPATHY_IS_INDIVIDUAL_WIDGET (self
));
2266 g_return_if_fail (individual
== NULL
|| FOLKS_IS_INDIVIDUAL (individual
));
2268 priv
= GET_PRIV (self
);
2270 if (individual
== priv
->individual
)
2273 /* Out with the old… */
2274 remove_individual (self
);
2276 /* …and in with the new. */
2277 if (individual
!= NULL
)
2278 g_object_ref (individual
);
2279 priv
->individual
= individual
;
2281 /* Update information for widgets */
2282 individual_update (self
);
2283 groups_update (self
);
2284 details_update (self
);
2285 location_update (self
);
2286 client_types_update (self
);