2 #include "empathy-roster-contact.h"
4 #include <glib/gi18n-lib.h>
5 #include <tp-account-widgets/tpaw-images.h>
6 #include <tp-account-widgets/tpaw-pixbuf-utils.h>
8 #include "empathy-ui-utils.h"
9 #include "empathy-utils.h"
11 G_DEFINE_TYPE (EmpathyRosterContact
, empathy_roster_contact
, GTK_TYPE_LIST_BOX_ROW
)
13 #define AVATAR_SIZE 48
21 PROP_MOST_RECENT_EVENT
,
31 static guint signals[LAST_SIGNAL];
34 struct _EmpathyRosterContactPriv
36 FolksIndividual
*individual
;
37 EmpathyContact
*contact
;
40 TplLogManager
*log_manager
;
41 TplEvent
*most_recent_event
;
44 GtkWidget
*first_line_alig
;
46 GtkWidget
*presence_msg
;
47 GtkWidget
*most_recent_msg
;
48 GtkWidget
*presence_icon
;
49 GtkWidget
*phone_icon
;
51 /* If not NULL, used instead of the individual's presence icon */
58 get_alias (EmpathyRosterContact
*self
)
60 return folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (
61 self
->priv
->individual
));
65 empathy_roster_contact_get_property (GObject
*object
,
70 EmpathyRosterContact
*self
= EMPATHY_ROSTER_CONTACT (object
);
74 case PROP_INDIVIDIUAL
:
75 g_value_set_object (value
, self
->priv
->individual
);
78 g_value_set_string (value
, self
->priv
->group
);
81 g_value_set_boolean (value
, self
->priv
->online
);
84 g_value_set_string (value
, get_alias (self
));
86 case PROP_MOST_RECENT_EVENT
:
87 g_value_set_object (value
, self
->priv
->most_recent_event
);
90 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
96 empathy_roster_contact_set_property (GObject
*object
,
101 EmpathyRosterContact
*self
= EMPATHY_ROSTER_CONTACT (object
);
105 case PROP_INDIVIDIUAL
:
106 g_assert (self
->priv
->individual
== NULL
); /* construct only */
107 self
->priv
->individual
= g_value_dup_object (value
);
110 g_assert (self
->priv
->group
== NULL
); /* construct only */
111 self
->priv
->group
= g_value_dup_string (value
);
114 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
120 empathy_roster_contact_get_most_recent_timestamp (EmpathyRosterContact
*contact
)
122 if (contact
->priv
->most_recent_event
) {
123 return tpl_event_get_timestamp (contact
->priv
->most_recent_event
);
129 get_most_recent_message (EmpathyRosterContact
*contact
)
131 if (contact
->priv
->most_recent_event
) {
132 return tpl_text_event_get_message (TPL_TEXT_EVENT(contact
->priv
->most_recent_event
));
138 avatar_loaded_cb (GObject
*source
,
139 GAsyncResult
*result
,
142 TpWeakRef
*wr
= user_data
;
143 EmpathyRosterContact
*self
;
146 self
= tp_weak_ref_dup_object (wr
);
150 pixbuf
= empathy_pixbuf_avatar_from_individual_scaled_finish (
151 FOLKS_INDIVIDUAL (source
), result
, NULL
);
155 pixbuf
= tpaw_pixbuf_from_icon_name_sized (
156 TPAW_IMAGE_AVATAR_DEFAULT
, AVATAR_SIZE
);
159 gtk_image_set_from_pixbuf (GTK_IMAGE (self
->priv
->avatar
), pixbuf
);
160 g_object_unref (pixbuf
);
162 g_object_unref (self
);
165 tp_weak_ref_destroy (wr
);
169 update_most_recent_msg (EmpathyRosterContact
*self
)
171 const gchar
* msg
= get_most_recent_message (self
);
173 if (tp_str_empty (msg
))
175 gtk_alignment_set (GTK_ALIGNMENT (self
->priv
->first_line_alig
),
177 gtk_widget_hide (self
->priv
->most_recent_msg
);
181 gchar
*tmp
= g_strdup (msg
);
182 if (strchr(tmp
, '\n')) strchr(tmp
, '\n')[0] = 0;
183 gtk_label_set_text (GTK_LABEL (self
->priv
->most_recent_msg
), tmp
);
184 gtk_alignment_set (GTK_ALIGNMENT (self
->priv
->first_line_alig
),
186 gtk_misc_set_alignment (GTK_MISC (self
->priv
->most_recent_msg
), 0, 0.25);
192 update_avatar (EmpathyRosterContact
*self
)
194 empathy_pixbuf_avatar_from_individual_scaled_async (self
->priv
->individual
,
195 AVATAR_SIZE
, AVATAR_SIZE
, NULL
, avatar_loaded_cb
,
196 tp_weak_ref_new (self
, NULL
, NULL
));
200 avatar_changed_cb (FolksIndividual
*individual
,
202 EmpathyRosterContact
*self
)
204 update_avatar (self
);
208 update_alias (EmpathyRosterContact
*self
)
210 gtk_label_set_text (GTK_LABEL (self
->priv
->alias
), get_alias (self
));
212 g_object_notify (G_OBJECT (self
), "alias");
216 alias_changed_cb (FolksIndividual
*individual
,
218 EmpathyRosterContact
*self
)
224 update_presence_msg (EmpathyRosterContact
*self
)
229 msg
= folks_presence_details_get_presence_message (
230 FOLKS_PRESENCE_DETAILS (self
->priv
->individual
));
232 if (tp_str_empty (msg
))
234 /* Just display the alias in the center of the row */
235 gtk_alignment_set (GTK_ALIGNMENT (self
->priv
->first_line_alig
),
238 gtk_widget_hide (self
->priv
->presence_msg
);
242 FolksPresenceType type
;
244 type
= folks_presence_details_get_presence_type (
245 FOLKS_PRESENCE_DETAILS (self
->priv
->individual
));
246 if (type
== FOLKS_PRESENCE_TYPE_ERROR
)
250 /* Add a prefix explaining that something goes wrong when trying to
251 * fetch contact's presence. */
252 tmp
= g_strdup_printf (_("Server cannot find contact: %s"), msg
);
253 gtk_label_set_text (GTK_LABEL (self
->priv
->presence_msg
), tmp
);
259 gtk_label_set_text (GTK_LABEL (self
->priv
->presence_msg
), msg
);
262 gtk_alignment_set (GTK_ALIGNMENT (self
->priv
->first_line_alig
),
264 gtk_misc_set_alignment (GTK_MISC (self
->priv
->presence_msg
), 0, 0.25);
266 gtk_widget_show (self
->priv
->presence_msg
);
269 types
= (GStrv
) empathy_individual_get_client_types (self
->priv
->individual
);
271 gtk_widget_set_visible (self
->priv
->phone_icon
,
272 empathy_client_types_contains_mobile_device (types
));
276 presence_message_changed_cb (FolksIndividual
*individual
,
278 EmpathyRosterContact
*self
)
280 update_presence_msg (self
);
284 update_presence_icon (EmpathyRosterContact
*self
)
288 if (self
->priv
->event_icon
== NULL
)
289 icon
= empathy_icon_name_for_individual (self
->priv
->individual
);
291 icon
= self
->priv
->event_icon
;
293 gtk_image_set_from_icon_name (GTK_IMAGE (self
->priv
->presence_icon
), icon
,
298 update_online (EmpathyRosterContact
*self
)
300 FolksPresenceType presence
;
303 presence
= folks_presence_details_get_presence_type (
304 FOLKS_PRESENCE_DETAILS (self
->priv
->individual
));
308 case FOLKS_PRESENCE_TYPE_UNSET
:
309 case FOLKS_PRESENCE_TYPE_OFFLINE
:
310 case FOLKS_PRESENCE_TYPE_UNKNOWN
:
311 case FOLKS_PRESENCE_TYPE_ERROR
:
315 case FOLKS_PRESENCE_TYPE_AVAILABLE
:
316 case FOLKS_PRESENCE_TYPE_AWAY
:
317 case FOLKS_PRESENCE_TYPE_EXTENDED_AWAY
:
318 case FOLKS_PRESENCE_TYPE_HIDDEN
:
319 case FOLKS_PRESENCE_TYPE_BUSY
:
324 g_warning ("Unknown FolksPresenceType: %d", presence
);
328 if (self
->priv
->online
== online
)
331 self
->priv
->online
= online
;
332 g_object_notify (G_OBJECT (self
), "online");
336 presence_status_changed_cb (FolksIndividual
*individual
,
338 EmpathyRosterContact
*self
)
340 update_presence_icon (self
);
341 update_online (self
);
345 get_filtered_events (GObject
*source_object
, GAsyncResult
*res
, gpointer user_data
)
347 EmpathyRosterContact
*contact
= EMPATHY_ROSTER_CONTACT (user_data
);
352 if (!tpl_log_manager_get_filtered_events_finish (contact
->priv
->log_manager
, res
, &events
, &error
))
354 g_warning ("Unable to get events: %s", error
->message
);
355 g_error_free (error
);
360 contact
->priv
->most_recent_event
= TPL_EVENT (events
->data
);
361 g_object_notify (G_OBJECT (contact
), "most-recent-event");
362 update_most_recent_msg (contact
);
370 empathy_roster_contact_constructed (GObject
*object
)
372 EmpathyRosterContact
*self
= EMPATHY_ROSTER_CONTACT (object
);
373 TplEntity
*tpl_entity
;
374 void (*chain_up
) (GObject
*) =
375 ((GObjectClass
*) empathy_roster_contact_parent_class
)->constructed
;
377 if (chain_up
!= NULL
)
380 g_assert (FOLKS_IS_INDIVIDUAL (self
->priv
->individual
));
382 self
->priv
->contact
= empathy_contact_dup_best_for_action (
383 self
->priv
->individual
,
384 EMPATHY_ACTION_CHAT
);
386 self
->priv
->log_manager
= tpl_log_manager_dup_singleton ();
388 tpl_entity
= tpl_entity_new_from_tp_contact (
389 empathy_contact_get_tp_contact (self
->priv
->contact
),
391 tpl_log_manager_get_filtered_events_async(
392 self
->priv
->log_manager
,
393 empathy_contact_get_account (self
->priv
->contact
),
402 tp_g_signal_connect_object (self
->priv
->individual
, "notify::avatar",
403 G_CALLBACK (avatar_changed_cb
), self
, 0);
404 tp_g_signal_connect_object (self
->priv
->individual
, "notify::alias",
405 G_CALLBACK (alias_changed_cb
), self
, 0);
406 tp_g_signal_connect_object (self
->priv
->individual
,
407 "notify::presence-message",
408 G_CALLBACK (presence_message_changed_cb
), self
, 0);
409 tp_g_signal_connect_object (self
->priv
->individual
, "notify::presence-status",
410 G_CALLBACK (presence_status_changed_cb
), self
, 0);
412 update_avatar (self
);
414 update_presence_msg (self
);
415 update_presence_icon (self
);
417 update_online (self
);
421 empathy_roster_contact_dispose (GObject
*object
)
423 EmpathyRosterContact
*self
= EMPATHY_ROSTER_CONTACT (object
);
424 void (*chain_up
) (GObject
*) =
425 ((GObjectClass
*) empathy_roster_contact_parent_class
)->dispose
;
427 g_clear_object (&self
->priv
->individual
);
429 if (chain_up
!= NULL
)
434 empathy_roster_contact_finalize (GObject
*object
)
436 EmpathyRosterContact
*self
= EMPATHY_ROSTER_CONTACT (object
);
437 void (*chain_up
) (GObject
*) =
438 ((GObjectClass
*) empathy_roster_contact_parent_class
)->finalize
;
440 g_free (self
->priv
->group
);
441 g_free (self
->priv
->event_icon
);
442 g_object_unref (self
->priv
->log_manager
);
444 if (chain_up
!= NULL
)
449 empathy_roster_contact_class_init (
450 EmpathyRosterContactClass
*klass
)
452 GObjectClass
*oclass
= G_OBJECT_CLASS (klass
);
455 oclass
->get_property
= empathy_roster_contact_get_property
;
456 oclass
->set_property
= empathy_roster_contact_set_property
;
457 oclass
->constructed
= empathy_roster_contact_constructed
;
458 oclass
->dispose
= empathy_roster_contact_dispose
;
459 oclass
->finalize
= empathy_roster_contact_finalize
;
461 spec
= g_param_spec_object ("individual", "Individual",
463 FOLKS_TYPE_INDIVIDUAL
,
464 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
| G_PARAM_STATIC_STRINGS
);
465 g_object_class_install_property (oclass
, PROP_INDIVIDIUAL
, spec
);
467 spec
= g_param_spec_string ("group", "Group",
468 "Group of this widget, or NULL",
470 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
| G_PARAM_STATIC_STRINGS
);
471 g_object_class_install_property (oclass
, PROP_GROUP
, spec
);
473 spec
= g_param_spec_boolean ("online", "Online",
474 "TRUE if Individual is online",
476 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
477 g_object_class_install_property (oclass
, PROP_ONLINE
, spec
);
479 spec
= g_param_spec_string ("alias", "Alias",
480 "The Alias of the individual displayed in the widget",
482 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
483 g_object_class_install_property (oclass
, PROP_ALIAS
, spec
);
485 spec
= g_param_spec_object ("most-recent-event", "Most recent event",
488 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
489 g_object_class_install_property (oclass
, PROP_MOST_RECENT_EVENT
, spec
);
491 g_type_class_add_private (klass
, sizeof (EmpathyRosterContactPriv
));
495 empathy_roster_contact_init (EmpathyRosterContact
*self
)
497 GtkWidget
*alig
, *main_box
, *box
, *first_line_box
;
498 GtkStyleContext
*context
;
500 self
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (self
,
501 EMPATHY_TYPE_ROSTER_CONTACT
, EmpathyRosterContactPriv
);
503 alig
= gtk_alignment_new (0.5, 0.5, 1, 1);
504 gtk_widget_show (alig
);
505 gtk_alignment_set_padding (GTK_ALIGNMENT (alig
), 4, 4, 4, 12);
507 main_box
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 8);
510 self
->priv
->avatar
= gtk_image_new ();
512 gtk_widget_set_size_request (self
->priv
->avatar
, AVATAR_SIZE
, AVATAR_SIZE
);
514 gtk_box_pack_start (GTK_BOX (main_box
), self
->priv
->avatar
, FALSE
, FALSE
, 0);
515 gtk_widget_show (self
->priv
->avatar
);
517 box
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 0);
519 /* Alias and phone icon */
520 self
->priv
->first_line_alig
= gtk_alignment_new (0, 0.5, 1, 1);
521 first_line_box
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 0);
523 self
->priv
->alias
= gtk_label_new (NULL
);
524 gtk_label_set_ellipsize (GTK_LABEL (self
->priv
->alias
), PANGO_ELLIPSIZE_END
);
525 gtk_box_pack_start (GTK_BOX (first_line_box
), self
->priv
->alias
,
527 gtk_misc_set_alignment (GTK_MISC (self
->priv
->alias
), 0, 0.5);
528 gtk_widget_show (self
->priv
->alias
);
530 self
->priv
->phone_icon
= gtk_image_new_from_icon_name ("phone-symbolic",
532 gtk_misc_set_alignment (GTK_MISC (self
->priv
->phone_icon
), 0, 0.5);
533 gtk_box_pack_start (GTK_BOX (first_line_box
), self
->priv
->phone_icon
,
536 gtk_container_add (GTK_CONTAINER (self
->priv
->first_line_alig
),
538 gtk_widget_show (self
->priv
->first_line_alig
);
540 gtk_box_pack_start (GTK_BOX (box
), self
->priv
->first_line_alig
,
542 gtk_widget_show (first_line_box
);
544 gtk_box_pack_start (GTK_BOX (main_box
), box
, TRUE
, TRUE
, 0);
545 gtk_widget_show (box
);
548 self
->priv
->presence_msg
= gtk_label_new (NULL
);
549 gtk_label_set_ellipsize (GTK_LABEL (self
->priv
->presence_msg
),
550 PANGO_ELLIPSIZE_END
);
552 gtk_box_pack_start (GTK_BOX (box), self->priv->presence_msg, TRUE, TRUE, 0);
553 gtk_widget_show (self->priv->presence_msg);
556 context
= gtk_widget_get_style_context (self
->priv
->presence_msg
);
557 gtk_style_context_add_class (context
, GTK_STYLE_CLASS_DIM_LABEL
);
559 /* Most recent message */
560 self
->priv
->most_recent_msg
= gtk_label_new (NULL
);
561 gtk_label_set_ellipsize (GTK_LABEL (self
->priv
->most_recent_msg
),
562 PANGO_ELLIPSIZE_END
);
563 gtk_box_pack_start (GTK_BOX (box
), self
->priv
->most_recent_msg
, TRUE
, TRUE
, 0);
564 gtk_widget_show (self
->priv
->most_recent_msg
);
566 context
= gtk_widget_get_style_context (self
->priv
->most_recent_msg
);
567 gtk_style_context_add_class (context
, GTK_STYLE_CLASS_DIM_LABEL
);
570 self
->priv
->presence_icon
= gtk_image_new ();
572 gtk_box_pack_start (GTK_BOX (main_box
), self
->priv
->presence_icon
,
574 gtk_widget_show (self
->priv
->presence_icon
);
576 gtk_container_add (GTK_CONTAINER (self
), alig
);
577 gtk_container_add (GTK_CONTAINER (alig
), main_box
);
578 gtk_widget_show (main_box
);
582 empathy_roster_contact_new (FolksIndividual
*individual
,
585 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual
), NULL
);
587 return g_object_new (EMPATHY_TYPE_ROSTER_CONTACT
,
588 "individual", individual
,
594 empathy_roster_contact_get_individual (EmpathyRosterContact
*self
)
596 return self
->priv
->individual
;
600 empathy_roster_contact_get_contact (EmpathyRosterContact
*self
)
602 return self
->priv
->contact
;
606 empathy_roster_contact_is_online (EmpathyRosterContact
*self
)
608 return self
->priv
->online
;
612 empathy_roster_contact_get_group (EmpathyRosterContact
*self
)
614 return self
->priv
->group
;
618 empathy_roster_contact_set_event_icon (EmpathyRosterContact
*self
,
621 if (!tp_strdiff (self
->priv
->event_icon
, icon
))
624 g_free (self
->priv
->event_icon
);
625 self
->priv
->event_icon
= g_strdup (icon
);
627 update_presence_icon (self
);
631 empathy_roster_contact_get_avatar_pixbuf (EmpathyRosterContact
*self
)
633 return gtk_image_get_pixbuf (GTK_IMAGE (self
->priv
->avatar
));