1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2007-2009 Collabora Ltd.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 * Authors: Xavier Claessens <xclaesse@gmail.com>
28 #include <glib/gi18n-lib.h>
30 #ifdef HAVE_LIBCHAMPLAIN
31 #include <champlain/champlain.h>
32 #include <champlain-gtk/champlain-gtk.h>
35 #include <telepathy-glib/account.h>
36 #include <telepathy-glib/util.h>
37 #include <telepathy-glib/interfaces.h>
39 #include <libempathy/empathy-tp-contact-factory.h>
40 #include <libempathy/empathy-contact-list.h>
41 #include <libempathy/empathy-location.h>
42 #include <libempathy/empathy-time.h>
43 #include <libempathy/empathy-utils.h>
45 #include "empathy-contact-widget.h"
46 #include "empathy-contactinfo-utils.h"
47 #include "empathy-account-chooser.h"
48 #include "empathy-avatar-chooser.h"
49 #include "empathy-avatar-image.h"
50 #include "empathy-groups-widget.h"
51 #include "empathy-ui-utils.h"
52 #include "empathy-string-parser.h"
54 #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT
55 #include <libempathy/empathy-debug.h>
58 * SECTION:empathy-contact-widget
59 * @title:EmpathyContactWidget
60 * @short_description: A widget used to display and edit details about a contact
61 * @include: libempathy-empathy-contact-widget.h
63 * #EmpathyContactWidget is a widget which displays appropriate widgets
64 * with details about a contact, also allowing changing these details,
69 * EmpathyContactWidget:
70 * @parent: parent object
72 * Widget which displays appropriate widgets with details about a contact,
73 * also allowing changing these details, if desired.
76 /* Delay before updating the widget when the id entry changed (seconds) */
77 #define ID_CHANGED_TIMEOUT 1
79 #define DATA_FIELD "contact-info-field"
83 EmpathyContact
*contact
;
84 EmpathyContactWidgetFlags flags
;
85 guint widget_id_timeout
;
88 GtkWidget
*vbox_contact_widget
;
91 GtkWidget
*widget_avatar
;
92 GtkWidget
*widget_account
;
93 GtkWidget
*image_account
;
94 GtkWidget
*label_account
;
96 GtkWidget
*widget_alias
;
97 GtkWidget
*label_alias
;
98 GtkWidget
*hbox_presence
;
99 GtkWidget
*image_state
;
100 GtkWidget
*label_status
;
101 GtkWidget
*grid_contact
;
102 GtkWidget
*vbox_avatar
;
103 GtkWidget
*favourite_checkbox
;
106 GtkWidget
*vbox_location
;
107 GtkWidget
*subvbox_location
;
108 GtkWidget
*grid_location
;
109 GtkWidget
*label_location
;
110 #ifdef HAVE_LIBCHAMPLAIN
111 GtkWidget
*viewport_map
;
112 GtkWidget
*map_view_embed
;
113 ChamplainView
*map_view
;
117 GtkWidget
*groups_widget
;
120 GtkWidget
*vbox_details
;
121 GtkWidget
*grid_details
;
122 GtkWidget
*hbox_details_requested
;
123 GtkWidget
*spinner_details
;
124 GList
*details_to_set
;
125 GCancellable
*details_cancellable
;
126 gboolean details_changed
;
129 GtkWidget
*vbox_client
;
130 GtkWidget
*grid_client
;
131 GtkWidget
*hbox_client_requested
;
132 } EmpathyContactWidget
;
136 EmpathyContactWidget
*information
;
139 GtkTreeIter found_iter
;
151 field_value_is_empty (TpContactInfoField
*field
)
155 if (field
->field_value
== NULL
)
158 /* Field is empty if all its values are empty */
159 for (i
= 0; field
->field_value
[i
] != NULL
; i
++)
161 if (!tp_str_empty (field
->field_value
[i
]))
169 set_contact_info_cb (GObject
*source
,
170 GAsyncResult
*result
,
173 GError
*error
= NULL
;
175 if (!tp_connection_set_contact_info_finish (TP_CONNECTION (source
), result
,
178 DEBUG ("SetContactInfo() failed: %s", error
->message
);
179 g_error_free (error
);
183 DEBUG ("SetContactInfo() succeeded");
187 contact_widget_save (EmpathyContactWidget
*information
)
189 TpConnection
*connection
;
192 connection
= empathy_contact_get_connection (information
->contact
);
194 /* Remove empty fields */
195 for (l
= information
->details_to_set
; l
!= NULL
; l
= next
)
197 TpContactInfoField
*field
= l
->data
;
200 if (field_value_is_empty (field
))
202 DEBUG ("Drop empty field: %s", field
->field_name
);
203 tp_contact_info_field_free (field
);
204 information
->details_to_set
=
205 g_list_delete_link (information
->details_to_set
, l
);
209 if (information
->details_to_set
!= NULL
)
211 if (information
->details_changed
)
213 tp_connection_set_contact_info_async (connection
,
214 information
->details_to_set
, set_contact_info_cb
, NULL
);
217 tp_contact_info_list_free (information
->details_to_set
);
218 information
->details_to_set
= NULL
;
223 contact_widget_details_setup (EmpathyContactWidget
*information
)
225 gtk_widget_hide (information
->vbox_details
);
227 information
->spinner_details
= gtk_spinner_new ();
228 gtk_box_pack_end (GTK_BOX (information
->hbox_details_requested
),
229 information
->spinner_details
, TRUE
, TRUE
, 0);
230 gtk_widget_show (information
->spinner_details
);
234 contact_widget_details_changed_cb (GtkEntry
*entry
,
235 EmpathyContactWidget
*self
)
237 const gchar
*strv
[] = { NULL
, NULL
};
238 TpContactInfoField
*field
;
240 self
->details_changed
= TRUE
;
242 field
= g_object_get_data ((GObject
*) entry
, DATA_FIELD
);
243 g_assert (field
!= NULL
);
245 strv
[0] = gtk_entry_get_text (entry
);
247 if (field
->field_value
!= NULL
)
248 g_strfreev (field
->field_value
);
249 field
->field_value
= g_strdupv ((GStrv
) strv
);
253 contact_widget_bday_changed_cb (GtkCalendar
*calendar
,
254 EmpathyContactWidget
*self
)
256 guint year
, month
, day
;
259 const gchar
*strv
[] = { NULL
, NULL
};
260 TpContactInfoField
*field
;
262 self
->details_changed
= TRUE
;
264 field
= g_object_get_data ((GObject
*) calendar
, DATA_FIELD
);
265 g_assert (field
!= NULL
);
267 gtk_calendar_get_date (calendar
, &year
, &month
, &day
);
268 date
= g_date_new_dmy (day
, month
+1, year
);
270 gtk_calendar_clear_marks (calendar
);
271 gtk_calendar_mark_day (calendar
, g_date_get_day (date
));
273 g_date_strftime (tmp
, sizeof (tmp
), EMPATHY_DATE_FORMAT_DISPLAY_SHORT
, date
);
275 if (field
->field_value
!= NULL
)
276 g_strfreev (field
->field_value
);
277 field
->field_value
= g_strdupv ((GStrv
) strv
);
282 static void contact_widget_details_notify_cb (EmpathyContactWidget
*information
);
285 field_name_in_field_list (GList
*list
,
290 for (l
= list
; l
!= NULL
; l
= g_list_next (l
))
292 TpContactInfoField
*field
= l
->data
;
294 if (!tp_strdiff (field
->field_name
, name
))
301 static TpContactInfoFieldSpec
*
302 get_spec_from_list (GList
*list
,
307 for (l
= list
; l
!= NULL
; l
= g_list_next (l
))
309 TpContactInfoFieldSpec
*spec
= l
->data
;
311 if (!tp_strdiff (spec
->name
, name
))
319 contact_widget_details_update_edit (EmpathyContactWidget
*information
)
322 TpConnection
*connection
;
326 const char **field_names
= empathy_contact_info_get_field_names (NULL
);
329 g_assert (information
->details_to_set
== NULL
);
331 information
->details_changed
= FALSE
;
333 contact
= empathy_contact_get_tp_contact (information
->contact
);
334 connection
= tp_contact_get_connection (contact
);
336 info
= tp_contact_get_contact_info (contact
);
338 specs
= tp_connection_get_contact_info_supported_fields (connection
);
340 /* Look at the fields set in our vCard */
341 for (l
= info
; l
!= NULL
; l
= l
->next
)
343 TpContactInfoField
*field
= l
->data
;
345 /* make a copy for the details_to_set list */
346 field
= tp_contact_info_field_copy (field
);
347 DEBUG ("Field %s is in our vCard", field
->field_name
);
349 information
->details_to_set
= g_list_prepend (information
->details_to_set
,
353 /* Add fields which are supported but not in the vCard */
354 for (i
= 0; field_names
[i
] != NULL
; i
++)
356 TpContactInfoFieldSpec
*spec
;
357 TpContactInfoField
*field
;
359 /* Check if the field was in the vCard */
360 if (field_name_in_field_list (information
->details_to_set
,
364 /* Check if the CM supports the field */
365 spec
= get_spec_from_list (specs
, field_names
[i
]);
369 /* add an empty field so user can set a value */
370 field
= tp_contact_info_field_new (spec
->name
, spec
->parameters
, NULL
);
372 information
->details_to_set
= g_list_prepend (information
->details_to_set
,
376 /* Add widgets for supported fields */
377 information
->details_to_set
= g_list_sort (information
->details_to_set
,
378 (GCompareFunc
) empathy_contact_info_field_spec_cmp
);
380 for (l
= information
->details_to_set
; l
!= NULL
; l
= g_list_next (l
))
382 TpContactInfoField
*field
= l
->data
;
384 TpContactInfoFieldSpec
*spec
;
388 has_field
= empathy_contact_info_lookup_field (field
->field_name
,
392 /* Empathy doesn't display this field so we can't change it.
393 * But we put it in the details_to_set list so it won't be erased
394 * when calling SetContactInfo (bgo #630427) */
395 DEBUG ("Unhandled ContactInfo field spec: %s", field
->field_name
);
399 spec
= get_spec_from_list (specs
, field
->field_name
);
400 /* We shouldn't have added the field to details_to_set if it's not
401 * supported by the CM */
402 g_assert (spec
!= NULL
);
404 if (spec
->flags
& TP_CONTACT_INFO_FIELD_FLAG_OVERWRITTEN_BY_NICKNAME
)
406 DEBUG ("Ignoring field '%s' due it to having the "
407 "Overwritten_By_Nickname flag", field
->field_name
);
412 title
= empathy_contact_info_field_label (field
->field_name
,
414 w
= gtk_label_new (title
);
417 gtk_grid_attach (GTK_GRID (information
->grid_details
),
420 gtk_misc_set_alignment (GTK_MISC (w
), 0, 0.5);
424 if (!tp_strdiff (field
->field_name
, "bday"))
426 w
= gtk_calendar_new ();
427 if (field
->field_value
[0])
431 g_date_set_parse (&date
, field
->field_value
[0]);
432 if (g_date_valid (&date
))
434 gtk_calendar_select_day (GTK_CALENDAR (w
),
435 g_date_get_day (&date
));
436 gtk_calendar_select_month (GTK_CALENDAR (w
),
437 g_date_get_month (&date
) - 1, g_date_get_year (&date
));
438 gtk_calendar_mark_day (GTK_CALENDAR (w
),
439 g_date_get_day (&date
));
443 gtk_grid_attach (GTK_GRID (information
->grid_details
),
447 g_object_set_data ((GObject
*) w
, DATA_FIELD
, field
);
449 g_signal_connect (w
, "day-selected",
450 G_CALLBACK (contact_widget_bday_changed_cb
), information
);
451 g_signal_connect (w
, "month-changed",
452 G_CALLBACK (contact_widget_bday_changed_cb
), information
);
456 w
= gtk_entry_new ();
457 gtk_entry_set_text (GTK_ENTRY (w
),
458 field
->field_value
[0] ? field
->field_value
[0] : "");
459 gtk_grid_attach (GTK_GRID (information
->grid_details
),
463 g_object_set_data ((GObject
*) w
, DATA_FIELD
, field
);
465 g_signal_connect (w
, "changed",
466 G_CALLBACK (contact_widget_details_changed_cb
), information
);
479 add_row (GtkGrid
*grid
,
484 gtk_grid_attach (grid
, title
, 0, row
, 1, 1);
485 gtk_misc_set_alignment (GTK_MISC (title
), 0, 0.5);
486 gtk_widget_show (title
);
488 gtk_grid_attach (grid
, value
, 1, row
, 1, 1);
489 gtk_misc_set_alignment (GTK_MISC (value
), 0, 0.5);
490 gtk_widget_show (value
);
494 contact_widget_details_update_show (EmpathyContactWidget
*information
)
499 GtkWidget
*channels_label
;
502 contact
= empathy_contact_get_tp_contact (information
->contact
);
503 info
= tp_contact_get_contact_info (contact
);
504 info
= g_list_sort (info
, (GCompareFunc
) empathy_contact_info_field_cmp
);
505 for (l
= info
; l
!= NULL
; l
= l
->next
)
507 TpContactInfoField
*field
= l
->data
;
509 gchar
*markup
= NULL
, *title
;
510 GtkWidget
*title_widget
, *value_widget
;
511 EmpathyContactInfoFormatFunc format
;
513 if (field
->field_value
== NULL
|| field
->field_value
[0] == NULL
)
516 value
= field
->field_value
[0];
518 if (!empathy_contact_info_lookup_field (field
->field_name
, NULL
, &format
))
520 DEBUG ("Unhandled ContactInfo field: %s", field
->field_name
);
526 markup
= format (field
->field_value
);
530 DEBUG ("Invalid value for field '%s' (first element was '%s')",
531 field
->field_name
, field
->field_value
[0]);
537 title
= empathy_contact_info_field_label (field
->field_name
,
539 title_widget
= gtk_label_new (title
);
543 value_widget
= gtk_label_new (value
);
546 gtk_label_set_markup (GTK_LABEL (value_widget
), markup
);
550 if ((information
->flags
& EMPATHY_CONTACT_WIDGET_FOR_TOOLTIP
) == 0)
551 gtk_label_set_selectable (GTK_LABEL (value_widget
), TRUE
);
553 add_row (GTK_GRID (information
->grid_details
), n_rows
, title_widget
,
559 account
= empathy_contact_get_account (information
->contact
);
561 channels_label
= empathy_contact_info_create_channel_list_label (account
,
564 if (channels_label
!= NULL
)
566 GtkWidget
*title_widget
;
568 title_widget
= gtk_label_new (_("Channels:"));
570 add_row (GTK_GRID (information
->grid_details
), n_rows
, title_widget
,
582 contact_widget_details_notify_cb (EmpathyContactWidget
*information
)
586 gtk_container_foreach (GTK_CONTAINER (information
->grid_details
),
587 (GtkCallback
) gtk_widget_destroy
, NULL
);
589 if ((information
->flags
& EMPATHY_CONTACT_WIDGET_EDIT_DETAILS
) != 0)
590 n_rows
= contact_widget_details_update_edit (information
);
592 n_rows
= contact_widget_details_update_show (information
);
596 gtk_widget_show (information
->vbox_details
);
597 gtk_widget_show (information
->grid_details
);
601 gtk_widget_hide (information
->vbox_details
);
604 gtk_widget_hide (information
->hbox_details_requested
);
605 gtk_spinner_stop (GTK_SPINNER (information
->spinner_details
));
609 contact_widget_details_request_cb (GObject
*object
,
613 TpContact
*contact
= TP_CONTACT (object
);
614 EmpathyContactWidget
*information
= user_data
;
615 GError
*error
= NULL
;
617 if (!tp_contact_request_contact_info_finish (contact
, res
, &error
))
619 /* If the request got cancelled it could mean the contact widget is
620 * destroyed, so we should not dereference information */
621 if (g_error_matches (error
, G_IO_ERROR
, G_IO_ERROR_CANCELLED
))
623 g_clear_error (&error
);
627 gtk_widget_hide (information
->vbox_details
);
628 g_clear_error (&error
);
632 contact_widget_details_notify_cb (information
);
635 /* If we are going to edit ContactInfo, we don't want live updates */
636 if ((information
->flags
& EMPATHY_CONTACT_WIDGET_EDIT_DETAILS
) == 0)
638 g_signal_connect_swapped (contact
, "notify::contact-info",
639 G_CALLBACK (contact_widget_details_notify_cb
), information
);
642 tp_clear_object (&information
->details_cancellable
);
646 fetch_contact_information (EmpathyContactWidget
*information
,
647 TpConnection
*connection
)
650 TpContactInfoFlags flags
;
652 if (!tp_proxy_has_interface_by_id (connection
,
653 TP_IFACE_QUARK_CONNECTION_INTERFACE_CONTACT_INFO
))
655 gtk_widget_hide (information
->vbox_details
);
659 /* If we want to edit info, but connection does not support that, stop */
660 flags
= tp_connection_get_contact_info_flags (connection
);
661 if ((flags
& TP_CONTACT_INFO_FLAG_CAN_SET
) == 0 &&
662 (information
->flags
& EMPATHY_CONTACT_WIDGET_EDIT_DETAILS
) != 0)
664 gtk_widget_hide (information
->vbox_details
);
668 /* Request the contact's info */
669 gtk_widget_show (information
->vbox_details
);
670 gtk_widget_show (information
->hbox_details_requested
);
671 gtk_widget_hide (information
->grid_details
);
672 gtk_spinner_start (GTK_SPINNER (information
->spinner_details
));
674 contact
= empathy_contact_get_tp_contact (information
->contact
);
675 g_assert (information
->details_cancellable
== NULL
);
676 information
->details_cancellable
= g_cancellable_new ();
677 tp_contact_request_contact_info_async (contact
,
678 information
->details_cancellable
, contact_widget_details_request_cb
,
683 contact_widget_details_update (EmpathyContactWidget
*information
)
685 TpContact
*tp_contact
= NULL
;
687 if ((information
->flags
& EMPATHY_CONTACT_WIDGET_SHOW_DETAILS
) == 0 &&
688 (information
->flags
& EMPATHY_CONTACT_WIDGET_EDIT_DETAILS
) == 0)
691 gtk_widget_hide (information
->vbox_details
);
693 if (information
->contact
!= NULL
)
694 tp_contact
= empathy_contact_get_tp_contact (information
->contact
);
696 if (tp_contact
!= NULL
)
698 TpConnection
*connection
;
700 connection
= tp_contact_get_connection (tp_contact
);
702 fetch_contact_information (information
, connection
);
707 contact_widget_client_update (EmpathyContactWidget
*information
)
709 /* FIXME: Needs new telepathy spec */
713 contact_widget_client_setup (EmpathyContactWidget
*information
)
715 /* FIXME: Needs new telepathy spec */
716 gtk_widget_hide (information
->vbox_client
);
720 contact_widget_groups_update (EmpathyContactWidget
*information
)
722 if (information
->flags
& EMPATHY_CONTACT_WIDGET_EDIT_GROUPS
&&
723 information
->contact
!= NULL
)
725 FolksPersona
*persona
=
726 empathy_contact_get_persona (information
->contact
);
728 if (FOLKS_IS_GROUP_DETAILS (persona
))
730 empathy_groups_widget_set_group_details (
731 EMPATHY_GROUPS_WIDGET (information
->groups_widget
),
732 FOLKS_GROUP_DETAILS (persona
));
733 gtk_widget_show (information
->groups_widget
);
739 /* In case of failure */
740 gtk_widget_hide (information
->groups_widget
);
743 /* Converts the Location's GHashTable's key to a user readable string */
745 location_key_to_label (const gchar
*key
)
747 if (tp_strdiff (key
, EMPATHY_LOCATION_COUNTRY_CODE
) == FALSE
)
748 return _("Country ISO Code:");
749 else if (tp_strdiff (key
, EMPATHY_LOCATION_COUNTRY
) == FALSE
)
750 return _("Country:");
751 else if (tp_strdiff (key
, EMPATHY_LOCATION_REGION
) == FALSE
)
753 else if (tp_strdiff (key
, EMPATHY_LOCATION_LOCALITY
) == FALSE
)
755 else if (tp_strdiff (key
, EMPATHY_LOCATION_AREA
) == FALSE
)
757 else if (tp_strdiff (key
, EMPATHY_LOCATION_POSTAL_CODE
) == FALSE
)
758 return _("Postal Code:");
759 else if (tp_strdiff (key
, EMPATHY_LOCATION_STREET
) == FALSE
)
761 else if (tp_strdiff (key
, EMPATHY_LOCATION_BUILDING
) == FALSE
)
762 return _("Building:");
763 else if (tp_strdiff (key
, EMPATHY_LOCATION_FLOOR
) == FALSE
)
765 else if (tp_strdiff (key
, EMPATHY_LOCATION_ROOM
) == FALSE
)
767 else if (tp_strdiff (key
, EMPATHY_LOCATION_TEXT
) == FALSE
)
769 else if (tp_strdiff (key
, EMPATHY_LOCATION_DESCRIPTION
) == FALSE
)
770 return _("Description:");
771 else if (tp_strdiff (key
, EMPATHY_LOCATION_URI
) == FALSE
)
773 else if (tp_strdiff (key
, EMPATHY_LOCATION_ACCURACY_LEVEL
) == FALSE
)
774 return _("Accuracy Level:");
775 else if (tp_strdiff (key
, EMPATHY_LOCATION_ERROR
) == FALSE
)
777 else if (tp_strdiff (key
, EMPATHY_LOCATION_VERTICAL_ERROR_M
) == FALSE
)
778 return _("Vertical Error (meters):");
779 else if (tp_strdiff (key
, EMPATHY_LOCATION_HORIZONTAL_ERROR_M
) == FALSE
)
780 return _("Horizontal Error (meters):");
781 else if (tp_strdiff (key
, EMPATHY_LOCATION_SPEED
) == FALSE
)
783 else if (tp_strdiff (key
, EMPATHY_LOCATION_BEARING
) == FALSE
)
784 return _("Bearing:");
785 else if (tp_strdiff (key
, EMPATHY_LOCATION_CLIMB
) == FALSE
)
786 return _("Climb Speed:");
787 else if (tp_strdiff (key
, EMPATHY_LOCATION_TIMESTAMP
) == FALSE
)
788 return _("Last Updated on:");
789 else if (tp_strdiff (key
, EMPATHY_LOCATION_LON
) == FALSE
)
790 return _("Longitude:");
791 else if (tp_strdiff (key
, EMPATHY_LOCATION_LAT
) == FALSE
)
792 return _("Latitude:");
793 else if (tp_strdiff (key
, EMPATHY_LOCATION_ALT
) == FALSE
)
794 return _("Altitude:");
797 DEBUG ("Unexpected Location key: %s", key
);
803 contact_widget_location_update (EmpathyContactWidget
*information
)
805 GHashTable
*location
;
807 #ifdef HAVE_LIBCHAMPLAIN
808 gdouble lat
= 0.0, lon
= 0.0;
809 gboolean has_position
= TRUE
;
813 static const gchar
* ordered_geolocation_keys
[] = {
814 EMPATHY_LOCATION_TEXT
,
815 EMPATHY_LOCATION_URI
,
816 EMPATHY_LOCATION_DESCRIPTION
,
817 EMPATHY_LOCATION_BUILDING
,
818 EMPATHY_LOCATION_FLOOR
,
819 EMPATHY_LOCATION_ROOM
,
820 EMPATHY_LOCATION_STREET
,
821 EMPATHY_LOCATION_AREA
,
822 EMPATHY_LOCATION_LOCALITY
,
823 EMPATHY_LOCATION_REGION
,
824 EMPATHY_LOCATION_COUNTRY
,
829 gboolean display_map
= FALSE
;
831 if (!(information
->flags
& EMPATHY_CONTACT_WIDGET_SHOW_LOCATION
))
833 gtk_widget_hide (information
->vbox_location
);
837 location
= empathy_contact_get_location (information
->contact
);
838 if (location
== NULL
|| g_hash_table_size (location
) == 0)
840 gtk_widget_hide (information
->vbox_location
);
844 value
= g_hash_table_lookup (location
, EMPATHY_LOCATION_TIMESTAMP
);
847 gchar
*loc
= g_strdup_printf ("<b>%s</b>", _("Location"));
848 gtk_label_set_markup (GTK_LABEL (information
->label_location
), loc
);
858 stamp
= g_value_get_int64 (value
);
860 user_date
= empathy_time_to_string_relative (stamp
);
862 tmp
= g_strdup_printf ("<b>%s</b>", _("Location"));
863 /* translators: format is "Location, $date" */
864 text
= g_strdup_printf (_("%s, %s"), tmp
, user_date
);
866 gtk_label_set_markup (GTK_LABEL (information
->label_location
), text
);
872 /* Prepare the location information grid */
873 if (information
->grid_location
!= NULL
)
875 gtk_widget_destroy (information
->grid_location
);
878 information
->grid_location
= gtk_grid_new ();
879 gtk_box_pack_start (GTK_BOX (information
->subvbox_location
),
880 information
->grid_location
, FALSE
, FALSE
, 5);
883 for (i
= 0; (skey
= ordered_geolocation_keys
[i
]); i
++)
885 const gchar
* user_label
;
889 gvalue
= g_hash_table_lookup (location
, (gpointer
) skey
);
893 user_label
= location_key_to_label (skey
);
895 label
= gtk_label_new (user_label
);
896 gtk_misc_set_alignment (GTK_MISC (label
), 0, 0.5);
897 gtk_grid_attach (GTK_GRID (information
->grid_location
),
898 label
, 0, row
, 1, 1);
899 gtk_widget_show (label
);
901 if (G_VALUE_TYPE (gvalue
) == G_TYPE_DOUBLE
)
904 dvalue
= g_value_get_double (gvalue
);
905 svalue
= g_strdup_printf ("%f", dvalue
);
907 else if (G_VALUE_TYPE (gvalue
) == G_TYPE_STRING
)
909 svalue
= g_value_dup_string (gvalue
);
911 else if (G_VALUE_TYPE (gvalue
) == G_TYPE_INT64
)
915 time_
= g_value_get_int64 (value
);
916 svalue
= empathy_time_to_string_utc (time_
, _("%B %e, %Y at %R UTC"));
921 label
= gtk_label_new (svalue
);
922 gtk_grid_attach (GTK_GRID (information
->grid_location
),
923 label
, 1, row
, 1, 1);
924 gtk_misc_set_alignment (GTK_MISC (label
), 0, 0);
925 gtk_widget_show (label
);
927 if (!(information
->flags
& EMPATHY_CONTACT_WIDGET_FOR_TOOLTIP
))
928 gtk_label_set_selectable (GTK_LABEL (label
), TRUE
);
935 #ifdef HAVE_LIBCHAMPLAIN
937 !(information
->flags
& EMPATHY_CONTACT_WIDGET_FOR_TOOLTIP
))
939 /* Cannot be displayed in tooltips until Clutter-Gtk can deal with such
947 /* We can display some fields */
948 gtk_widget_show (information
->grid_location
);
950 else if (!display_map
)
952 /* Can't display either fields or map */
953 gtk_widget_hide (information
->vbox_location
);
957 #ifdef HAVE_LIBCHAMPLAIN
960 ClutterActor
*marker
;
961 ChamplainMarkerLayer
*layer
;
963 information
->map_view_embed
= gtk_champlain_embed_new ();
964 information
->map_view
= gtk_champlain_embed_get_view (
965 GTK_CHAMPLAIN_EMBED (information
->map_view_embed
));
967 gtk_container_add (GTK_CONTAINER (information
->viewport_map
),
968 information
->map_view_embed
);
969 g_object_set (G_OBJECT (information
->map_view
),
970 "kinetic-mode", TRUE
,
974 layer
= champlain_marker_layer_new ();
975 champlain_view_add_layer (information
->map_view
, CHAMPLAIN_LAYER (layer
));
977 marker
= champlain_label_new_with_text (
978 empathy_contact_get_alias (information
->contact
), NULL
, NULL
, NULL
);
979 champlain_location_set_location (CHAMPLAIN_LOCATION (marker
), lat
, lon
);
980 champlain_marker_layer_add_marker (layer
, CHAMPLAIN_MARKER (marker
));
982 champlain_view_center_on (information
->map_view
, lat
, lon
);
983 gtk_widget_show_all (information
->viewport_map
);
987 gtk_widget_show (information
->vbox_location
);
991 save_avatar_menu_activate_cb (GtkWidget
*widget
,
992 EmpathyContactWidget
*information
)
995 EmpathyAvatar
*avatar
;
996 gchar
*ext
= NULL
, *filename
;
998 dialog
= gtk_file_chooser_dialog_new (_("Save Avatar"),
1000 GTK_FILE_CHOOSER_ACTION_SAVE
,
1001 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
1002 GTK_STOCK_SAVE
, GTK_RESPONSE_ACCEPT
,
1005 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog
),
1008 /* look for the avatar extension */
1009 avatar
= empathy_contact_get_avatar (information
->contact
);
1010 if (avatar
->format
!= NULL
)
1014 splitted
= g_strsplit (avatar
->format
, "/", 2);
1015 if (splitted
[0] != NULL
&& splitted
[1] != NULL
)
1016 ext
= g_strdup (splitted
[1]);
1018 g_strfreev (splitted
);
1022 /* Avatar was loaded from the cache so was converted to PNG */
1023 ext
= g_strdup ("png");
1030 id
= tp_escape_as_identifier (empathy_contact_get_id (
1031 information
->contact
));
1033 filename
= g_strdup_printf ("%s.%s", id
, ext
);
1034 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog
), filename
);
1041 if (gtk_dialog_run (GTK_DIALOG (dialog
)) == GTK_RESPONSE_ACCEPT
)
1043 GError
*error
= NULL
;
1045 filename
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog
));
1047 if (!empathy_avatar_save_to_file (avatar
, filename
, &error
))
1050 GtkWidget
*error_dialog
;
1052 error_dialog
= gtk_message_dialog_new (NULL
, 0,
1053 GTK_MESSAGE_ERROR
, GTK_BUTTONS_CLOSE
,
1054 _("Unable to save avatar"));
1056 gtk_message_dialog_format_secondary_text (
1057 GTK_MESSAGE_DIALOG (error_dialog
), "%s", error
->message
);
1059 g_signal_connect (error_dialog
, "response",
1060 G_CALLBACK (gtk_widget_destroy
), NULL
);
1062 gtk_window_present (GTK_WINDOW (error_dialog
));
1064 g_clear_error (&error
);
1070 gtk_widget_destroy (dialog
);
1074 popup_avatar_menu (EmpathyContactWidget
*information
,
1076 GdkEventButton
*event
)
1078 GtkWidget
*menu
, *item
;
1079 gint button
, event_time
;
1081 if (information
->contact
== NULL
||
1082 empathy_contact_get_avatar (information
->contact
) == NULL
)
1085 menu
= empathy_context_menu_new (parent
);
1087 /* Add "Save as..." entry */
1088 item
= gtk_image_menu_item_new_from_stock (GTK_STOCK_SAVE_AS
, NULL
);
1089 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1090 gtk_widget_show (item
);
1092 g_signal_connect (item
, "activate",
1093 G_CALLBACK (save_avatar_menu_activate_cb
), information
);
1097 button
= event
->button
;
1098 event_time
= event
->time
;
1103 event_time
= gtk_get_current_event_time ();
1106 gtk_menu_popup (GTK_MENU (menu
), NULL
, NULL
, NULL
, NULL
,
1107 button
, event_time
);
1111 widget_avatar_popup_menu_cb (GtkWidget
*widget
,
1112 EmpathyContactWidget
*information
)
1114 popup_avatar_menu (information
, widget
, NULL
);
1120 widget_avatar_button_press_event_cb (GtkWidget
*widget
,
1121 GdkEventButton
*event
,
1122 EmpathyContactWidget
*information
)
1124 /* Ignore double-clicks and triple-clicks */
1125 if (event
->button
== 3 && event
->type
== GDK_BUTTON_PRESS
)
1127 popup_avatar_menu (information
, widget
, event
);
1135 set_avatar_cb (GObject
*source
,
1139 GError
*error
= NULL
;
1141 if (!tp_account_set_avatar_finish (TP_ACCOUNT (source
), res
, &error
)) {
1142 DEBUG ("Failed to set Account.Avatar: %s", error
->message
);
1143 g_error_free (error
);
1148 set_avatar_on_account (TpAccount
*account
,
1151 const gchar
*mime_type
)
1153 DEBUG ("%s Account.Avatar on %s", size
> 0 ? "Set": "Clear",
1154 tp_proxy_get_object_path (account
));
1156 tp_account_set_avatar_async (account
, (const guchar
*) data
, size
,
1157 mime_type
, set_avatar_cb
, NULL
);
1161 contact_widget_avatar_changed_cb (EmpathyAvatarChooser
*chooser
,
1162 EmpathyContactWidget
*information
)
1166 const gchar
*mime_type
;
1169 empathy_avatar_chooser_get_image_data (
1170 EMPATHY_AVATAR_CHOOSER (information
->widget_avatar
),
1171 &data
, &size
, &mime_type
);
1173 account
= empathy_contact_get_account (information
->contact
);
1174 set_avatar_on_account (account
, data
, size
, mime_type
);
1178 set_nickname_cb (GObject
*source
,
1182 GError
*error
= NULL
;
1184 if (!tp_account_set_nickname_finish (TP_ACCOUNT (source
), res
, &error
))
1186 DEBUG ("Failed to set Account.Nickname: %s", error
->message
);
1187 g_error_free (error
);
1191 /* Update all the contact info fields having the
1192 * Overwritten_By_Nickname flag to the new alias. This avoid accidentally
1193 * reseting the alias when calling SetContactInfo(). See bgo #644298 for
1196 update_nickname_in_contact_info (EmpathyContactWidget
*self
,
1197 TpConnection
*connection
,
1198 const gchar
*nickname
)
1202 specs
= tp_connection_get_contact_info_supported_fields (connection
);
1204 for (l
= self
->details_to_set
; l
!= NULL
; l
= g_list_next (l
))
1206 TpContactInfoField
*field
= l
->data
;
1207 TpContactInfoFieldSpec
*spec
;
1209 spec
= get_spec_from_list (specs
, field
->field_name
);
1210 /* We shouldn't have added the field to details_to_set if it's not
1211 * supported by the CM */
1212 g_assert (spec
!= NULL
);
1214 if (spec
->flags
& TP_CONTACT_INFO_FIELD_FLAG_OVERWRITTEN_BY_NICKNAME
)
1216 const gchar
*strv
[] = { nickname
, NULL
};
1218 DEBUG ("Updating field '%s' to '%s' as it has the "
1219 "Overwritten_By_Nickname flag and Account.Nickname has "
1220 "been updated", field
->field_name
, nickname
);
1222 if (field
->field_value
!= NULL
)
1223 g_strfreev (field
->field_value
);
1224 field
->field_value
= g_strdupv ((GStrv
) strv
);
1228 g_list_free (specs
);
1232 contact_widget_entry_alias_focus_event_cb (GtkEditable
*editable
,
1233 GdkEventFocus
*event
,
1234 EmpathyContactWidget
*information
)
1236 if (information
->contact
)
1240 alias
= gtk_entry_get_text (GTK_ENTRY (editable
));
1242 if (empathy_contact_is_user (information
->contact
))
1244 TpAccount
* account
;
1245 const gchar
*current_nickname
;
1247 account
= empathy_contact_get_account (information
->contact
);
1248 current_nickname
= tp_account_get_nickname (account
);
1250 if (tp_strdiff (current_nickname
, alias
))
1252 DEBUG ("Set Account.Nickname to %s", alias
);
1254 tp_account_set_nickname_async (account
, alias
, set_nickname_cb
,
1257 update_nickname_in_contact_info (information
,
1258 empathy_contact_get_connection (information
->contact
), alias
);
1263 empathy_contact_set_alias (information
->contact
, alias
);
1271 update_avatar_chooser_account_cb (EmpathyAccountChooser
*account_chooser
,
1272 EmpathyAvatarChooser
*avatar_chooser
)
1276 account
= empathy_account_chooser_get_account (account_chooser
);
1277 if (account
== NULL
)
1280 empathy_avatar_chooser_set_account (avatar_chooser
, account
);
1284 contact_widget_avatar_notify_cb (EmpathyContactWidget
*information
)
1286 EmpathyAvatar
*avatar
= NULL
;
1288 if (information
->contact
)
1289 avatar
= empathy_contact_get_avatar (information
->contact
);
1291 if (information
->flags
& EMPATHY_CONTACT_WIDGET_EDIT_AVATAR
)
1293 g_signal_handlers_block_by_func (information
->widget_avatar
,
1294 contact_widget_avatar_changed_cb
,
1296 empathy_avatar_chooser_set (
1297 EMPATHY_AVATAR_CHOOSER (information
->widget_avatar
), avatar
);
1298 g_signal_handlers_unblock_by_func (information
->widget_avatar
,
1299 contact_widget_avatar_changed_cb
, information
);
1302 empathy_avatar_image_set (
1303 EMPATHY_AVATAR_IMAGE (information
->widget_avatar
), avatar
);
1307 contact_widget_name_notify_cb (EmpathyContactWidget
*information
)
1309 if (GTK_IS_ENTRY (information
->widget_alias
))
1310 gtk_entry_set_text (GTK_ENTRY (information
->widget_alias
),
1311 empathy_contact_get_alias (information
->contact
));
1313 gtk_label_set_label (GTK_LABEL (information
->widget_alias
),
1314 empathy_contact_get_alias (information
->contact
));
1318 contact_widget_presence_notify_cb (EmpathyContactWidget
*information
)
1320 const gchar
*status
;
1321 gchar
*markup_text
= NULL
;
1323 status
= empathy_contact_get_status (information
->contact
);
1325 markup_text
= empathy_add_link_markup (status
);
1326 gtk_label_set_markup (GTK_LABEL (information
->label_status
), markup_text
);
1327 g_free (markup_text
);
1329 gtk_image_set_from_icon_name (GTK_IMAGE (information
->image_state
),
1330 empathy_icon_name_for_contact (information
->contact
),
1331 GTK_ICON_SIZE_BUTTON
);
1332 gtk_widget_show (information
->image_state
);
1336 contact_widget_remove_contact (EmpathyContactWidget
*information
)
1338 if (information
->contact
)
1340 TpContact
*tp_contact
;
1342 contact_widget_save (information
);
1344 g_signal_handlers_disconnect_by_func (information
->contact
,
1345 contact_widget_name_notify_cb
, information
);
1346 g_signal_handlers_disconnect_by_func (information
->contact
,
1347 contact_widget_presence_notify_cb
, information
);
1348 g_signal_handlers_disconnect_by_func (information
->contact
,
1349 contact_widget_avatar_notify_cb
, information
);
1351 tp_contact
= empathy_contact_get_tp_contact (information
->contact
);
1352 if (tp_contact
!= NULL
)
1354 g_signal_handlers_disconnect_by_func (tp_contact
,
1355 contact_widget_details_notify_cb
, information
);
1358 g_object_unref (information
->contact
);
1359 information
->contact
= NULL
;
1362 if (information
->details_cancellable
!= NULL
)
1364 g_cancellable_cancel (information
->details_cancellable
);
1365 tp_clear_object (&information
->details_cancellable
);
1369 static void contact_widget_change_contact (EmpathyContactWidget
*information
);
1372 contact_widget_contact_update (EmpathyContactWidget
*information
)
1374 TpAccount
*account
= NULL
;
1375 const gchar
*id
= NULL
;
1377 /* Connect and get info from new contact */
1378 if (information
->contact
)
1380 g_signal_connect_swapped (information
->contact
, "notify::name",
1381 G_CALLBACK (contact_widget_name_notify_cb
), information
);
1382 g_signal_connect_swapped (information
->contact
, "notify::presence",
1383 G_CALLBACK (contact_widget_presence_notify_cb
), information
);
1384 g_signal_connect_swapped (information
->contact
,
1385 "notify::presence-message",
1386 G_CALLBACK (contact_widget_presence_notify_cb
), information
);
1387 g_signal_connect_swapped (information
->contact
, "notify::avatar",
1388 G_CALLBACK (contact_widget_avatar_notify_cb
), information
);
1390 account
= empathy_contact_get_account (information
->contact
);
1391 id
= empathy_contact_get_id (information
->contact
);
1394 /* Update account widget */
1395 if (information
->flags
& EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT
)
1399 g_signal_handlers_block_by_func (information
->widget_account
,
1400 contact_widget_change_contact
,
1402 empathy_account_chooser_set_account (
1403 EMPATHY_ACCOUNT_CHOOSER (information
->widget_account
), account
);
1404 g_signal_handlers_unblock_by_func (information
->widget_account
,
1405 contact_widget_change_contact
, information
);
1414 name
= tp_account_get_display_name (account
);
1415 gtk_label_set_label (GTK_LABEL (information
->label_account
), name
);
1417 name
= tp_account_get_icon_name (account
);
1418 gtk_image_set_from_icon_name (GTK_IMAGE (information
->image_account
),
1419 name
, GTK_ICON_SIZE_MENU
);
1423 /* Update id widget */
1424 if (information
->flags
& EMPATHY_CONTACT_WIDGET_EDIT_ID
)
1425 gtk_entry_set_text (GTK_ENTRY (information
->widget_id
), id
? id
: "");
1427 gtk_label_set_label (GTK_LABEL (information
->widget_id
), id
? id
: "");
1429 /* Update other widgets */
1430 if (information
->contact
)
1432 contact_widget_name_notify_cb (information
);
1433 contact_widget_presence_notify_cb (information
);
1434 contact_widget_avatar_notify_cb (information
);
1436 gtk_widget_show (information
->label_alias
);
1437 gtk_widget_show (information
->widget_alias
);
1438 gtk_widget_show (information
->widget_avatar
);
1440 gtk_widget_set_visible (information
->hbox_presence
,
1441 !(information
->flags
& EMPATHY_CONTACT_WIDGET_NO_STATUS
));
1445 gtk_widget_hide (information
->label_alias
);
1446 gtk_widget_hide (information
->widget_alias
);
1447 gtk_widget_hide (information
->hbox_presence
);
1448 gtk_widget_hide (information
->widget_avatar
);
1453 contact_widget_set_contact (EmpathyContactWidget
*information
,
1454 EmpathyContact
*contact
)
1456 if (contact
== information
->contact
)
1459 contact_widget_remove_contact (information
);
1461 information
->contact
= g_object_ref (contact
);
1463 /* set the selected account to be the account this contact came from */
1464 if (contact
&& EMPATHY_IS_ACCOUNT_CHOOSER (information
->widget_account
)) {
1465 empathy_account_chooser_set_account (
1466 EMPATHY_ACCOUNT_CHOOSER (information
->widget_account
),
1467 empathy_contact_get_account (contact
));
1470 /* Update information for widgets */
1471 contact_widget_contact_update (information
);
1472 contact_widget_groups_update (information
);
1473 contact_widget_details_update (information
);
1474 contact_widget_client_update (information
);
1475 contact_widget_location_update (information
);
1479 contact_widget_got_contact_cb (TpConnection
*connection
,
1480 EmpathyContact
*contact
,
1481 const GError
*error
,
1483 GObject
*weak_object
)
1485 EmpathyContactWidget
*information
= user_data
;
1489 DEBUG ("Error: %s", error
->message
);
1493 contact_widget_set_contact (information
, contact
);
1497 contact_widget_change_contact (EmpathyContactWidget
*information
)
1499 TpConnection
*connection
;
1501 connection
= empathy_account_chooser_get_connection (
1502 EMPATHY_ACCOUNT_CHOOSER (information
->widget_account
));
1506 if (information
->flags
& EMPATHY_CONTACT_WIDGET_EDIT_ID
)
1510 id
= gtk_entry_get_text (GTK_ENTRY (information
->widget_id
));
1511 if (!EMP_STR_EMPTY (id
))
1513 empathy_tp_contact_factory_get_from_id (connection
, id
,
1514 contact_widget_got_contact_cb
, information
, NULL
,
1515 G_OBJECT (information
->vbox_contact_widget
));
1520 empathy_tp_contact_factory_get_from_handle (connection
,
1521 tp_connection_get_self_handle (connection
),
1522 contact_widget_got_contact_cb
, information
, NULL
,
1523 G_OBJECT (information
->vbox_contact_widget
));
1528 contact_widget_id_activate_timeout (EmpathyContactWidget
*self
)
1530 contact_widget_change_contact (self
);
1535 contact_widget_id_changed_cb (GtkEntry
*entry
,
1536 EmpathyContactWidget
*self
)
1538 if (self
->widget_id_timeout
!= 0)
1540 g_source_remove (self
->widget_id_timeout
);
1543 self
->widget_id_timeout
=
1544 g_timeout_add_seconds (ID_CHANGED_TIMEOUT
,
1545 (GSourceFunc
) contact_widget_id_activate_timeout
, self
);
1549 contact_widget_id_focus_out_cb (GtkWidget
*widget
,
1550 GdkEventFocus
*event
,
1551 EmpathyContactWidget
*information
)
1553 contact_widget_change_contact (information
);
1558 contact_widget_contact_setup (EmpathyContactWidget
*information
)
1560 information
->label_status
= gtk_label_new ("");
1561 gtk_label_set_line_wrap_mode (GTK_LABEL (information
->label_status
),
1562 PANGO_WRAP_WORD_CHAR
);
1563 gtk_label_set_line_wrap (GTK_LABEL (information
->label_status
),
1565 gtk_misc_set_alignment (GTK_MISC (information
->label_status
), 0, 0.5);
1567 if (!(information
->flags
& EMPATHY_CONTACT_WIDGET_FOR_TOOLTIP
))
1568 gtk_label_set_selectable (GTK_LABEL (information
->label_status
), TRUE
);
1570 gtk_box_pack_start (GTK_BOX (information
->hbox_presence
),
1571 information
->label_status
, TRUE
, TRUE
, 0);
1572 gtk_widget_show (information
->label_status
);
1574 /* Setup account label/chooser */
1575 if (information
->flags
& EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT
)
1577 information
->widget_account
= empathy_account_chooser_new ();
1579 g_signal_connect_swapped (information
->widget_account
, "changed",
1580 G_CALLBACK (contact_widget_change_contact
),
1585 /* Pack the protocol icon with the account name in an hbox */
1586 information
->widget_account
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 6);
1588 information
->label_account
= gtk_label_new (NULL
);
1589 if (!(information
->flags
& EMPATHY_CONTACT_WIDGET_FOR_TOOLTIP
)) {
1590 gtk_label_set_selectable (GTK_LABEL (information
->label_account
), TRUE
);
1592 gtk_misc_set_alignment (GTK_MISC (information
->label_account
), 0, 0.5);
1593 gtk_widget_show (information
->label_account
);
1595 information
->image_account
= gtk_image_new ();
1596 gtk_widget_show (information
->image_account
);
1598 gtk_box_pack_start (GTK_BOX (information
->widget_account
),
1599 information
->image_account
, FALSE
, FALSE
, 0);
1600 gtk_box_pack_start (GTK_BOX (information
->widget_account
),
1601 information
->label_account
, FALSE
, TRUE
, 0);
1604 gtk_grid_attach (GTK_GRID (information
->grid_contact
),
1605 information
->widget_account
,
1608 gtk_widget_show (information
->widget_account
);
1610 /* Set up avatar chooser/display */
1611 if (information
->flags
& EMPATHY_CONTACT_WIDGET_EDIT_AVATAR
)
1613 information
->widget_avatar
= empathy_avatar_chooser_new ();
1614 g_signal_connect (information
->widget_avatar
, "changed",
1615 G_CALLBACK (contact_widget_avatar_changed_cb
),
1617 if (information
->flags
& EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT
)
1619 g_signal_connect (information
->widget_account
, "changed",
1620 G_CALLBACK (update_avatar_chooser_account_cb
),
1621 information
->widget_avatar
);
1622 update_avatar_chooser_account_cb (
1623 EMPATHY_ACCOUNT_CHOOSER (information
->widget_account
),
1624 EMPATHY_AVATAR_CHOOSER (information
->widget_avatar
));
1629 information
->widget_avatar
= empathy_avatar_image_new ();
1631 g_signal_connect (information
->widget_avatar
, "popup-menu",
1632 G_CALLBACK (widget_avatar_popup_menu_cb
), information
);
1633 g_signal_connect (information
->widget_avatar
, "button-press-event",
1634 G_CALLBACK (widget_avatar_button_press_event_cb
), information
);
1637 gtk_box_pack_start (GTK_BOX (information
->vbox_avatar
),
1638 information
->widget_avatar
,
1641 gtk_widget_show (information
->widget_avatar
);
1643 /* Setup id label/entry */
1644 if (information
->flags
& EMPATHY_CONTACT_WIDGET_EDIT_ID
)
1646 information
->widget_id
= gtk_entry_new ();
1647 g_signal_connect (information
->widget_id
, "focus-out-event",
1648 G_CALLBACK (contact_widget_id_focus_out_cb
),
1650 g_signal_connect (information
->widget_id
, "changed",
1651 G_CALLBACK (contact_widget_id_changed_cb
),
1656 information
->widget_id
= gtk_label_new (NULL
);
1657 if (!(information
->flags
& EMPATHY_CONTACT_WIDGET_FOR_TOOLTIP
)) {
1658 gtk_label_set_selectable (GTK_LABEL (information
->widget_id
), TRUE
);
1660 gtk_misc_set_alignment (GTK_MISC (information
->widget_id
), 0, 0.5);
1663 gtk_grid_attach (GTK_GRID (information
->grid_contact
), information
->widget_id
,
1666 gtk_widget_show (information
->widget_id
);
1668 /* Setup alias label/entry */
1669 if (information
->flags
& EMPATHY_CONTACT_WIDGET_EDIT_ALIAS
)
1671 information
->widget_alias
= gtk_entry_new ();
1673 if (!(information
->flags
& EMPATHY_CONTACT_WIDGET_NO_SET_ALIAS
))
1674 g_signal_connect (information
->widget_alias
, "focus-out-event",
1675 G_CALLBACK (contact_widget_entry_alias_focus_event_cb
),
1678 /* Make return activate the window default (the Close button) */
1679 gtk_entry_set_activates_default (GTK_ENTRY (information
->widget_alias
),
1684 information
->widget_alias
= gtk_label_new (NULL
);
1685 if (!(information
->flags
& EMPATHY_CONTACT_WIDGET_FOR_TOOLTIP
)) {
1686 gtk_label_set_selectable (GTK_LABEL (information
->widget_alias
), TRUE
);
1688 gtk_misc_set_alignment (GTK_MISC (information
->widget_alias
), 0, 0.5);
1691 gtk_grid_attach (GTK_GRID (information
->grid_contact
),
1692 information
->widget_alias
, 1, 2, 1, 1);
1694 if (information
->flags
& EMPATHY_CONTACT_WIDGET_FOR_TOOLTIP
) {
1695 gtk_label_set_selectable (GTK_LABEL (information
->label_status
), FALSE
);
1697 gtk_widget_show (information
->widget_alias
);
1701 contact_widget_destroy_cb (GtkWidget
*widget
,
1702 EmpathyContactWidget
*information
)
1704 contact_widget_remove_contact (information
);
1706 if (information
->widget_id_timeout
!= 0)
1708 g_source_remove (information
->widget_id_timeout
);
1711 g_slice_free (EmpathyContactWidget
, information
);
1715 * empathy_contact_widget_new:
1716 * @contact: an #EmpathyContact
1717 * @flags: #EmpathyContactWidgetFlags for the new contact widget
1719 * Creates a new #EmpathyContactWidget.
1721 * Return value: a new #EmpathyContactWidget
1724 empathy_contact_widget_new (EmpathyContact
*contact
,
1725 EmpathyContactWidgetFlags flags
)
1727 EmpathyContactWidget
*information
;
1731 g_return_val_if_fail (contact
== NULL
|| EMPATHY_IS_CONTACT (contact
), NULL
);
1733 information
= g_slice_new0 (EmpathyContactWidget
);
1734 information
->flags
= flags
;
1736 filename
= empathy_file_lookup ("empathy-contact-widget.ui",
1738 gui
= empathy_builder_get_file (filename
,
1739 "vbox_contact_widget", &information
->vbox_contact_widget
,
1740 "hbox_presence", &information
->hbox_presence
,
1741 "label_alias", &information
->label_alias
,
1742 "image_state", &information
->image_state
,
1743 "grid_contact", &information
->grid_contact
,
1744 "vbox_avatar", &information
->vbox_avatar
,
1745 "vbox_location", &information
->vbox_location
,
1746 "subvbox_location", &information
->subvbox_location
,
1747 "label_location", &information
->label_location
,
1748 #ifdef HAVE_LIBCHAMPLAIN
1749 "viewport_map", &information
->viewport_map
,
1751 "groups_widget", &information
->groups_widget
,
1752 "vbox_details", &information
->vbox_details
,
1753 "grid_details", &information
->grid_details
,
1754 "hbox_details_requested", &information
->hbox_details_requested
,
1755 "vbox_client", &information
->vbox_client
,
1756 "grid_client", &information
->grid_client
,
1757 "hbox_client_requested", &information
->hbox_client_requested
,
1761 empathy_builder_connect (gui
, information
,
1762 "vbox_contact_widget", "destroy", contact_widget_destroy_cb
,
1764 information
->grid_location
= NULL
;
1766 g_object_set_data (G_OBJECT (information
->vbox_contact_widget
),
1767 "EmpathyContactWidget",
1770 /* Create widgets */
1771 contact_widget_contact_setup (information
);
1772 contact_widget_details_setup (information
);
1773 contact_widget_client_setup (information
);
1775 if (contact
!= NULL
)
1776 contact_widget_set_contact (information
, contact
);
1777 else if (information
->flags
& EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT
||
1778 information
->flags
& EMPATHY_CONTACT_WIDGET_EDIT_ID
)
1779 contact_widget_change_contact (information
);
1781 return empathy_builder_unref_and_keep_widget (gui
,
1782 information
->vbox_contact_widget
);
1786 * empathy_contact_widget_get_contact:
1787 * @widget: an #EmpathyContactWidget
1789 * Get the #EmpathyContact related with the #EmpathyContactWidget @widget.
1791 * Returns: the #EmpathyContact associated with @widget
1794 empathy_contact_widget_get_contact (GtkWidget
*widget
)
1796 EmpathyContactWidget
*information
;
1798 g_return_val_if_fail (GTK_IS_WIDGET (widget
), NULL
);
1800 information
= g_object_get_data (G_OBJECT (widget
), "EmpathyContactWidget");
1804 return information
->contact
;
1808 empathy_contact_widget_get_alias (GtkWidget
*widget
)
1810 EmpathyContactWidget
*information
;
1812 g_return_val_if_fail (GTK_IS_WIDGET (widget
), NULL
);
1814 information
= g_object_get_data (G_OBJECT (widget
), "EmpathyContactWidget");
1818 return gtk_entry_get_text (GTK_ENTRY (information
->widget_alias
));
1822 * empathy_contact_widget_set_contact:
1823 * @widget: an #EmpathyContactWidget
1824 * @contact: a different #EmpathyContact
1826 * Change the #EmpathyContact related with the #EmpathyContactWidget @widget.
1829 empathy_contact_widget_set_contact (GtkWidget
*widget
,
1830 EmpathyContact
*contact
)
1832 EmpathyContactWidget
*information
;
1834 g_return_if_fail (GTK_IS_WIDGET (widget
));
1835 g_return_if_fail (EMPATHY_IS_CONTACT (contact
));
1837 information
= g_object_get_data (G_OBJECT (widget
), "EmpathyContactWidget");
1841 contact_widget_set_contact (information
, contact
);
1845 * empathy_contact_widget_set_account_filter:
1846 * @widget: an #EmpathyContactWidget
1847 * @filter: a #EmpathyAccountChooserFilterFunc
1848 * @user_data: user data to pass to @filter, or %NULL
1850 * Set a filter on the #EmpathyAccountChooser included in the
1851 * #EmpathyContactWidget.
1854 empathy_contact_widget_set_account_filter (
1856 EmpathyAccountChooserFilterFunc filter
,
1859 EmpathyContactWidget
*information
;
1860 EmpathyAccountChooser
*chooser
;
1862 g_return_if_fail (GTK_IS_WIDGET (widget
));
1864 information
= g_object_get_data (G_OBJECT (widget
), "EmpathyContactWidget");
1868 chooser
= EMPATHY_ACCOUNT_CHOOSER (information
->widget_account
);
1870 empathy_account_chooser_set_filter (chooser
, filter
, user_data
);