From 6aef9eda7957ac651f21b6a54efac85ad71e7d3c Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 25 May 2012 13:32:38 +0200 Subject: rename EmpathyRosterItem to EmpathyRosterContact --- libempathy-gtk/empathy-roster-contact.c | 452 ++++++++++++++++++++++++++++++++ 1 file changed, 452 insertions(+) create mode 100644 libempathy-gtk/empathy-roster-contact.c (limited to 'libempathy-gtk/empathy-roster-contact.c') diff --git a/libempathy-gtk/empathy-roster-contact.c b/libempathy-gtk/empathy-roster-contact.c new file mode 100644 index 000000000..3b30d2517 --- /dev/null +++ b/libempathy-gtk/empathy-roster-contact.c @@ -0,0 +1,452 @@ +#include "config.h" + +#include "empathy-roster-contact.h" + +#include + +#include + +#include +#include + +G_DEFINE_TYPE (EmpathyRosterContact, empathy_roster_contact, GTK_TYPE_ALIGNMENT) + +#define AVATAR_SIZE 48 + +enum +{ + PROP_INDIVIDIUAL = 1, + PROP_ONLINE, + PROP_ALIAS, + N_PROPS +}; + +/* +enum +{ + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; +*/ + +struct _EmpathyRosterContactPriv +{ + FolksIndividual *individual; + + GtkWidget *avatar; + GtkWidget *first_line_alig; + GtkWidget *alias; + GtkWidget *presence_msg; + GtkWidget *presence_icon; + GtkWidget *phone_icon; + + gboolean online; +}; + +static const gchar * +get_alias (EmpathyRosterContact *self) +{ + return folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS ( + self->priv->individual)); +} + +static void +empathy_roster_contact_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + EmpathyRosterContact *self = EMPATHY_ROSTER_CONTACT (object); + + switch (property_id) + { + case PROP_INDIVIDIUAL: + g_value_set_object (value, self->priv->individual); + break; + case PROP_ONLINE: + g_value_set_boolean (value, self->priv->online); + break; + case PROP_ALIAS: + g_value_set_string (value, get_alias (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +empathy_roster_contact_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + EmpathyRosterContact *self = EMPATHY_ROSTER_CONTACT (object); + + switch (property_id) + { + case PROP_INDIVIDIUAL: + g_assert (self->priv->individual == NULL); /* construct only */ + self->priv->individual = g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +avatar_loaded_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + TpWeakRef *wr = user_data; + EmpathyRosterContact *self; + GdkPixbuf *pixbuf; + + self = tp_weak_ref_dup_object (wr); + if (self == NULL) + goto out; + + pixbuf = empathy_pixbuf_avatar_from_individual_scaled_finish ( + FOLKS_INDIVIDUAL (source), result, NULL); + + if (pixbuf == NULL) + { + pixbuf = empathy_pixbuf_from_icon_name_sized ( + EMPATHY_IMAGE_AVATAR_DEFAULT, AVATAR_SIZE); + } + + gtk_image_set_from_pixbuf (GTK_IMAGE (self->priv->avatar), pixbuf); + g_object_unref (pixbuf); + + g_object_unref (self); + +out: + tp_weak_ref_destroy (wr); +} + +static void +update_avatar (EmpathyRosterContact *self) +{ + empathy_pixbuf_avatar_from_individual_scaled_async (self->priv->individual, + AVATAR_SIZE, AVATAR_SIZE, NULL, avatar_loaded_cb, + tp_weak_ref_new (self, NULL, NULL)); +} + +static void +avatar_changed_cb (FolksIndividual *individual, + GParamSpec *spec, + EmpathyRosterContact *self) +{ + update_avatar (self); +} + +static void +update_alias (EmpathyRosterContact *self) +{ + gtk_label_set_text (GTK_LABEL (self->priv->alias), get_alias (self)); + + g_object_notify (G_OBJECT (self), "alias"); +} + +static void +alias_changed_cb (FolksIndividual *individual, + GParamSpec *spec, + EmpathyRosterContact *self) +{ + update_alias (self); +} + +static gboolean +is_phone (FolksIndividual *individual) +{ + const gchar * const *types; + + types = empathy_individual_get_client_types (individual); + if (types == NULL) + return FALSE; + + if (g_strv_length ((GStrv) types) <= 0) + return FALSE; + + return !tp_strdiff (types[0], "phone"); +} + +static void +update_presence_msg (EmpathyRosterContact *self) +{ + const gchar *msg; + + msg = folks_presence_details_get_presence_message ( + FOLKS_PRESENCE_DETAILS (self->priv->individual)); + + if (tp_str_empty (msg)) + { + /* Just display the alias in the center of the row */ + gtk_alignment_set (GTK_ALIGNMENT (self->priv->first_line_alig), + 0, 0.5, 1, 1); + + gtk_widget_hide (self->priv->presence_msg); + } + else + { + gtk_label_set_text (GTK_LABEL (self->priv->presence_msg), msg); + + gtk_alignment_set (GTK_ALIGNMENT (self->priv->first_line_alig), + 0, 0.75, 1, 1); + gtk_misc_set_alignment (GTK_MISC (self->priv->presence_msg), 0, 0.25); + + gtk_widget_show (self->priv->presence_msg); + } + + gtk_widget_set_visible (self->priv->phone_icon, + is_phone (self->priv->individual)); +} + +static void +presence_message_changed_cb (FolksIndividual *individual, + GParamSpec *spec, + EmpathyRosterContact *self) +{ + update_presence_msg (self); +} + +static void +update_presence_icon (EmpathyRosterContact *self) +{ + const gchar *icon; + + icon = empathy_icon_name_for_individual (self->priv->individual); + + gtk_image_set_from_icon_name (GTK_IMAGE (self->priv->presence_icon), icon, + GTK_ICON_SIZE_MENU); +} + +static void +update_online (EmpathyRosterContact *self) +{ + FolksPresenceType presence; + gboolean online; + + presence = folks_presence_details_get_presence_type ( + FOLKS_PRESENCE_DETAILS (self->priv->individual)); + + switch (presence) + { + case FOLKS_PRESENCE_TYPE_UNSET: + case FOLKS_PRESENCE_TYPE_OFFLINE: + case FOLKS_PRESENCE_TYPE_UNKNOWN: + case FOLKS_PRESENCE_TYPE_ERROR: + online = FALSE; + break; + + case FOLKS_PRESENCE_TYPE_AVAILABLE: + case FOLKS_PRESENCE_TYPE_AWAY: + case FOLKS_PRESENCE_TYPE_EXTENDED_AWAY: + case FOLKS_PRESENCE_TYPE_HIDDEN: + case FOLKS_PRESENCE_TYPE_BUSY: + online = TRUE; + break; + + default: + g_warning ("Unknown FolksPresenceType: %d", presence); + online = FALSE; + } + + if (self->priv->online == online) + return; + + self->priv->online = online; + g_object_notify (G_OBJECT (self), "online"); +} + +static void +presence_status_changed_cb (FolksIndividual *individual, + GParamSpec *spec, + EmpathyRosterContact *self) +{ + update_presence_icon (self); + update_online (self); +} + +static void +empathy_roster_contact_constructed (GObject *object) +{ + EmpathyRosterContact *self = EMPATHY_ROSTER_CONTACT (object); + void (*chain_up) (GObject *) = + ((GObjectClass *) empathy_roster_contact_parent_class)->constructed; + + if (chain_up != NULL) + chain_up (object); + + g_assert (FOLKS_IS_INDIVIDUAL (self->priv->individual)); + + tp_g_signal_connect_object (self->priv->individual, "notify::avatar", + G_CALLBACK (avatar_changed_cb), self, 0); + tp_g_signal_connect_object (self->priv->individual, "notify::alias", + G_CALLBACK (alias_changed_cb), self, 0); + tp_g_signal_connect_object (self->priv->individual, + "notify::presence-message", + G_CALLBACK (presence_message_changed_cb), self, 0); + tp_g_signal_connect_object (self->priv->individual, "notify::presence-status", + G_CALLBACK (presence_status_changed_cb), self, 0); + + update_avatar (self); + update_alias (self); + update_presence_msg (self); + update_presence_icon (self); + + update_online (self); +} + +static void +empathy_roster_contact_dispose (GObject *object) +{ + EmpathyRosterContact *self = EMPATHY_ROSTER_CONTACT (object); + void (*chain_up) (GObject *) = + ((GObjectClass *) empathy_roster_contact_parent_class)->dispose; + + g_clear_object (&self->priv->individual); + + if (chain_up != NULL) + chain_up (object); +} + +static void +empathy_roster_contact_finalize (GObject *object) +{ + //EmpathyRosterContact *self = EMPATHY_ROSTER_CONTACT (object); + void (*chain_up) (GObject *) = + ((GObjectClass *) empathy_roster_contact_parent_class)->finalize; + + if (chain_up != NULL) + chain_up (object); +} + +static void +empathy_roster_contact_class_init ( + EmpathyRosterContactClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + GParamSpec *spec; + + oclass->get_property = empathy_roster_contact_get_property; + oclass->set_property = empathy_roster_contact_set_property; + oclass->constructed = empathy_roster_contact_constructed; + oclass->dispose = empathy_roster_contact_dispose; + oclass->finalize = empathy_roster_contact_finalize; + + spec = g_param_spec_object ("individual", "Individual", + "FolksIndividual", + FOLKS_TYPE_INDIVIDUAL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (oclass, PROP_INDIVIDIUAL, spec); + + spec = g_param_spec_boolean ("online", "Online", + "TRUE if Individual is online", + FALSE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (oclass, PROP_ONLINE, spec); + + spec = g_param_spec_string ("alias", "Alias", + "The Alias of the individual displayed in the widget", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (oclass, PROP_ALIAS, spec); + + g_type_class_add_private (klass, sizeof (EmpathyRosterContactPriv)); +} + +static void +empathy_roster_contact_init (EmpathyRosterContact *self) +{ + GtkWidget *main_box, *box, *first_line_box; + GtkStyleContext *context; + + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + EMPATHY_TYPE_ROSTER_CONTACT, EmpathyRosterContactPriv); + + gtk_widget_set_size_request (GTK_WIDGET (self), 300, 64); + + main_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8); + + /* Avatar */ + self->priv->avatar = gtk_image_new (); + + gtk_box_pack_start (GTK_BOX (main_box), self->priv->avatar, FALSE, FALSE, 0); + gtk_widget_show (self->priv->avatar); + + box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + + /* Alias and phone icon */ + self->priv->first_line_alig = gtk_alignment_new (0, 0.5, 1, 1); + first_line_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + + self->priv->alias = gtk_label_new (NULL); + gtk_box_pack_start (GTK_BOX (first_line_box), self->priv->alias, + FALSE, FALSE, 0); + gtk_widget_show (self->priv->alias); + + self->priv->phone_icon = gtk_image_new_from_icon_name ("phone-symbolic", + GTK_ICON_SIZE_MENU); + gtk_misc_set_alignment (GTK_MISC (self->priv->phone_icon), 0, 0.5); + gtk_box_pack_start (GTK_BOX (first_line_box), self->priv->phone_icon, + TRUE, TRUE, 0); + + gtk_container_add (GTK_CONTAINER (self->priv->first_line_alig), + first_line_box); + gtk_widget_show (self->priv->first_line_alig); + + gtk_box_pack_start (GTK_BOX (box), self->priv->first_line_alig, + TRUE, TRUE, 0); + gtk_widget_show (first_line_box); + + gtk_box_pack_start (GTK_BOX (main_box), box, TRUE, TRUE, 0); + gtk_widget_show (box); + + /* Presence */ + self->priv->presence_msg = gtk_label_new (NULL); + gtk_box_pack_start (GTK_BOX (box), self->priv->presence_msg, TRUE, TRUE, 0); + gtk_widget_show (self->priv->presence_msg); + + context = gtk_widget_get_style_context (self->priv->presence_msg); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_DIM_LABEL); + + /* Presence icon */ + self->priv->presence_icon = gtk_image_new (); + + gtk_box_pack_start (GTK_BOX (main_box), self->priv->presence_icon, + FALSE, FALSE, 0); + gtk_widget_show (self->priv->presence_icon); + + gtk_container_add (GTK_CONTAINER (self), main_box); + gtk_widget_show (main_box); +} + +GtkWidget * +empathy_roster_contact_new (FolksIndividual *individual) +{ + g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual), NULL); + + return g_object_new (EMPATHY_TYPE_ROSTER_CONTACT, + "individual", individual, + "bottom-padding", 8, + "top-padding", 8, + "left-padding", 8, + "right-padding", 8, + NULL); +} + +FolksIndividual * +empathy_roster_contact_get_individual (EmpathyRosterContact *self) +{ + return self->priv->individual; +} + +gboolean +empathy_roster_contact_is_online (EmpathyRosterContact *self) +{ + return self->priv->online; +} -- cgit v1.2.3