/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with the program; if not, see * * * Authors: * Chris Toshok * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * */ #ifdef HAVE_CONFIG_H #include #endif #include "eab-contact-display.h" #include "eab-gui-util.h" #include "e-util/e-util.h" #include "e-util/e-html-utils.h" #include "e-util/e-icon-factory.h" #include "e-util/e-plugin-ui.h" #include #include #include #include #define EAB_CONTACT_DISPLAY_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), EAB_TYPE_CONTACT_DISPLAY, EABContactDisplayPrivate)) #define HANDLE_MAILTO_INTERNALLY 1 struct _EABContactDisplayPrivate { EContact *contact; EABContactDisplayMode mode; GtkUIManager *ui_manager; GtkActionGroup *email_actions; GtkActionGroup *uri_actions; GtkWidget *invisible; gchar *selected_uri; gchar *clipboard_uri; }; enum { PROP_0, PROP_CONTACT, PROP_MODE }; enum { SEND_MESSAGE, LAST_SIGNAL }; static struct { const gchar *name; const gchar *pretty_name; } common_location [] = { { "WORK", N_ ("Work") }, { "HOME", N_ ("Home") }, { "OTHER", N_ ("Other") } }; #define HTML_HEADER "\n\n" \ "\n\n\n" #define HEADER_COLOR "#7f7f7f" #define IMAGE_COL_WIDTH "20" #define CONTACT_LIST_ICON "stock_contact-list" #define AIM_ICON "im-aim" #define GROUPWISE_ICON "im-nov" #define ICQ_ICON "im-icq" #define JABBER_ICON "im-jabber" #define MSN_ICON "im-msn" #define YAHOO_ICON "im-yahoo" #define GADUGADU_ICON "im-gadugadu" #define SKYPE_ICON "stock_people" #define VIDEOCONF_ICON "stock_video-conferencing" #define MAX_COMPACT_IMAGE_DIMENSION 48 static const gchar *ui = "" " " " " " " " " " " " " ""; static gpointer parent_class; static guint signals[LAST_SIGNAL]; static void action_copy_address_cb (GtkAction *action, EABContactDisplay *display) { EContact *contact; GList *list; const gchar *uri; gchar *html; gint index; uri = display->priv->selected_uri; index = atoi (uri + strlen ("internal-mailto:")); contact = eab_contact_display_get_contact (display); list = e_contact_get (contact, E_CONTACT_EMAIL); html = e_text_to_html (g_list_nth_data (list, index), 0); g_list_foreach (list, (GFunc) g_free, NULL); g_list_free (list); display->priv->clipboard_uri = html; display->priv->selected_uri = NULL; gtk_selection_owner_set ( display->priv->invisible, GDK_SELECTION_PRIMARY, gtk_get_current_event_time ()); gtk_selection_owner_set ( display->priv->invisible, GDK_SELECTION_CLIPBOARD, gtk_get_current_event_time ()); } static void action_copy_link_cb (GtkAction *action, EABContactDisplay *display) { display->priv->clipboard_uri = display->priv->selected_uri; display->priv->selected_uri = NULL; gtk_selection_owner_set ( display->priv->invisible, GDK_SELECTION_PRIMARY, gtk_get_current_event_time ()); gtk_selection_owner_set ( display->priv->invisible, GDK_SELECTION_CLIPBOARD, gtk_get_current_event_time ()); } static void action_open_link_cb (GtkAction *action, EABContactDisplay *display) { /* XXX Pass a parent window. */ e_show_uri (NULL, display->priv->selected_uri); } static void action_send_message_cb (GtkAction *action, EABContactDisplay *display) { EDestination *destination; EContact *contact; const gchar *uri; gint row; uri = display->priv->selected_uri; row = atoi (uri + strlen ("internal-mailto:")); g_return_if_fail (row >= 0); destination = e_destination_new (); contact = eab_contact_display_get_contact (display); e_destination_set_contact (destination, contact, row); g_signal_emit (display, signals[SEND_MESSAGE], 0, destination); g_object_unref (destination); } static GtkActionEntry email_entries[] = { { "copy-address", NULL, N_("Copy _Email Address"), NULL, NULL, G_CALLBACK (action_copy_address_cb) }, { "send-message", NULL, N_("_Send New Message To..."), NULL, NULL, G_CALLBACK (action_send_message_cb) } }; static GtkActionEntry uri_entries[] = { { "copy-link", NULL, N_("_Copy Link Location"), NULL, NULL, G_CALLBACK (action_copy_link_cb) }, { "open-link", NULL, N_("_Open Link in Browser"), NULL, NULL, G_CALLBACK (action_open_link_cb) } }; static void contact_display_selection_get (EABContactDisplay *display, GtkSelectionData *data, guint info, guint time_stamp) { if (display->priv->clipboard_uri == NULL) return; gtk_selection_data_set ( data, data->target, 8, (guchar *) display->priv->clipboard_uri, strlen (display->priv->clipboard_uri)); } static void contact_display_selection_clear_event (EABContactDisplay *display, GdkEventSelection *event) { g_free (display->priv->clipboard_uri); display->priv->clipboard_uri = NULL; } static void contact_display_on_url_requested (GtkHTML *html, const gchar *url, GtkHTMLStream *handle, EABContactDisplay *display) { if (!strcmp (url, "internal-contact-photo:")) { EContactPhoto *photo; photo = e_contact_get (display->priv->contact, E_CONTACT_PHOTO); if (!photo) photo = e_contact_get (display->priv->contact, E_CONTACT_LOGO); gtk_html_stream_write (handle, (gchar *)photo->data.inlined.data, photo->data.inlined.length); gtk_html_end (html, handle, GTK_HTML_STREAM_OK); e_contact_photo_free (photo); } else if (!strncmp (url, "evo-icon:", strlen ("evo-icon:"))) { gchar *data; gsize data_length; gchar *filename; filename = e_icon_factory_get_icon_filename (url + strlen ("evo-icon:"), GTK_ICON_SIZE_MENU); if (g_file_get_contents (filename, &data, &data_length, NULL)) { gtk_html_stream_write (handle, data, data_length); g_free (data); } gtk_html_stream_close (handle, GTK_HTML_STREAM_OK); g_free (filename); } } static void contact_display_on_link_clicked (GtkHTML *html, const gchar *uri, EABContactDisplay *display) { #ifdef HANDLE_MAILTO_INTERNALLY if (!strncmp (uri, "internal-mailto:", strlen ("internal-mailto:"))) { EDestination *destination; EContact *contact; gint email_num; email_num = atoi (uri + strlen ("internal-mailto:")); if (email_num == -1) return; destination = e_destination_new (); contact = eab_contact_display_get_contact (display); e_destination_set_contact (destination, contact, email_num); g_signal_emit (display, signals[SEND_MESSAGE], 0, destination); g_object_unref (destination); return; } #endif /* FIXME Pass a parent window. */ e_show_uri (NULL, uri); } static void render_name_value (GtkHTMLStream *html_stream, const gchar *label, const gchar *str, const gchar *icon, guint html_flags) { gchar *value = e_text_to_html (str, html_flags); if (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL) { gtk_html_stream_printf (html_stream, "%s %s:", value, label); gtk_html_stream_printf (html_stream, ""); if (icon) gtk_html_stream_printf (html_stream, "", icon); else gtk_html_stream_printf (html_stream, ""); } else { gtk_html_stream_printf (html_stream, ""); if (icon) gtk_html_stream_printf (html_stream, "", icon); gtk_html_stream_printf (html_stream, "%s: %s", label, value); } g_free (value); } static void render_attribute (GtkHTMLStream *html_stream, EContact *contact, const gchar *html_label, EContactField field, const gchar *icon, guint html_flags) { const gchar *str; str = e_contact_get_const (contact, field); if (str && *str) { render_name_value (html_stream, html_label, str, icon, html_flags); } } static void accum_address (GString *gstr, EContact *contact, const gchar *html_label, EContactField adr_field, EContactField label_field) { EContactAddress *adr; const gchar *label; gboolean is_rtl = (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL); label = e_contact_get_const (contact, label_field); if (label) { gchar *html = e_text_to_html (label, E_TEXT_TO_HTML_CONVERT_NL); #ifdef mapping_works if (is_rtl) g_string_append_printf (gstr, "%s%s:
%s", html, html_label, _("(map)")); else g_string_append_printf (gstr, "%s:
%s%s", html_label, _("(map)"), html); #else if (is_rtl) g_string_append_printf (gstr, "%s%s:", html, html_label); else g_string_append_printf (gstr, "%s:%s", html_label, html); #endif g_free (html); return; } adr = e_contact_get (contact, adr_field); if (adr && (adr->po || adr->ext || adr->street || adr->locality || adr->region || adr->code || adr->country)) { if (is_rtl) g_string_append_printf (gstr, ""); else g_string_append_printf (gstr, "%s:
%s", html_label, _("map")); if (adr->po && *adr->po) g_string_append_printf (gstr, "%s
", adr->po); if (adr->ext && *adr->ext) g_string_append_printf (gstr, "%s
", adr->ext); if (adr->street && *adr->street) g_string_append_printf (gstr, "%s
", adr->street); if (adr->locality && *adr->locality) g_string_append_printf (gstr, "%s
", adr->locality); if (adr->region && *adr->region) g_string_append_printf (gstr, "%s
", adr->region); if (adr->code && *adr->code) g_string_append_printf (gstr, "%s
", adr->code); if (adr->country && *adr->country) g_string_append_printf (gstr, "%s
", adr->country); if (is_rtl) g_string_append_printf (gstr, "%s:
%s", html_label, _("map")); else g_string_append_printf (gstr, ""); } if (adr) e_contact_address_free (adr); } static void accum_name_value (GString *gstr, const gchar *label, const gchar *str, const gchar *icon, guint html_flags) { gchar *value = e_text_to_html (str, html_flags); if (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL) { g_string_append_printf (gstr, "%s %s:", value, label); g_string_append_printf (gstr, ""); if (icon) g_string_append_printf (gstr, "", icon); else g_string_append_printf (gstr, ""); } else { g_string_append_printf (gstr, ""); if (icon) g_string_append_printf (gstr, "", icon); g_string_append_printf (gstr, "%s: %s", label, value); } g_free (value); } static void accum_attribute (GString *gstr, EContact *contact, const gchar *html_label, EContactField field, const gchar *icon, guint html_flags) { const gchar *str; str = e_contact_get_const (contact, field); if (str && *str) { accum_name_value (gstr, html_label, str, icon, html_flags); } } static void accum_time_attribute (GString *gstr, EContact *contact, const gchar *html_label, EContactField field, const gchar *icon, guint html_flags) { EContactDate *date; GDate *gdate = NULL; gchar sdate[100]; date = e_contact_get (contact, field); if (date) { gdate = g_date_new_dmy ( date->day, date->month, date->year ); g_date_strftime (sdate, 100, "%x", gdate); g_date_free (gdate); accum_name_value (gstr, html_label, sdate, icon, html_flags); e_contact_date_free (date); } } static void accum_multival_attribute (GString *gstr, EContact *contact, const gchar *html_label, EContactField field, const gchar *icon, guint html_flags) { GList *val_list, *l; val_list = e_contact_get (contact, field); for (l = val_list; l; l = l->next) { const gchar *str = (const gchar *) l->data; accum_name_value (gstr, html_label, str, icon, html_flags); } g_list_foreach (val_list, (GFunc) g_free, NULL); g_list_free (val_list); } static void render_contact_list (GtkHTMLStream *html_stream, EContact *contact) { GList *email_list; GList *l; gtk_html_stream_printf (html_stream, ""); gtk_html_stream_printf (html_stream, "
"); gtk_html_stream_printf (html_stream, ""); gtk_html_stream_printf (html_stream, "%s: ", _("List Members")); email_list = e_contact_get (contact, E_CONTACT_EMAIL); for (l = email_list; l; l = l->next) { gchar *value; value = eab_parse_qp_email_to_html (l->data); if (!value) value = e_text_to_html (l->data, E_TEXT_TO_HTML_CONVERT_ADDRESSES); gtk_html_stream_printf (html_stream, "%s
", value); g_free (value); } gtk_html_stream_printf (html_stream, "
"); } static void start_block (GtkHTMLStream *html_stream, const gchar *label) { gtk_html_stream_printf (html_stream, "%s", label); } static void end_block (GtkHTMLStream *html_stream) { gtk_html_stream_printf (html_stream, " "); } static const gchar * get_email_location (EVCardAttribute *attr) { gint i; for (i = 0; i < G_N_ELEMENTS (common_location); i++) { if (e_vcard_attribute_has_type (attr, common_location [i].name)) return _(common_location [i].pretty_name); } return _("Other"); } static void render_contact (GtkHTMLStream *html_stream, EContact *contact) { GString *accum; GList *email_list, *l, *email_attr_list, *al; gboolean is_rtl = (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL); #ifdef HANDLE_MAILTO_INTERNALLY gint email_num = 0; #endif const gchar *nl; gchar *nick=NULL; gtk_html_stream_printf (html_stream, ""); accum = g_string_new (""); nl = ""; start_block (html_stream, ""); email_list = e_contact_get (contact, E_CONTACT_EMAIL); email_attr_list = e_contact_get_attributes (contact, E_CONTACT_EMAIL); for (l = email_list, al=email_attr_list; l && al; l = l->next, al = al->next) { gchar *html = NULL, *name = NULL, *mail = NULL; gchar *attr_str = (gchar *)get_email_location ((EVCardAttribute *) al->data); #ifdef HANDLE_MAILTO_INTERNALLY if (!eab_parse_qp_email (l->data, &name, &mail)) mail = e_text_to_html (l->data, 0); g_string_append_printf (accum, "%s%s%s%s%s (%s)", nl, name ? name : "", name ? " <" : "", email_num, mail, name ? ">" : "", attr_str ? attr_str : ""); email_num ++; #else html = eab_parse_qp_email_to_html (l->data); if (!html) html = e_text_to_html (l->data, E_TEXT_TO_HTML_CONVERT_ADDRESSES); g_string_append_printf (accum, "%s%s (%s)", nl, html, attr_str ? attr_str : ""); #endif nl = "
"; g_free (html); g_free (name); g_free (mail); } g_list_foreach (email_list, (GFunc)g_free, NULL); g_list_free (email_list); if (accum->len) { #ifdef HANDLE_MAILTO_INTERNALLY if (is_rtl) { gtk_html_stream_printf (html_stream, "", accum->str, _("Email")); } else { gtk_html_stream_printf (html_stream, "", _("Email"), accum->str); } #else render_name_value (html_stream, _("Email"), accum->str, NULL, E_TEXT_TO_HTML_CONVERT_ADDRESSES | E_TEXT_TO_HTML_CONVERT_NL); #endif } g_string_assign (accum, ""); nick = e_contact_get (contact, E_CONTACT_NICKNAME); if (nick && *nick) { accum_name_value (accum, _("Nickname"), nick, NULL, 0); if (accum->len > 0) gtk_html_stream_printf (html_stream, "%s", accum->str); } g_string_assign (accum, ""); accum_multival_attribute (accum, contact, _("AIM"), E_CONTACT_IM_AIM, AIM_ICON, 0); accum_multival_attribute (accum, contact, _("GroupWise"), E_CONTACT_IM_GROUPWISE, GROUPWISE_ICON, 0); accum_multival_attribute (accum, contact, _("ICQ"), E_CONTACT_IM_ICQ, ICQ_ICON, 0); accum_multival_attribute (accum, contact, _("Jabber"), E_CONTACT_IM_JABBER, JABBER_ICON, 0); accum_multival_attribute (accum, contact, _("MSN"), E_CONTACT_IM_MSN, MSN_ICON, 0); accum_multival_attribute (accum, contact, _("Yahoo"), E_CONTACT_IM_YAHOO, YAHOO_ICON, 0); accum_multival_attribute (accum, contact, _("Gadu-Gadu"), E_CONTACT_IM_GADUGADU, GADUGADU_ICON, 0); accum_multival_attribute (accum, contact, _("Skype"), E_CONTACT_IM_SKYPE, SKYPE_ICON, 0); if (accum->len > 0) gtk_html_stream_printf (html_stream, "%s", accum->str); end_block (html_stream); g_string_assign (accum, ""); accum_attribute (accum, contact, _("Company"), E_CONTACT_ORG, NULL, 0); accum_attribute (accum, contact, _("Department"), E_CONTACT_ORG_UNIT, NULL, 0); accum_attribute (accum, contact, _("Profession"), E_CONTACT_ROLE, NULL, 0); accum_attribute (accum, contact, _("Position"), E_CONTACT_TITLE, NULL, 0); accum_attribute (accum, contact, _("Manager"), E_CONTACT_MANAGER, NULL, 0); accum_attribute (accum, contact, _("Assistant"), E_CONTACT_ASSISTANT, NULL, 0); accum_attribute (accum, contact, _("Video Chat"), E_CONTACT_VIDEO_URL, VIDEOCONF_ICON, E_TEXT_TO_HTML_CONVERT_URLS); accum_attribute (accum, contact, _("Calendar"), E_CONTACT_CALENDAR_URI, NULL, E_TEXT_TO_HTML_CONVERT_URLS); accum_attribute (accum, contact, _("Free/Busy"), E_CONTACT_FREEBUSY_URL, NULL, E_TEXT_TO_HTML_CONVERT_URLS); accum_attribute (accum, contact, _("Phone"), E_CONTACT_PHONE_BUSINESS, NULL, 0); accum_attribute (accum, contact, _("Fax"), E_CONTACT_PHONE_BUSINESS_FAX, NULL, 0); accum_address (accum, contact, _("Address"), E_CONTACT_ADDRESS_WORK, E_CONTACT_ADDRESS_LABEL_WORK); if (accum->len > 0) { start_block (html_stream, _("Work")); gtk_html_stream_printf (html_stream, "%s", accum->str); end_block (html_stream); } g_string_assign (accum, ""); accum_attribute (accum, contact, _("Home Page"), E_CONTACT_HOMEPAGE_URL, NULL, E_TEXT_TO_HTML_CONVERT_URLS); accum_attribute (accum, contact, _("Web Log"), E_CONTACT_BLOG_URL, NULL, E_TEXT_TO_HTML_CONVERT_URLS); accum_attribute (accum, contact, _("Phone"), E_CONTACT_PHONE_HOME, NULL, 0); accum_attribute (accum, contact, _("Mobile Phone"), E_CONTACT_PHONE_MOBILE, NULL, 0); accum_address (accum, contact, _("Address"), E_CONTACT_ADDRESS_HOME, E_CONTACT_ADDRESS_LABEL_HOME); accum_time_attribute (accum, contact, _("Birthday"), E_CONTACT_BIRTH_DATE, NULL, 0); accum_time_attribute (accum, contact, _("Anniversary"), E_CONTACT_ANNIVERSARY, NULL, 0); accum_attribute (accum, contact, _("Spouse"), E_CONTACT_SPOUSE, NULL, 0); if (accum->len > 0) { start_block (html_stream, _("Personal")); gtk_html_stream_printf (html_stream, "%s", accum->str); end_block (html_stream); } start_block (html_stream, ""); render_attribute (html_stream, contact, _("Note"), E_CONTACT_NOTE, NULL, E_TEXT_TO_HTML_CONVERT_ADDRESSES | E_TEXT_TO_HTML_CONVERT_URLS | E_TEXT_TO_HTML_CONVERT_NL); end_block (html_stream); gtk_html_stream_printf (html_stream, "
%s %s:
"); gtk_html_stream_printf (html_stream, "%s: %s
"); } static void eab_contact_display_render_normal (EABContactDisplay *display, EContact *contact) { GtkHTMLStream *html_stream; gboolean is_rtl = (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL); html_stream = gtk_html_begin (GTK_HTML (display)); gtk_html_stream_write (html_stream, HTML_HEADER, sizeof (HTML_HEADER) - 1); gtk_html_stream_printf (html_stream, "
\n", is_rtl ? " align=\"right\" " : ""); if (contact) { const gchar *str; gchar *html; EContactPhoto *photo; gtk_html_stream_printf (html_stream, "
", is_rtl ? " align=\"right\" " : ""); photo = e_contact_get (contact, E_CONTACT_PHOTO); if (!photo) photo = e_contact_get (contact, E_CONTACT_LOGO); /* Only handle inlined photos for now */ if (photo && photo->type == E_CONTACT_PHOTO_TYPE_INLINED) { gtk_html_stream_printf (html_stream, ""); e_contact_photo_free (photo); } gtk_html_stream_printf (html_stream, "\n", is_rtl ? " align=\"right\" " : ""); str = e_contact_get_const (contact, E_CONTACT_FILE_AS); if (!str) str = e_contact_get_const (contact, E_CONTACT_FULL_NAME); if (str) { html = e_text_to_html (str, 0); #ifdef HANDLE_MAILTO_INTERNALLY if (e_contact_get (contact, E_CONTACT_IS_LIST)) gtk_html_stream_printf (html_stream, "

%s

", html); else #endif gtk_html_stream_printf (html_stream, "

%s

", html); g_free (html); } if (e_contact_get (contact, E_CONTACT_IS_LIST)) render_contact_list (html_stream, contact); else render_contact (html_stream, contact); gtk_html_stream_printf (html_stream, "
\n"); } gtk_html_stream_printf (html_stream, "
\n"); gtk_html_end (GTK_HTML (display), html_stream, GTK_HTML_STREAM_OK); } static void eab_contact_display_render_compact (EABContactDisplay *display, EContact *contact) { GtkHTMLStream *html_stream; html_stream = gtk_html_begin (GTK_HTML (display)); gtk_html_stream_write (html_stream, HTML_HEADER, sizeof (HTML_HEADER) - 1); gtk_html_stream_write (html_stream, "\n", 7); if (contact) { const gchar *str; gchar *html; EContactPhoto *photo; guint bg_frame = 0x000000, bg_body = 0xEEEEEE; GtkStyle *style; style = gtk_widget_get_style (GTK_WIDGET (display)); if (style) { gushort r, g, b; r = style->black.red >> 8; g = style->black.green >> 8; b = style->black.blue >> 8; bg_frame = ((r << 16) | (g << 8) | b) & 0xffffff; #define DARKER(a) (((a) >= 0x22) ? ((a) - 0x22) : 0) r = DARKER (style->bg[GTK_STATE_NORMAL].red >> 8); g = DARKER (style->bg[GTK_STATE_NORMAL].green >> 8); b = DARKER (style->bg[GTK_STATE_NORMAL].blue >> 8); bg_body = ((r << 16) | (g << 8) | b) & 0xffffff; #undef DARKER } gtk_html_stream_printf (html_stream, "" "
" "" "
" "" "
", bg_frame, bg_body); photo = e_contact_get (contact, E_CONTACT_PHOTO); if (!photo) photo = e_contact_get (contact, E_CONTACT_LOGO); if (photo) { gint calced_width = MAX_COMPACT_IMAGE_DIMENSION, calced_height = MAX_COMPACT_IMAGE_DIMENSION; GdkPixbufLoader *loader = gdk_pixbuf_loader_new (); GdkPixbuf *pixbuf; /* figure out if we need to downscale the image here. we don't scale the pixbuf itself, just insert width/height tags in the html */ gdk_pixbuf_loader_write (loader, photo->data.inlined.data, photo->data.inlined.length, NULL); gdk_pixbuf_loader_close (loader, NULL); pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); if (pixbuf) g_object_ref (pixbuf); g_object_unref (loader); if (pixbuf) { gint max_dimension; calced_width = gdk_pixbuf_get_width (pixbuf); calced_height = gdk_pixbuf_get_height (pixbuf); max_dimension = calced_width; if (max_dimension < calced_height) max_dimension = calced_height; if (max_dimension > MAX_COMPACT_IMAGE_DIMENSION) { calced_width *= ((gfloat)MAX_COMPACT_IMAGE_DIMENSION / max_dimension); calced_height *= ((gfloat)MAX_COMPACT_IMAGE_DIMENSION / max_dimension); } } g_object_unref (pixbuf); gtk_html_stream_printf (html_stream, "", calced_width, calced_height); e_contact_photo_free (photo); } gtk_html_stream_printf (html_stream, "\n"); str = e_contact_get_const (contact, E_CONTACT_FILE_AS); if (str) { html = e_text_to_html (str, 0); gtk_html_stream_printf (html_stream, "%s", html); g_free (html); } else { str = e_contact_get_const (contact, E_CONTACT_FULL_NAME); if (str) { html = e_text_to_html (str, 0); gtk_html_stream_printf (html_stream, "%s", html); g_free (html); } } gtk_html_stream_write (html_stream, "
", 4); if (e_contact_get (contact, E_CONTACT_IS_LIST)) { GList *email_list; GList *l; gtk_html_stream_printf (html_stream, "
"); gtk_html_stream_printf (html_stream, "%s: ", _("List Members")); email_list = e_contact_get (contact, E_CONTACT_EMAIL); for (l = email_list; l; l = l->next) { if (l->data) { html = e_text_to_html (l->data, 0); gtk_html_stream_printf (html_stream, "%s, ", html); g_free (html); } } gtk_html_stream_printf (html_stream, "
"); } else { gboolean comma = FALSE; str = e_contact_get_const (contact, E_CONTACT_TITLE); if (str) { html = e_text_to_html (str, 0); gtk_html_stream_printf (html_stream, "%s: %s
", _("Job Title"), str); g_free (html); } #define print_email() { \ html = eab_parse_qp_email_to_html (str); \ \ if (!html) \ html = e_text_to_html (str, 0); \ \ gtk_html_stream_printf (html_stream, "%s%s", comma ? ", " : "", html); \ g_free (html); \ comma = TRUE; \ } gtk_html_stream_printf (html_stream, "%s: ", _("Email")); str = e_contact_get_const (contact, E_CONTACT_EMAIL_1); if (str) print_email (); str = e_contact_get_const (contact, E_CONTACT_EMAIL_2); if (str) print_email (); str = e_contact_get_const (contact, E_CONTACT_EMAIL_3); if (str) print_email (); gtk_html_stream_write (html_stream, "
", 4); #undef print_email str = e_contact_get_const (contact, E_CONTACT_HOMEPAGE_URL); if (str) { html = e_text_to_html (str, E_TEXT_TO_HTML_CONVERT_URLS); gtk_html_stream_printf (html_stream, "%s: %s
", _("Home page"), html); g_free (html); } str = e_contact_get_const (contact, E_CONTACT_BLOG_URL); if (str) { html = e_text_to_html (str, E_TEXT_TO_HTML_CONVERT_URLS); gtk_html_stream_printf (html_stream, "%s: %s
", _("Blog"), html); } } gtk_html_stream_printf (html_stream, "
\n"); } gtk_html_stream_write (html_stream, "\n", 15); gtk_html_end (GTK_HTML (display), html_stream, GTK_HTML_STREAM_OK); } static gint contact_display_button_press_event (GtkWidget *widget, GdkEvent *event, EABContactDisplay *display) { GtkUIManager *ui_manager; GtkActionGroup *action_group; GtkWidget *menu; gboolean has_email; gchar *uri; if (event->button.button != 3) return FALSE; uri = gtk_html_get_url_at ( GTK_HTML (widget), event->button.x, event->button.y); if (uri == NULL) return FALSE; g_free (display->priv->selected_uri); display->priv->selected_uri = uri; ui_manager = display->priv->ui_manager; menu = gtk_ui_manager_get_widget (ui_manager, "/popup"); g_return_val_if_fail (GTK_IS_MENU (menu), FALSE); has_email = (g_ascii_strncasecmp (uri, "internal-mailto:", 16) == 0); /* Show the appropriate actions. */ action_group = display->priv->email_actions; gtk_action_group_set_visible (action_group, has_email); action_group = display->priv->uri_actions; gtk_action_group_set_visible (action_group, !has_email); if (event != NULL) gtk_menu_popup ( GTK_MENU (menu), NULL, NULL, NULL, NULL, event->button.button, event->button.time); else gtk_menu_popup ( GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time ()); return TRUE; } static void contact_display_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { switch (property_id) { case PROP_CONTACT: eab_contact_display_set_contact ( EAB_CONTACT_DISPLAY (object), g_value_get_object (value)); return; case PROP_MODE: eab_contact_display_set_mode ( EAB_CONTACT_DISPLAY (object), g_value_get_int (value)); return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } static void contact_display_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { switch (property_id) { case PROP_CONTACT: g_value_set_object ( value, eab_contact_display_get_contact ( EAB_CONTACT_DISPLAY (object))); return; case PROP_MODE: g_value_set_int ( value, eab_contact_display_get_mode ( EAB_CONTACT_DISPLAY (object))); return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } static void contact_display_dispose (GObject *object) { EABContactDisplayPrivate *priv; priv = EAB_CONTACT_DISPLAY_GET_PRIVATE (object); if (priv->contact != NULL) { g_object_unref (priv->contact); priv->contact = NULL; } if (priv->ui_manager != NULL) { g_object_unref (priv->ui_manager); priv->ui_manager = NULL; } if (priv->email_actions != NULL) { g_object_unref (priv->email_actions); priv->email_actions = NULL; } if (priv->uri_actions != NULL) { g_object_unref (priv->uri_actions); priv->uri_actions = NULL; } if (priv->invisible != NULL) { g_object_unref (priv->invisible); priv->invisible = NULL; } /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (parent_class)->dispose (object); } static void contact_display_finalize (GObject *object) { EABContactDisplayPrivate *priv; priv = EAB_CONTACT_DISPLAY_GET_PRIVATE (object); g_free (priv->selected_uri); g_free (priv->clipboard_uri); /* Chain up to parent's finalize() method. */ G_OBJECT_CLASS (parent_class)->finalize (object); } static void eab_contact_display_class_init (EABContactDisplayClass *class) { GObjectClass *object_class; parent_class = g_type_class_peek_parent (class); g_type_class_add_private (class, sizeof (EABContactDisplayPrivate)); object_class = G_OBJECT_CLASS (class); object_class->set_property = contact_display_set_property; object_class->get_property = contact_display_get_property; object_class->dispose = contact_display_dispose; object_class->finalize = contact_display_finalize; g_object_class_install_property ( object_class, PROP_CONTACT, g_param_spec_object ( "contact", NULL, NULL, E_TYPE_CONTACT, G_PARAM_READWRITE)); /* XXX Make this a real enum property. */ g_object_class_install_property ( object_class, PROP_MODE, g_param_spec_int ( "mode", NULL, NULL, EAB_CONTACT_DISPLAY_RENDER_NORMAL, EAB_CONTACT_DISPLAY_RENDER_COMPACT, EAB_CONTACT_DISPLAY_RENDER_NORMAL, G_PARAM_READWRITE)); signals[SEND_MESSAGE] = g_signal_new ( "send-message", G_OBJECT_CLASS_TYPE (class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (EABContactDisplayClass, send_message), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, E_TYPE_DESTINATION); } static void eab_contact_display_init (EABContactDisplay *display) { GtkActionGroup *action_group; GtkHTML *html; const gchar *id; display->priv = EAB_CONTACT_DISPLAY_GET_PRIVATE (display); display->priv->mode = EAB_CONTACT_DISPLAY_RENDER_NORMAL; display->priv->ui_manager = gtk_ui_manager_new (); display->priv->invisible = gtk_invisible_new (); g_object_ref_sink (display->priv->invisible); action_group = gtk_action_group_new ("email"); gtk_action_group_set_translation_domain ( action_group, GETTEXT_PACKAGE); gtk_action_group_add_actions ( action_group, email_entries, G_N_ELEMENTS (email_entries), display); gtk_ui_manager_insert_action_group ( display->priv->ui_manager, action_group, 0); display->priv->email_actions = action_group; action_group = gtk_action_group_new ("uri"); gtk_action_group_set_translation_domain ( action_group, GETTEXT_PACKAGE); gtk_action_group_add_actions ( action_group, uri_entries, G_N_ELEMENTS (uri_entries), display); gtk_ui_manager_insert_action_group ( display->priv->ui_manager, action_group, 0); display->priv->uri_actions = action_group; gtk_ui_manager_add_ui_from_string ( display->priv->ui_manager, ui, -1, NULL); html = GTK_HTML (display); gtk_html_construct (html); gtk_html_set_editable (html, FALSE); gtk_html_set_default_content_type (html, "text/html; charset=utf-8"); g_signal_connect ( display, "url-requested", G_CALLBACK (contact_display_on_url_requested), display); g_signal_connect ( display, "link-clicked", G_CALLBACK (contact_display_on_link_clicked), display); g_signal_connect ( display, "button-press-event", G_CALLBACK (contact_display_button_press_event), display); g_signal_connect_swapped ( display->priv->invisible, "selection-get", G_CALLBACK (contact_display_selection_get), display); g_signal_connect_swapped ( display->priv->invisible, "selection-clear-event", G_CALLBACK (contact_display_selection_clear_event), display); gtk_selection_add_target ( display->priv->invisible, GDK_SELECTION_PRIMARY, GDK_SELECTION_TYPE_STRING, 0); gtk_selection_add_target ( display->priv->invisible, GDK_SELECTION_CLIPBOARD, GDK_SELECTION_TYPE_STRING, 1); id = "org.gnome.evolution.contact-display"; e_plugin_ui_register_manager (display->priv->ui_manager, id, display); e_plugin_ui_enable_manager (display->priv->ui_manager, id); } GType eab_contact_display_get_type (void) { static GType type = 0; if (G_UNLIKELY (type == 0)) { static const GTypeInfo type_info = { sizeof (EABContactDisplayClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) eab_contact_display_class_init, (GClassFinalizeFunc) NULL, NULL, /* class_data */ sizeof (EABContactDisplay), 0, /* n_preallocs */ (GInstanceInitFunc) eab_contact_display_init, NULL /* value_table */ }; type = g_type_register_static ( GTK_TYPE_HTML, "EABContactDisplay", &type_info, 0); } return type; } GtkWidget * eab_contact_display_new (void) { return g_object_new (EAB_TYPE_CONTACT_DISPLAY, NULL); } EContact * eab_contact_display_get_contact (EABContactDisplay *display) { g_return_val_if_fail (EAB_IS_CONTACT_DISPLAY (display), NULL); return display->priv->contact; } void eab_contact_display_set_contact (EABContactDisplay *display, EContact *contact) { EABContactDisplayMode mode; g_return_if_fail (EAB_IS_CONTACT_DISPLAY (display)); mode = eab_contact_display_get_mode (display); if (contact != NULL) g_object_ref (contact); if (display->priv->contact != NULL) g_object_unref (display->priv->contact); display->priv->contact = contact; switch (mode) { case EAB_CONTACT_DISPLAY_RENDER_NORMAL: eab_contact_display_render_normal (display, contact); break; case EAB_CONTACT_DISPLAY_RENDER_COMPACT: eab_contact_display_render_compact (display, contact); break; } g_object_notify (G_OBJECT (display), "contact"); } EABContactDisplayMode eab_contact_display_get_mode (EABContactDisplay *display) { g_return_val_if_fail (EAB_IS_CONTACT_DISPLAY (display), 0); return display->priv->mode; } void eab_contact_display_set_mode (EABContactDisplay *display, EABContactDisplayMode mode) { EContact *contact; g_return_if_fail (EAB_IS_CONTACT_DISPLAY (display)); display->priv->mode = mode; contact = eab_contact_display_get_contact (display); switch (mode) { case EAB_CONTACT_DISPLAY_RENDER_NORMAL: eab_contact_display_render_normal (display, contact); break; case EAB_CONTACT_DISPLAY_RENDER_COMPACT: eab_contact_display_render_compact (display, contact); break; } g_object_notify (G_OBJECT (display), "mode"); }