[evolution/webkit: 168/177] Move the contact preview HTML formatter to it's own class



commit a142a1e63cd5781c211bd590f95342749ada1f66
Author: Dan VrÃtil <dvratil redhat com>
Date:   Thu Feb 23 20:55:50 2012 +0100

    Move the contact preview HTML formatter to it's own class
    
    The EABContactFormatter provides simple public API for both synchronous
    and asynchronous formatting of an EContact to HTML.
    
    The EABContactDisplay hasn't changed from user's point of view, but
    internally it only call the formatter and then just displayes the
    output.
    
    This split allows the vcard-inline plugin to render the contact compact
    preview in <iframe> instead of embedding the EABContactDisplay into the
    message preview pane.

 addressbook/gui/widgets/Makefile.am             |    2 +
 addressbook/gui/widgets/eab-contact-display.c   |  941 +----------------
 addressbook/gui/widgets/eab-contact-formatter.c | 1275 +++++++++++++++++++++++
 addressbook/gui/widgets/eab-contact-formatter.h |   89 ++
 4 files changed, 1415 insertions(+), 892 deletions(-)
---
diff --git a/addressbook/gui/widgets/Makefile.am b/addressbook/gui/widgets/Makefile.am
index 60f6992..19c9c4f 100644
--- a/addressbook/gui/widgets/Makefile.am
+++ b/addressbook/gui/widgets/Makefile.am
@@ -33,6 +33,8 @@ libeabwidgets_la_SOURCES =			\
 	eab-config.c				\
 	eab-contact-display.c			\
 	eab-contact-display.h			\
+	eab-contact-formatter.c			\
+	eab-contact-formatter.h			\
 	eab-gui-util.c				\
 	eab-gui-util.h				\
 	e-minicard.c				\
diff --git a/addressbook/gui/widgets/eab-contact-display.c b/addressbook/gui/widgets/eab-contact-display.c
index 362b136..d28f657 100644
--- a/addressbook/gui/widgets/eab-contact-display.c
+++ b/addressbook/gui/widgets/eab-contact-display.c
@@ -25,6 +25,7 @@
 #endif
 
 #include "eab-contact-display.h"
+#include "eab-contact-formatter.h"
 
 #include "eab-gui-util.h"
 #include "e-util/e-util.h"
@@ -49,8 +50,7 @@
 
 struct _EABContactDisplayPrivate {
 	EContact *contact;
-	EABContactDisplayMode mode;
-	gboolean show_maps;
+        EABContactFormatter *formatter;
 };
 
 enum {
@@ -65,56 +65,6 @@ enum {
 	LAST_SIGNAL
 };
 
-static struct {
-	const gchar *name;
-	const gchar *pretty_name;
-}
-common_location[] =
-{
-	{ "WORK",  N_ ("Work")  },
-	{ "HOME",  N_ ("Home")  },
-	{ "OTHER", N_ ("Other") }
-};
-
-#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
-
-
-#define HTML_HEADER "<!doctype html public \"-//W3C//DTD HTML 4.0 TRANSITIONAL//EN\">\n<html>\n"  \
-                    "<head>\n<meta name=\"generator\" content=\"Evolution Addressbook Component\">\n" \
-                    "<link type=\"text/css\" rel=\"stylesheet\" href=\"file://" EVOLUTION_PRIVDATADIR "/theme/webview.css\">" \
-                    "<style type=\"text/css\">\n" \
-		    "  div#header { width:100%; clear: both; }\n" \
-		    "  div#columns { width: 100%; clear: both; }\n" \
-		    "  div#footer { width: 100%; clear: both; }\n" \
-		    "  div.column { width: auto; float: left; margin-right: 15px; }\n" \
-		    "  img#contact-photo { float: left; }\n" \
-		    "  div#contact-name { float: left; margin-left: 20px; }\n" \
-		    "</style>\n" \
-		    "<script type=\"text/javascript\">\n" \
-		    "function collapse_list (obj, listId) {\n" \
-		    "	var l = document.getElementById (listId);\n" \
-		    "	if (l.style.display == \"none\") {\n" \
-		    "		l.style.display = \"block\"; obj.src = obj.src.substr (0, obj.src.lastIndexOf (\"/\")) + \"/minus.png\";\n" \
-		    "	} else {\n" \
-		    "		l.style.display = \"none\"; obj.src = obj.src.substr (0, obj.src.lastIndexOf (\"/\")) + \"/plus.png\";\n" \
-		    "   }\n" \
-		    "}\n" \
-		    "</script>\n" \
-                    "</head>\n"
-
-
 static const gchar *ui =
 "<ui>"
 "  <popup name='context'>"
@@ -135,33 +85,6 @@ G_DEFINE_TYPE (
 	eab_contact_display,
 	E_TYPE_WEB_VIEW)
 
-static gchar*
-get_icon_uri (const gchar *icon_name)
-{
-	GtkIconTheme *icon_theme;
-	GtkIconInfo *icon_info;
-	const gchar *filename;
-	gchar *icon_uri;
-	GError *error = NULL;
-
-	icon_theme = gtk_icon_theme_get_default ();
-	icon_info = gtk_icon_theme_lookup_icon (
-		icon_theme, icon_name, GTK_ICON_SIZE_MENU, 0);
-	g_return_val_if_fail (icon_info != NULL, NULL);
-
-	filename = gtk_icon_info_get_filename (icon_info);
-	icon_uri = g_filename_to_uri (filename, NULL, &error);
-
-	if (error != NULL) {
-		g_warning ("%s", error->message);
-		g_error_free (error);
-	}
-
-	gtk_icon_info_free (icon_info);
-
-	return icon_uri;
-}
-
 static void
 contact_display_emit_send_message (EABContactDisplay *display,
                                    gint email_num)
@@ -243,785 +166,37 @@ static GtkActionEntry internal_mailto_entries[] = {
 };
 
 static void
-render_address_link (GString *buffer,
-                     EContact *contact,
-                     gint map_type)
+contact_formatting_finished (GObject *object,
+                             GSimpleAsyncResult *result,
+                             gpointer user_data)
 {
-	EContactAddress *adr;
-	GString *link = g_string_new ("");
-
-	adr = e_contact_get (contact, map_type);
-	if (adr &&
-	    (adr->street || adr->locality || adr->region || adr->country)) {
-		gchar *escaped;
+        EABContactDisplay *display = user_data;
+        CamelStreamMem *stream;
+        gchar *html;
+        GByteArray *ba;
 
-		if (adr->street && *adr->street) g_string_append_printf (link, "%s, ", adr->street);
-		if (adr->locality && *adr->locality) g_string_append_printf (link, "%s, ", adr->locality);
-		if (adr->region && *adr->region) g_string_append_printf (link, "%s, ", adr->region);
-		if (adr->country && *adr->country) g_string_append_printf (link, "%s", adr->country);
+        stream = g_simple_async_result_get_op_res_gpointer (result);
+        ba = camel_stream_mem_get_byte_array (stream);
 
-		escaped = g_uri_escape_string (link->str, NULL, TRUE);
-		g_string_assign (link, escaped);
-		g_free (escaped);
+        html = g_strndup ((gchar *) ba->data, ba->len);
+        e_web_view_load_string (E_WEB_VIEW (display), html);
 
-		g_string_prepend (link, "<a href=\"http://maps.google.com?q=";);
-		g_string_append_printf (link, "\">%s</a>", _("Open map"));
-	}
-
-	if (adr)
-		e_contact_address_free (adr);
-
-	g_string_append (buffer, link->str);
-	g_string_free (link, TRUE);
+        g_free (html);
+        g_object_unref (stream);
 }
 
 static void
-accum_address (GString *buffer,
-               EContact *contact,
-               const gchar *html_label,
-               EContactField adr_field,
-               EContactField label_field)
+load_contact (EABContactDisplay *display)
 {
-	EContactAddress *adr;
-	const gchar *label;
-	GString *map_link = g_string_new ("<br>");
-
-	render_address_link (map_link, contact, adr_field);
-
-	label = e_contact_get_const (contact, label_field);
-	if (label) {
-		gchar *html = e_text_to_html (label, E_TEXT_TO_HTML_CONVERT_NL);
-
-		if (TEXT_IS_RIGHT_TO_LEFT)
-			g_string_append_printf (buffer, "<tr><td align=\"right\" valign=\"top\" nowrap>%s</td><th>%s:<br>%s</th><td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\"></td></tr>", html, html_label, map_link->str);
-		else
-			g_string_append_printf (buffer, "<tr><td width=\"" IMAGE_COL_WIDTH "\"></td><th>%s:<br>%s</th><td valign=\"top\" nowrap>%s</td></tr>", html_label, map_link->str, html);
-
-		g_free (html);
-		g_string_free (map_link, TRUE);
+	if (!display->priv->contact)
 		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 (TEXT_IS_RIGHT_TO_LEFT)
-			g_string_append_printf (buffer, "<tr><td align=\"right\" valign=\"top\" nowrap>");
-		else
-			g_string_append_printf (buffer, "<tr><td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\"></td><th>%s:<br>%s</th><td valign=\"top\" nowrap>", html_label, map_link->str);
-
-		if (adr->po && *adr->po) g_string_append_printf (buffer, "%s<br>", adr->po);
-		if (adr->ext && *adr->ext) g_string_append_printf (buffer, "%s<br>", adr->ext);
-		if (adr->street && *adr->street) g_string_append_printf (buffer, "%s<br>", adr->street);
-		if (adr->locality && *adr->locality) g_string_append_printf (buffer, "%s<br>", adr->locality);
-		if (adr->region && *adr->region) g_string_append_printf (buffer, "%s<br>", adr->region);
-		if (adr->code && *adr->code) g_string_append_printf (buffer, "%s<br>", adr->code);
-		if (adr->country && *adr->country) g_string_append_printf (buffer, "%s<br>", adr->country);
-
-		if (TEXT_IS_RIGHT_TO_LEFT)
-			g_string_append_printf (buffer, "</td><th%s:<br>%s</th><td width=\"" IMAGE_COL_WIDTH "\"></td></tr>", html_label, map_link->str);
-		else
-			g_string_append_printf (buffer, "</td></tr>");
-	}
-	if (adr)
-		e_contact_address_free (adr);
-
-	g_string_free (map_link, TRUE);
-}
-
-static void
-render_table_row (GString *buffer,
-                  const gchar *label,
-                  const gchar *str,
-                  const gchar *icon,
-                  guint html_flags)
-{
-	const gchar *icon_html;
-	gchar *value;
-
-	if (html_flags)
-		value = e_text_to_html (str, html_flags);
-	else
-		value = (gchar*)str;
-
-
-	if (icon) {
-		gchar *icon_uri = get_icon_uri (icon);
-		icon_html = g_strdup_printf ("<img src=\"%s\" width=\"16\" height=\"16\" />", icon_uri);
-		g_free (icon_uri);
-	} else {
-		icon_html = "";
-	}
-
-	if (TEXT_IS_RIGHT_TO_LEFT) {
-		g_string_append_printf (
-			buffer, "<tr>"
-			"<td valign=\"top\" align=\"right\">%s</td>"
-			"<th align=\"right\" valign=\"top\" width=\"100\" nowrap>:%s</th>"
-			"<td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\">%s</td>"
-			"</tr>",
-			value, label, icon_html);
-	} else {
-		g_string_append_printf (
-			buffer, "<tr>"
-			"<td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\">%s</td>"
-			"<th valign=\"top\" width=\"100\" nowrap>%s:</th>"
-			"<td valign=\"top\">%s</td>"
-			"</tr>",
-			icon_html, label, value);
-	}
-
-	if (html_flags)
-		g_free (value);
-}
-
-static void
-accum_attribute (GString *buffer,
-                 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 != NULL && *str != '\0')
-		render_table_row (buffer, html_label, str, icon, html_flags);
-}
-
-static void
-accum_time_attribute (GString *buffer,
-                      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);
-		render_table_row (buffer, html_label, sdate, icon, html_flags);
-		e_contact_date_free (date);
-	}
-}
-
-static void
-accum_attribute_multival (GString *buffer,
-                          EContact *contact,
-                          const gchar *html_label,
-                          EContactField field,
-                          const gchar *icon,
-                          guint html_flags)
-{
-	GList *val_list, *l;
-	GString *val = g_string_new ("");
-
-	val_list = e_contact_get (contact, field);
-
-	for (l = val_list; l; l = l->next) {
-		if (l != val_list)
-			g_string_append (val, "<br>");
-
-		g_string_append (val, l->data);
-	}
-
-	if (val->str && *val->str)
-		render_table_row (buffer, html_label, val->str, icon, html_flags);
-
-	g_string_free (val, TRUE);
-	g_list_foreach (val_list, (GFunc) g_free, NULL);
-	g_list_free (val_list);
-}
-
-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_title_block (GString *buffer,
-                    EContact *contact)
-{
-	const gchar *str;
-	gchar *html;
-	EContactPhoto *photo;
-
-	g_string_append_printf (
-			buffer, "<table border=\"0\"><tr>"
-			"<td %s valign=\"middle\">", TEXT_IS_RIGHT_TO_LEFT ?
-			"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) {
-		gchar *photo_data = g_base64_encode (photo->data.inlined.data, photo->data.inlined.length);
-		g_string_append_printf (buffer, "<img border=\"1\" src=\"data:%s;base64,%s\">",
-			photo->data.inlined.mime_type,
-			photo_data);
-	} else if (photo && photo->type == E_CONTACT_PHOTO_TYPE_URI && photo->data.uri && *photo->data.uri) {
-		g_string_append_printf (buffer, "<img border=\"1\" src=\"%s\">", photo->data.uri);
-	}
-
-	if (photo)
-		e_contact_photo_free (photo);
-
-	if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
-		gchar *icon = get_icon_uri (CONTACT_LIST_ICON);
-		g_string_append_printf (buffer, "<img src=\"%s\">", icon);
-		g_free (icon);
-	}
-
-	g_string_append_printf (
-		buffer, "</td><td width=\"20\"></td><td %s valign=\"top\">\n",
-		TEXT_IS_RIGHT_TO_LEFT ? "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);
-		if (e_contact_get (contact, E_CONTACT_IS_LIST))
-			g_string_append_printf (buffer, "<h2><a href=\"internal-mailto:0\";>%s</a></h2>", html);
-		else
-			g_string_append_printf (buffer, "<h2>%s</h2>", html);
-		g_free (html);
-	}
-
-	g_string_append (buffer, "</td></tr></table>");
-
-}
-
-static void
-render_contact_list_row (GString *buffer,
-                         EDestination *destination,
-                         EABContactDisplay *display)
-{
-	gchar *evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL);
-	gboolean list_collapsed = FALSE;
-	const gchar *textrep;
-	gchar *name = NULL, *email_addr = NULL;
-
-	textrep = e_destination_get_textrep (destination, TRUE);
-	if (!eab_parse_qp_email (textrep, &name, &email_addr))
-		email_addr = g_strdup (textrep);
-
-	g_string_append (buffer, "<tr>");
-	if (e_destination_is_evolution_list (destination)) {
-		g_string_append_printf (buffer,
-			"<td width=" IMAGE_COL_WIDTH " valign=\"top\"><img src=\"%s/minus.png\" onClick=\"collapse_list(this, %s);\" class=\"navigable\"></td><td width=\"100%%\">%s",
-			evolution_imagesdir,
-			e_destination_get_contact_uid (destination),
-			name ? name : email_addr);
-
-		if (!list_collapsed) {
-			const GList *dest, *dests;
-			g_string_append_printf (buffer, "<br><table cellspacing=\"1\" id=\"%s\">",
-				e_destination_get_contact_uid (destination));
-
-			dests = e_destination_list_get_root_dests (destination);
-			for (dest = dests; dest; dest = dest->next) {
-				render_contact_list_row (buffer, dest->data, display);
-			}
-
-			g_string_append (buffer, "</table>");
-		}
-
-		g_string_append (buffer, "</td>");
-
-	} else {
-		if (name && *name) {
-			g_string_append_printf (buffer, "<td colspan=\"2\">%s &lt<a href=\"mailto:%s\";>%s</a>&gt;</td>", name, email_addr, email_addr);
-		} else {
-			g_string_append_printf (buffer, "<td colspan=\"2\"><a href=\"mailto:%s\";>%s</a></td>", email_addr, email_addr);
-		}
-	}
-
-	g_string_append (buffer, "</tr>");
-
-	g_free (evolution_imagesdir);
-	g_free (name);
-	g_free (email_addr);
-}
-
-static void
-render_contact_list (GString *buffer,
-		             EContact *contact,
-                     EABContactDisplay *display)
-{
-	EDestination *destination;
-	const GList *dest, *dests;
-
-	destination = e_destination_new ();
-	e_destination_set_contact (destination, contact, 0);
-	dests = e_destination_list_get_root_dests (destination);
-
-	render_title_block (buffer, contact);
-
-	g_string_append_printf (buffer, "<table border=\"0\"><tr><th colspan=\"2\">%s</th></tr>"
-		"<tr><td with=" IMAGE_COL_WIDTH "></td><td>", _("List Members:"));
-	g_string_append (buffer, "<table border=\"0\" cellspacing=\"1\">");
-
-	for (dest = dests; dest; dest = dest->next)
-		render_contact_list_row (buffer, dest->data, display);
-
-	g_string_append (buffer, "</table>");
-	g_string_append (buffer, "</td></tr></table>");
-
-	g_object_unref (destination);
-}
-
-static void
-render_contact_column (GString *buffer,
-                       EContact *contact)
-{
-	GString *accum, *email;
-	GList *email_list, *l, *email_attr_list, *al;
-	gint email_num = 0;
-	const gchar *nl;
-
-	email = g_string_new ("");
-	nl = "";
-
-	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 *name = NULL, *mail = NULL;
-		gchar *attr_str = (gchar *) get_email_location ((EVCardAttribute *) al->data);
-
-		if (!eab_parse_qp_email (l->data, &name, &mail))
-			mail = e_text_to_html (l->data, 0);
-
-		g_string_append_printf (email, "%s%s%s<a href=\"internal-mailto:%d\";>%s</a>%s <span class=\"header\">(%s)</span>",
-						nl,
-						name ? name : "",
-						name ? " &lt;" : "",
-						email_num,
-						mail,
-						name ? "&gt;" : "",
-						attr_str ? attr_str : "");
-		email_num++;
-		nl = "<br>";
-
-		g_free (name);
-		g_free (mail);
-	}
-	g_list_foreach (email_list, (GFunc) g_free, NULL);
-	g_list_foreach (email_attr_list, (GFunc) e_vcard_attribute_free, NULL);
-	g_list_free (email_list);
-	g_list_free (email_attr_list);
-
-	accum = g_string_new ("");
-
-	if (email->len)
-		render_table_row (accum, _("Email"), email->str, NULL, 0);
-
-	accum_attribute (accum, contact, _("Nickname"), E_CONTACT_NICKNAME, NULL, 0);
-	accum_attribute_multival (accum, contact, _("AIM"), E_CONTACT_IM_AIM, AIM_ICON, 0);
-	accum_attribute_multival (accum, contact, _("GroupWise"), E_CONTACT_IM_GROUPWISE, GROUPWISE_ICON, 0);
-	accum_attribute_multival (accum, contact, _("ICQ"), E_CONTACT_IM_ICQ, ICQ_ICON, 0);
-	accum_attribute_multival (accum, contact, _("Jabber"), E_CONTACT_IM_JABBER, JABBER_ICON, 0);
-	accum_attribute_multival (accum, contact, _("MSN"), E_CONTACT_IM_MSN, MSN_ICON, 0);
-	accum_attribute_multival (accum, contact, _("Yahoo"), E_CONTACT_IM_YAHOO, YAHOO_ICON, 0);
-	accum_attribute_multival (accum, contact, _("Gadu-Gadu"), E_CONTACT_IM_GADUGADU, GADUGADU_ICON, 0);
-	accum_attribute_multival (accum, contact, _("Skype"), E_CONTACT_IM_SKYPE, SKYPE_ICON, 0);
-
-	if (accum->len)
-		g_string_append_printf (buffer,
-			"<div class=\"column\" id=\"contact-internet\">"
-			"<table border=\"0\" cellspacing=\"5\">%s</table>"
-			"</div>", accum->str);
-
-	g_string_free (accum, TRUE);
-	g_string_free (email, TRUE);
-}
-
-
-static void
-accum_address_map (GString *buffer,
-                   EContact *contact,
-                   gint map_type)
-{
-#ifdef WITH_CONTACT_MAPS
-
-        g_string_append (buffer, "<tr><td colspan=\"3\">");
-
-        if (map_type == E_CONTACT_ADDRESS_WORK) {
-                g_string_append (buffer,
-                        "<object type=\"application/x-work-map-widget\" "
-                                "width=\"250\" height=\"250\"></object>");
-        } else {
-                g_string_append (buffer,
-                        "<object type=\"application/x-home-map-widget\" "
-                                "width=\"250\" height=\"250\"></object>");
-        }
-
-        g_string_append (buffer, "</td></tr>");
-
-#endif
-}
-
-static void
-render_work_column (GString *buffer,
-                    EContact *contact,
-                    EABContactDisplay *display)
-{
-	GString *accum = g_string_new ("");
-
-	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 (display->priv->show_maps)
-                accum_address_map (accum, contact, E_CONTACT_ADDRESS_WORK);
-
-	if (accum->len > 0) {
-		g_string_append_printf (buffer,
-			"<div class=\"column\" id=\"contact-work\">"
-			"<h3>%s</h3>"
-			"<table border=\"0\" cellspacing=\"5\">%s</table>"
-			"</div>", _("Work"), accum->str);
-	}
-
-	g_string_free (accum, TRUE);
-}
-
-static void
-render_personal_column (GString *buffer,
-                        EContact *contact,
-                        EABContactDisplay *display)
-{
-	GString *accum = g_string_new ("");
-
-	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 (display->priv->show_maps)
-                accum_address_map (accum, contact, E_CONTACT_ADDRESS_HOME);
-        
-	if (accum->len > 0) {
-		g_string_append_printf (buffer,
-			"<div class=\"column\" id=\"contact-personal\">"
-			"<h3>%s</h3>"
-			"<table border=\"0\" cellspacing=\"5\">%s</table>"
-			"</div>", _("Personal"), accum->str);
-	}
-
-	g_string_free (accum, TRUE);
-}
-
-static void
-render_footer (GString *buffer,
-               EContact *contact)
-{
-	const gchar *str;
-
-	str = e_contact_get_const (contact, E_CONTACT_NOTE);
-	if (!str || !*str)
-		return;
-
-	g_string_append (buffer, "<div id=\"footer\">"
-		"<table border=\"0\" cellspacing=\"5\">");
-	render_table_row (buffer, _("Note"),
-		e_contact_get_const (contact, E_CONTACT_NOTE),
-		NULL, E_TEXT_TO_HTML_CONVERT_ADDRESSES | E_TEXT_TO_HTML_CONVERT_URLS | E_TEXT_TO_HTML_CONVERT_NL);
-	g_string_append (buffer, "</table></div>");
-}
-
-
-static void
-render_contact (GString *buffer,
-                EContact *contact,
-                EABContactDisplay *display)
-{
-	render_title_block (buffer, contact);
-
-	g_string_append (buffer, "<div id=\"columns\">");
-	render_contact_column (buffer, contact);
-	render_work_column (buffer, contact, display);
-	render_personal_column (buffer, contact, display);
-	g_string_append (buffer, "</div>");
-
-	render_footer (buffer, contact);
-}
-
-static void
-eab_contact_display_render_normal (EABContactDisplay *display,
-                                   EContact *contact)
-{
-	GString *buffer;
-
-	/* XXX The initial buffer size is arbitrary.  Tune it. */
-
-	buffer = g_string_sized_new (4096);
-	g_string_append (buffer, HTML_HEADER);
-	g_string_append (buffer, "<body>");
-
-	if (contact) {
-		if (e_contact_get (contact, E_CONTACT_IS_LIST))
-			render_contact_list (buffer, contact, display);
-		else
-			render_contact (buffer, contact, display);
-	}
-
-	g_string_append (buffer, "</body></html>\n");
-
-	e_web_view_load_string (E_WEB_VIEW (display), buffer->str);
-
-	g_string_free (buffer, TRUE);
-}
-
-static void
-eab_contact_display_render_compact (EABContactDisplay *display,
-                                    EContact *contact)
-{
-	GString *buffer;
-
-
-	/* XXX The initial buffer size is arbitrary.  Tune it. */
-
-	buffer = g_string_sized_new (4096);
-	g_string_append (buffer, HTML_HEADER);
-	g_string_append (buffer, "<body>\n");
-
-	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
-		}
-
-		g_string_append_printf (
-			buffer,
-			"<table width=\"100%%\" cellpadding=1 cellspacing=0 bgcolor=\"#%06X\">"
-			"<tr><td valign=\"top\">"
-			"<table width=\"100%%\" cellpadding=0 cellspacing=0 bgcolor=\"#%06X\">"
-			"<tr><td valign=\"top\">"
-			"<table>"
-			"<tr><td valign=\"top\">", 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 */
-			if (photo->type == E_CONTACT_PHOTO_TYPE_INLINED) {
-				gdk_pixbuf_loader_write (loader, photo->data.inlined.data, photo->data.inlined.length, NULL);
-			} else if (photo->type == E_CONTACT_PHOTO_TYPE_URI && photo->data.uri &&
-				   g_ascii_strncasecmp (photo->data.uri, "file://", 7) == 0) {
-				gchar *filename, *contents = NULL;
-				gsize length;
-
-				filename = g_filename_from_uri (photo->data.uri, NULL, NULL);
-				if (filename) {
-					if (g_file_get_contents (filename, &contents, &length, NULL)) {
-						gdk_pixbuf_loader_write (loader, (const guchar *) contents, length, NULL);
-						g_free (contents);
-					}
-					g_free (filename);
-				}
-			}
-			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);
-			}
-
-			if (photo->type == E_CONTACT_PHOTO_TYPE_URI && photo->data.uri && *photo->data.uri)
-				g_string_append_printf (
-					buffer,
-					"<img width=\"%d\" height=\"%d\" src=\"%s\">",
-					calced_width, calced_height, photo->data.uri);
-			else {
-				gchar *photo_data = g_base64_encode (
-					photo->data.inlined.data,
-					photo->data.inlined.length);
-				g_string_append_printf (buffer,
-					"<img border=\"1\" src=\"data:%s;base64,%s\" "
-					     "width=\"%d\" height=\"%d\">",
-					photo->data.inlined.mime_type,
-					photo_data,
-					calced_width, calced_height);
-				g_free (photo_data);
-			}
-
-			e_contact_photo_free (photo);
-		}
-
-		g_string_append (buffer, "</td><td valign=\"top\">\n");
-
-		str = e_contact_get_const (contact, E_CONTACT_FILE_AS);
-		if (str) {
-			html = e_text_to_html (str, 0);
-			g_string_append_printf (buffer, "<b>%s</b>", html);
-			g_free (html);
-		}
-		else {
-			str = e_contact_get_const (contact, E_CONTACT_FULL_NAME);
-			if (str) {
-				html = e_text_to_html (str, 0);
-				g_string_append_printf (buffer, "<b>%s</b>", html);
-				g_free (html);
-			}
-		}
-
-		g_string_append (buffer, "<hr>");
-
-		if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
-			GList *email_list;
-			GList *l;
-
-			g_string_append (buffer, "<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\"><tr><td valign=\"top\">");
-			g_string_append_printf (buffer, "<b>%s:</b>&nbsp;<td>", _("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);
-					g_string_append_printf (buffer, "%s, ", html);
-					g_free (html);
-				}
-			}
-			g_string_append (buffer, "</td></tr></table>");
-		}
-		else {
-			gboolean comma = FALSE;
-			str = e_contact_get_const (contact, E_CONTACT_TITLE);
-			if (str) {
-				html = e_text_to_html (str, 0);
-				g_string_append_printf (buffer, "<b>%s:</b> %s<br>", _("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);				\
-													\
-				g_string_append_printf (buffer, "%s%s", comma ? ", " : "", html);	\
-				g_free (html);								\
-				comma = TRUE;								\
-			}
-
-			g_string_append_printf (buffer, "<b>%s:</b> ", _("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 ();
-
-			g_string_append (buffer, "<br>");
-
-			#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);
-				g_string_append_printf (
-					buffer, "<b>%s:</b> %s<br>",
-					_("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);
-				g_string_append_printf (
-					buffer, "<b>%s:</b> %s<br>",
-					_("Blog"), html);
-			}
-		}
-
-		g_string_append (buffer, "</td></tr></table></td></tr></table></td></tr></table>\n");
-	}
-
-	g_string_append (buffer, "</body></html>\n");
-
-	e_web_view_load_string (E_WEB_VIEW (display), buffer->str);
-
-	g_string_free (buffer, TRUE);
+        eab_contact_formatter_format_contact_async (
+                display->priv->formatter,
+                display->priv->contact,
+                NULL, 
+                (GAsyncReadyCallback) contact_formatting_finished,
+                display);
 }
 
 static void
@@ -1323,13 +498,15 @@ eab_contact_display_init (EABContactDisplay *display)
 	GError *error = NULL;
 
 	display->priv = EAB_CONTACT_DISPLAY_GET_PRIVATE (display);
-	display->priv->mode = EAB_CONTACT_DISPLAY_RENDER_NORMAL;
-	display->priv->show_maps = FALSE;
+
+        display->priv->formatter = g_object_new (
+                EAB_TYPE_CONTACT_FORMATTER,
+                "display-mode", EAB_CONTACT_DISPLAY_RENDER_NORMAL,
+                "render-maps", FALSE, NULL);
 
 	web_view = E_WEB_VIEW (display);
 	ui_manager = e_web_view_get_ui_manager (web_view);
 
-
 #ifdef WITH_CONTACT_MAPS
 	g_signal_connect (web_view, "create-plugin-widget",
 		G_CALLBACK (contact_display_object_requested), display);
@@ -1370,27 +547,17 @@ 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;
+	display->priv->contact = contact;
 
-		case EAB_CONTACT_DISPLAY_RENDER_COMPACT:
-			eab_contact_display_render_compact (display, contact);
-			break;
-	}
+        load_contact (display);
 
 	g_object_notify (G_OBJECT (display), "contact");
 }
@@ -1400,29 +567,25 @@ eab_contact_display_get_mode (EABContactDisplay *display)
 {
 	g_return_val_if_fail (EAB_IS_CONTACT_DISPLAY (display), 0);
 
-	return display->priv->mode;
+	return eab_contact_formatter_get_display_mode (display->priv->formatter);
 }
 
 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);
+        if (eab_contact_formatter_get_display_mode (
+                display->priv->formatter) == mode) {
 
-	switch (mode) {
-		case EAB_CONTACT_DISPLAY_RENDER_NORMAL:
-			eab_contact_display_render_normal (display, contact);
-			break;
+                return;
+        };
 
-		case EAB_CONTACT_DISPLAY_RENDER_COMPACT:
-			eab_contact_display_render_compact (display, contact);
-			break;
-	}
+        eab_contact_formatter_set_display_mode (
+                display->priv->formatter, mode);
+
+        load_contact (display);
 
 	g_object_notify (G_OBJECT (display), "mode");
 }
@@ -1432,31 +595,25 @@ eab_contact_display_get_show_maps (EABContactDisplay *display)
 {
 	g_return_val_if_fail (EAB_IS_CONTACT_DISPLAY (display), FALSE);
 
-	return display->priv->show_maps;
+	return eab_contact_formatter_get_render_maps (display->priv->formatter);
 }
 
 void
 eab_contact_display_set_show_maps (EABContactDisplay *display,
                                    gboolean show_maps)
 {
-	EABContactDisplayMode mode;
-	EContact *contact;
-
 	g_return_if_fail (EAB_IS_CONTACT_DISPLAY (display));
 
-	display->priv->show_maps = show_maps;
-	contact = eab_contact_display_get_contact (display);
-	mode = eab_contact_display_get_mode (display);
+        if (eab_contact_formatter_get_render_maps (
+                display->priv->formatter) == show_maps) {
 
-	switch (mode) {
-		case EAB_CONTACT_DISPLAY_RENDER_NORMAL:
-			eab_contact_display_render_normal (display, contact);
-			break;
+                return;
+        }
 
-		case EAB_CONTACT_DISPLAY_RENDER_COMPACT:
-			eab_contact_display_render_compact (display, contact);
-			break;
-	}
+        eab_contact_formatter_set_render_maps (
+                display->priv->formatter, show_maps);
+
+        load_contact (display);
 
 	g_object_notify (G_OBJECT (display), "show-maps");
 }
diff --git a/addressbook/gui/widgets/eab-contact-formatter.c b/addressbook/gui/widgets/eab-contact-formatter.c
new file mode 100644
index 0000000..3111df0
--- /dev/null
+++ b/addressbook/gui/widgets/eab-contact-formatter.c
@@ -0,0 +1,1275 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "eab-contact-formatter.h"
+
+#include "eab-gui-util.h"
+#include "e-util/e-util.h"
+#include "e-util/e-util-private.h"
+#include "e-util/e-html-utils.h"
+#include "e-util/e-icon-factory.h"
+#include "e-util/e-plugin-ui.h"
+
+#ifdef WITH_CONTACT_MAPS
+#include "widgets/misc/e-contact-map.h"
+#endif
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+G_DEFINE_TYPE (
+        EABContactFormatter,
+        eab_contact_formatter,
+        G_TYPE_OBJECT);
+
+#define EAB_CONTACT_FORMATTER_GET_PRIVATE(obj) \
+        (G_TYPE_INSTANCE_GET_PRIVATE \
+        ((obj), EAB_TYPE_CONTACT_FORMATTER, EABContactFormatterPrivate))
+
+#define TEXT_IS_RIGHT_TO_LEFT \
+        (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL)
+
+static gpointer parent_class = NULL;
+
+enum {
+	PROP_0,
+        PROP_DISPLAY_MODE,
+        PROP_RENDER_MAPS
+};
+
+struct _EABContactFormatterPrivate {
+
+        EContact *contact;
+
+        EABContactDisplayMode mode;
+        gboolean render_maps;
+};
+
+static struct {
+	const gchar *name;
+	const gchar *pretty_name;
+}
+common_location[] =
+{
+	{ "WORK",  N_ ("Work")  },
+	{ "HOME",  N_ ("Home")  },
+	{ "OTHER", N_ ("Other") }
+};
+
+#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
+
+
+#define HTML_HEADER "<!doctype html public \"-//W3C//DTD HTML 4.0 TRANSITIONAL//EN\">\n<html>\n"  \
+"<head>\n<meta name=\"generator\" content=\"Evolution Addressbook Component\">\n" \
+"<link type=\"text/css\" rel=\"stylesheet\" href=\"evo-file://" EVOLUTION_PRIVDATADIR "/theme/webview.css\">" \
+"<style type=\"text/css\">\n" \
+"  div#header { width:100%; clear: both; }\n" \
+"  div#columns { width: 100%; clear: both; }\n" \
+"  div#footer { width: 100%; clear: both; }\n" \
+"  div.column { width: auto; float: left; margin-right: 15px; }\n" \
+"  img#contact-photo { float: left; }\n" \
+"  div#contact-name { float: left; margin-left: 20px; }\n" \
+"</style>\n" \
+"<script type=\"text/javascript\">\n" \
+"function collapse_list (obj, listId) {\n" \
+"	var l = document.getElementById (listId);\n" \
+"	if (l.style.display == \"none\") {\n" \
+"		l.style.display = \"block\"; obj.src = obj.src.substr (0, obj.src.lastIndexOf (\"/\")) + \"/minus.png\";\n" \
+"	} else {\n" \
+"		l.style.display = \"none\"; obj.src = obj.src.substr (0, obj.src.lastIndexOf (\"/\")) + \"/plus.png\";\n" \
+"   }\n" \
+"}\n" \
+"</script>\n" \
+"</head>\n"
+
+
+static gchar*
+get_icon_uri (const gchar *icon_name)
+{
+	GtkIconTheme *icon_theme;
+	GtkIconInfo *icon_info;
+	const gchar *filename;
+	gchar *icon_uri;
+	GError *error = NULL;
+	
+	icon_theme = gtk_icon_theme_get_default ();
+	icon_info = gtk_icon_theme_lookup_icon (
+		icon_theme, icon_name, GTK_ICON_SIZE_MENU, 0);
+	g_return_val_if_fail (icon_info != NULL, NULL);
+	
+	filename = gtk_icon_info_get_filename (icon_info);
+	icon_uri = g_filename_to_uri (filename, NULL, &error);
+	
+	if (error != NULL) {
+		g_warning ("%s", error->message);
+		g_error_free (error);
+	}
+	
+	gtk_icon_info_free (icon_info);
+	
+	return icon_uri;
+}
+
+static void
+render_address_link (GString *buffer,
+                     EContact *contact,
+                     gint map_type)
+{
+        EContactAddress *adr;
+        GString *link = g_string_new ("");
+
+        adr = e_contact_get (contact, map_type);
+        if (adr &&
+	    (adr->street || adr->locality || adr->region || adr->country)) {
+		gchar *escaped;
+
+        	if (adr->street && *adr->street)
+			g_string_append_printf (link, "%s, ", adr->street);
+
+        	if (adr->locality && *adr->locality)
+			g_string_append_printf (link, "%s, ", adr->locality);
+
+        	if (adr->region && *adr->region)
+			g_string_append_printf (link, "%s, ", adr->region);
+
+        	if (adr->country && *adr->country)
+			g_string_append_printf (link, "%s", adr->country);
+
+        	escaped = g_uri_escape_string (link->str, NULL, TRUE);
+        	g_string_assign (link, escaped);
+        	g_free (escaped);
+
+        	g_string_prepend (link, "<a href=\"http://maps.google.com?q=";);
+        	g_string_append_printf (link, "\">%s</a>", _("Open map"));
+	}
+
+	if (adr)
+        	e_contact_address_free (adr);
+
+	g_string_append (buffer, link->str);
+        g_string_free (link, TRUE);
+}
+
+static void
+accum_address (GString *buffer,
+               EContact *contact,
+               const gchar *html_label,
+               EContactField adr_field,
+               EContactField label_field)
+{
+        EContactAddress *adr;
+        const gchar *label;
+        GString *map_link = g_string_new ("<br>");
+
+        render_address_link (map_link, contact, adr_field);
+
+        label = e_contact_get_const (contact, label_field);
+        if (label) {
+                gchar *html = e_text_to_html (label, E_TEXT_TO_HTML_CONVERT_NL);
+
+                if (TEXT_IS_RIGHT_TO_LEFT) {
+                        g_string_append_printf (
+				buffer,
+				"<tr>"
+				"<td align=\"right\" valign=\"top\" nowrap>%s</td>"
+				"<th>%s:<br>%s</th>"
+				"<td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\"></td>"
+				"</tr>",
+				html, html_label, map_link->str);
+		} else {
+                        g_string_append_printf (
+				buffer,
+				"<tr>"
+				"<td width=\"" IMAGE_COL_WIDTH "\"></td>"
+				"<th>%s:<br>%s</th>"
+				"<td valign=\"top\" nowrap>%s</td>"
+				"</tr>",
+				html_label, map_link->str, html);
+		}
+
+                g_free (html);
+                g_string_free (map_link, TRUE);
+                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 (TEXT_IS_RIGHT_TO_LEFT) {
+                        g_string_append_printf (
+				buffer, "<tr><td align=\"right\" valign=\"top\" nowrap>");
+		} else {
+                        g_string_append_printf (
+				buffer,
+				"<tr>"
+				"<td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\"></td>"
+				"<th>%s:<br>%s</th>"
+				"<td valign=\"top\" nowrap>",
+				html_label, map_link->str);
+		}
+
+                if (adr->po && *adr->po)
+			g_string_append_printf (buffer, "%s<br>", adr->po);
+
+		if (adr->ext && *adr->ext)
+			g_string_append_printf (buffer, "%s<br>", adr->ext);
+
+		if (adr->street && *adr->street)
+			g_string_append_printf (buffer, "%s<br>", adr->street);
+
+	        if (adr->locality && *adr->locality)
+			g_string_append_printf (buffer, "%s<br>", adr->locality);
+
+        	if (adr->region && *adr->region)
+			g_string_append_printf (buffer, "%s<br>", adr->region);
+
+        	if (adr->code && *adr->code)
+			g_string_append_printf (buffer, "%s<br>", adr->code);
+
+        	if (adr->country && *adr->country)
+			g_string_append_printf (buffer, "%s<br>", adr->country);
+
+        	if (TEXT_IS_RIGHT_TO_LEFT) {
+                	g_string_append_printf (
+				buffer,
+				"</td><th%s:<br>%s</th>"
+				"<td width=\"" IMAGE_COL_WIDTH "\"></td>"
+				"</tr>", html_label, map_link->str);
+		} else {
+                	g_string_append_printf (buffer, "</td></tr>");
+		}
+
+	}
+
+	if (adr)
+		e_contact_address_free (adr);
+
+	g_string_free (map_link, TRUE);
+}
+
+static void
+render_table_row (GString *buffer,
+                  const gchar *label,
+                  const gchar *str,
+                  const gchar *icon,
+                  guint html_flags)
+{
+        const gchar *icon_html;
+        gchar *value;
+
+        if (html_flags)
+                value = e_text_to_html (str, html_flags);
+        else
+                value = (gchar*)str;
+
+        if (icon) {
+                gchar *icon_uri = get_icon_uri (icon);
+                icon_html = g_strdup_printf ("<img src=\"%s\" width=\"16\" height=\"16\" />", icon_uri);
+                g_free (icon_uri);
+        } else {
+                icon_html = "";
+        }
+
+        if (TEXT_IS_RIGHT_TO_LEFT) {
+                g_string_append_printf (
+                        buffer, "<tr>"
+                        "<td valign=\"top\" align=\"right\">%s</td>"
+                        "<th align=\"right\" valign=\"top\" width=\"100\" nowrap>:%s</th>"
+                        "<td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\">%s</td>"
+                        "</tr>",
+                        value, label, icon_html);
+        } else {
+                g_string_append_printf (
+                        buffer, "<tr>"
+                        "<td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\">%s</td>"
+                        "<th valign=\"top\" width=\"100\" nowrap>%s:</th>"
+                        "<td valign=\"top\">%s</td>"
+                        "</tr>",
+                        icon_html, label, value);
+        }
+
+        if (html_flags)
+                g_free (value);
+}
+
+static void
+accum_attribute (GString *buffer,
+                 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 != NULL && *str != '\0')
+                render_table_row (buffer, html_label, str, icon, html_flags);
+}
+
+static void
+accum_time_attribute (GString *buffer,
+                      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);
+                render_table_row (buffer, html_label, sdate, icon, html_flags);
+                e_contact_date_free (date);
+        }
+}
+
+static void
+accum_attribute_multival (GString *buffer,
+                          EContact *contact,
+                          const gchar *html_label,
+                          EContactField field,
+                          const gchar *icon,
+                          guint html_flags)
+{
+        GList *val_list, *l;
+        GString *val = g_string_new ("");
+
+        val_list = e_contact_get (contact, field);
+
+        for (l = val_list; l; l = l->next) {
+                if (l != val_list)
+                        g_string_append (val, "<br>");
+
+                g_string_append (val, l->data);
+        }
+
+        if (val->str && *val->str)
+                render_table_row (buffer, html_label, val->str, icon, html_flags);
+
+        g_string_free (val, TRUE);
+        g_list_foreach (val_list, (GFunc) g_free, NULL);
+        g_list_free (val_list);
+}
+
+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_title_block (EABContactFormatter *formatter,
+		    GString *buffer)
+{
+        const gchar *str;
+        gchar *html;
+        EContactPhoto *photo;
+	EContact *contact;
+
+	contact = formatter->priv->contact;
+
+        g_string_append_printf (
+                buffer,
+		"<table border=\"0\"><tr>"
+                "<td %s valign=\"middle\">", TEXT_IS_RIGHT_TO_LEFT ?
+                "align=\"right\"" : "");
+
+        photo = e_contact_get (contact, E_CONTACT_PHOTO);
+        if (!photo)
+                photo = e_contact_get (contact, E_CONTACT_LOGO);
+
+        if (photo && photo->type == E_CONTACT_PHOTO_TYPE_INLINED) {
+                gchar *photo_data;
+		photo_data = g_base64_encode (
+				photo->data.inlined.data,
+				photo->data.inlined.length);
+                g_string_append_printf (
+			buffer, "<img border=\"1\" src=\"data:%s;base64,%s\">",
+                        photo->data.inlined.mime_type,
+                        photo_data);
+        } else if (photo && photo->type == E_CONTACT_PHOTO_TYPE_URI && photo->data.uri && *photo->data.uri) {
+                g_string_append_printf (
+			buffer, "<img border=\"1\" src=\"%s\">", photo->data.uri);
+        }
+
+        if (photo)
+                e_contact_photo_free (photo);
+
+        if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
+                gchar *icon = get_icon_uri (CONTACT_LIST_ICON);
+                g_string_append_printf (buffer, "<img src=\"%s\">", icon);
+                g_free (icon);
+        }
+
+        g_string_append_printf (
+                buffer,
+		"</td><td width=\"20\"></td><td %s valign=\"top\">\n",
+                TEXT_IS_RIGHT_TO_LEFT ? "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);
+                if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
+                        g_string_append_printf (
+				buffer,
+				"<h2><a href=\"internal-mailto:0\";>%s</a></h2>",
+				html);
+		} else {
+                        g_string_append_printf (buffer, "<h2>%s</h2>", html);
+		}
+                g_free (html);
+        }
+
+        g_string_append (buffer, "</td></tr></table>");
+}
+
+static void
+render_contact_list_row (EABContactFormatter *formatter,
+			 EDestination *destination,
+			 GString *buffer)
+{
+        gchar *evolution_imagesdir;
+        gboolean list_collapsed = FALSE;
+        const gchar *textrep;
+        gchar *name = NULL, *email_addr = NULL;
+
+	evolution_imagesdir = g_filename_to_uri (EVOLUTION_IMAGESDIR, NULL, NULL);
+
+        textrep = e_destination_get_textrep (destination, TRUE);
+        if (!eab_parse_qp_email (textrep, &name, &email_addr))
+                email_addr = g_strdup (textrep);
+
+        g_string_append (buffer, "<tr>");
+        if (e_destination_is_evolution_list (destination)) {
+                g_string_append_printf (
+			buffer,
+                        "<td width=" IMAGE_COL_WIDTH " valign=\"top\">"
+			"<img src=\"%s/minus.png\" "
+			     "onClick=\"collapse_list(this, %s);\" "
+			     "class=\"navigable\">"
+			"</td><td width=\"100%%\">%s",
+                        evolution_imagesdir,
+                        e_destination_get_contact_uid (destination),
+                        name ? name : email_addr);
+
+                if (!list_collapsed) {
+                        const GList *dest, *dests;
+                        g_string_append_printf (
+				buffer,
+				"<br><table cellspacing=\"1\" id=\"%s\">",
+                                e_destination_get_contact_uid (destination));
+
+                        dests = e_destination_list_get_root_dests (destination);
+                        for (dest = dests; dest; dest = dest->next) {
+                                render_contact_list_row (
+					formatter, dest->data, buffer);
+                        }
+
+                        g_string_append (buffer, "</table>");
+                }
+
+                g_string_append (buffer, "</td>");
+
+        } else {
+                if (name && *name) {
+                        g_string_append_printf (
+				buffer,
+				"<td colspan=\"2\">%s &lt"
+				"<a href=\"mailto:%s\";>%s</a>&gt;"
+				"</td>",
+				name, email_addr, email_addr);
+                } else {
+                        g_string_append_printf (
+				buffer,
+				"<td colspan=\"2\">"
+				"<a href=\"mailto:%s\";>%s</a>"
+				"</td>",
+				email_addr, email_addr);
+                }
+        }
+
+        g_string_append (buffer, "</tr>");
+
+        g_free (evolution_imagesdir);
+        g_free (name);
+        g_free (email_addr);
+}
+
+static void
+render_contact_list (EABContactFormatter *formatter,
+		     GString *buffer)
+{
+	EContact *contact;
+        EDestination *destination;
+        const GList *dest, *dests;
+
+	contact = formatter->priv->contact;
+
+        destination = e_destination_new ();
+        e_destination_set_contact (destination, contact, 0);
+        dests = e_destination_list_get_root_dests (destination);
+
+        render_title_block (formatter, buffer);
+
+        g_string_append_printf (
+		buffer,
+		"<table border=\"0\"><tr><th colspan=\"2\">%s</th></tr>"
+		"<tr><td with=" IMAGE_COL_WIDTH "></td><td>", _("List Members:"));
+
+        g_string_append (buffer, "<table border=\"0\" cellspacing=\"1\">");
+
+        for (dest = dests; dest; dest = dest->next)
+                render_contact_list_row (formatter, dest->data, buffer);
+
+        g_string_append (buffer, "</table>");
+        g_string_append (buffer, "</td></tr></table>");
+
+        g_object_unref (destination);
+}
+
+static void
+render_contact_column (EABContactFormatter *formatter,
+		       GString *buffer)
+{
+	EContact *contact;
+        GString *accum, *email;
+        GList *email_list, *l, *email_attr_list, *al;
+        gint email_num = 0;
+        const gchar *nl;
+
+	contact = formatter->priv->contact;
+        email = g_string_new ("");
+        nl = "";
+
+        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 *name = NULL, *mail = NULL;
+                gchar *attr_str = (gchar *) get_email_location ((EVCardAttribute *) al->data);
+
+                if (!eab_parse_qp_email (l->data, &name, &mail))
+                        mail = e_text_to_html (l->data, 0);
+
+                g_string_append_printf (
+			email,
+			"%s%s%s<a href=\"internal-mailto:%d\";>%s</a>%s "
+			"<span class=\"header\">(%s)</span>",
+                        nl,
+                        name ? name : "",
+                        name ? " &lt;" : "",
+                        email_num,
+                        mail,
+                        name ? "&gt;" : "",
+                        attr_str ? attr_str : "");
+                email_num++;
+                nl = "<br>";
+
+                g_free (name);
+                g_free (mail);
+        }
+        g_list_foreach (email_list, (GFunc) g_free, NULL);
+        g_list_foreach (email_attr_list, (GFunc) e_vcard_attribute_free, NULL);
+        g_list_free (email_list);
+        g_list_free (email_attr_list);
+
+        accum = g_string_new ("");
+
+        if (email->len)
+                render_table_row (accum, _("Email"), email->str, NULL, 0);
+
+        accum_attribute (accum, contact, _("Nickname"), E_CONTACT_NICKNAME, NULL, 0);
+        accum_attribute_multival (accum, contact, _("AIM"), E_CONTACT_IM_AIM, AIM_ICON, 0);
+        accum_attribute_multival (accum, contact, _("GroupWise"), E_CONTACT_IM_GROUPWISE, GROUPWISE_ICON, 0);
+        accum_attribute_multival (accum, contact, _("ICQ"), E_CONTACT_IM_ICQ, ICQ_ICON, 0);
+        accum_attribute_multival (accum, contact, _("Jabber"), E_CONTACT_IM_JABBER, JABBER_ICON, 0);
+        accum_attribute_multival (accum, contact, _("MSN"), E_CONTACT_IM_MSN, MSN_ICON, 0);
+        accum_attribute_multival (accum, contact, _("Yahoo"), E_CONTACT_IM_YAHOO, YAHOO_ICON, 0);
+        accum_attribute_multival (accum, contact, _("Gadu-Gadu"), E_CONTACT_IM_GADUGADU, GADUGADU_ICON, 0);
+        accum_attribute_multival (accum, contact, _("Skype"), E_CONTACT_IM_SKYPE, SKYPE_ICON, 0);
+
+        if (accum->len)
+                g_string_append_printf (
+			buffer,
+                        "<div class=\"column\" id=\"contact-internet\">"
+                        "<table border=\"0\" cellspacing=\"5\">%s</table>"
+                        "</div>", accum->str);
+
+	g_string_free (accum, TRUE);
+        g_string_free (email, TRUE);
+}
+
+
+static void
+accum_address_map (GString *buffer,
+                   EContact *contact,
+                   gint map_type)
+{
+        #ifdef WITH_CONTACT_MAPS
+
+        g_string_append (buffer, "<tr><td colspan=\"3\">");
+
+        if (map_type == E_CONTACT_ADDRESS_WORK) {
+                g_string_append (buffer,
+                                 "<object type=\"application/x-work-map-widget\" "
+                                 "width=\"250\" height=\"250\"></object>");
+        } else {
+                g_string_append (buffer,
+                                 "<object type=\"application/x-home-map-widget\" "
+                                 "width=\"250\" height=\"250\"></object>");
+        }
+
+        g_string_append (buffer, "</td></tr>");
+
+        #endif
+}
+
+static void
+render_work_column (EABContactFormatter *formatter,
+		    GString *buffer)
+{
+	EContact *contact = formatter->priv->contact;
+        GString *accum = g_string_new ("");
+
+        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 (formatter->priv->render_maps)
+                accum_address_map (accum, contact, E_CONTACT_ADDRESS_WORK);
+
+        if (accum->len > 0) {
+                g_string_append_printf (
+			buffer,
+                        "<div class=\"column\" id=\"contact-work\">"
+                        "<h3>%s</h3>"
+                        "<table border=\"0\" cellspacing=\"5\">%s</table>"
+                        "</div>", _("Work"), accum->str);
+        }
+
+        g_string_free (accum, TRUE);
+}
+
+static void
+render_personal_column (EABContactFormatter *formatter,
+			GString *buffer)
+{
+	EContact *contact = formatter->priv->contact;
+        GString *accum = g_string_new ("");
+
+        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 (formatter->priv->render_maps)
+                accum_address_map (accum, contact, E_CONTACT_ADDRESS_HOME);
+
+        if (accum->len > 0) {
+                g_string_append_printf (
+			buffer,
+                        "<div class=\"column\" id=\"contact-personal\">"
+                        "<h3>%s</h3>"
+                        "<table border=\"0\" cellspacing=\"5\">%s</table>"
+                        "</div>", _("Personal"), accum->str);
+        }
+
+        g_string_free (accum, TRUE);
+}
+
+static void
+render_footer (EABContactFormatter *formatter,
+	       GString *buffer)
+{
+	EContact *contact;
+        const gchar *str;
+
+	contact = formatter->priv->contact;
+
+        str = e_contact_get_const (contact, E_CONTACT_NOTE);
+        if (!str || !*str)
+                return;
+
+        g_string_append (
+		buffer, 
+		"<div id=\"footer\"><table border=\"0\" cellspacing=\"5\">");
+
+        render_table_row (
+		buffer, _("Note"),
+                e_contact_get_const (contact, E_CONTACT_NOTE),
+                NULL,
+		E_TEXT_TO_HTML_CONVERT_ADDRESSES | 
+                E_TEXT_TO_HTML_CONVERT_URLS |
+                E_TEXT_TO_HTML_CONVERT_NL);
+
+        g_string_append (buffer, "</table></div>");
+}
+
+
+static void
+render_contact (EABContactFormatter *formatter,
+		GString *buffer)
+{
+	render_title_block (formatter, buffer);
+
+        g_string_append (buffer, "<div id=\"columns\">");
+	render_contact_column (formatter, buffer);
+	render_work_column (formatter, buffer);
+	render_personal_column (formatter, buffer);
+        g_string_append (buffer, "</div>");
+
+	render_footer (formatter, buffer);
+}
+
+static void
+render_normal (EABContactFormatter *formatter,
+	       GString *buffer)
+{
+        g_string_append (buffer, HTML_HEADER);
+        g_string_append (buffer, "<body>");
+
+        if (formatter->priv->contact) {
+
+                if (e_contact_get (formatter->priv->contact, E_CONTACT_IS_LIST))
+
+                        render_contact_list (
+                                formatter,
+                                buffer);
+                else
+                        render_contact (
+                                formatter,
+                                buffer);
+
+        }
+
+        g_string_append (buffer, "</body></html>\n");
+}
+
+static void
+render_compact (EABContactFormatter *formatter,
+		GString *buffer)
+{
+	EContact *contact = formatter->priv->contact;
+	const gchar *str;
+	gchar *html;
+	EContactPhoto *photo;
+	
+	g_string_append (buffer, HTML_HEADER);
+	g_string_append (buffer, "<body>\n");
+
+	if (!contact) {
+		g_string_append (buffer, "</body></html>");
+		return;
+	}
+	
+	g_string_append_printf (
+		buffer,
+		"<table><tr><td valign=\"top\">");
+
+	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 */
+		if (photo->type == E_CONTACT_PHOTO_TYPE_INLINED) {
+			gdk_pixbuf_loader_write (
+				loader, photo->data.inlined.data,
+				photo->data.inlined.length, NULL);
+		} else if (photo->type == E_CONTACT_PHOTO_TYPE_URI && 
+				photo->data.uri &&
+				g_ascii_strncasecmp (photo->data.uri, "file://", 7) == 0) {
+			gchar *filename, *contents = NULL;
+			gsize length;
+
+			filename = g_filename_from_uri (photo->data.uri, NULL, NULL);
+
+			if (filename) {
+				if (g_file_get_contents (filename, &contents, &length, NULL)) {
+					gdk_pixbuf_loader_write (loader, (const guchar *) contents, length, NULL);
+					g_free (contents);
+				}
+
+				g_free (filename);
+			}
+		}
+
+		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);
+		}
+
+		if (photo->type == E_CONTACT_PHOTO_TYPE_URI && 
+			photo->data.uri && *photo->data.uri)
+			g_string_append_printf (
+				buffer,
+				"<img width=\"%d\" height=\"%d\" src=\"%s\">",
+				calced_width, calced_height, photo->data.uri);
+		else {
+			gchar *photo_data;
+
+			photo_data = g_base64_encode (
+					photo->data.inlined.data,
+					photo->data.inlined.length);
+			g_string_append_printf (buffer,
+				"<img border=\"1\" src=\"data:%s;base64,%s\" "
+					"width=\"%d\" height=\"%d\">",
+				photo->data.inlined.mime_type,
+				photo_data,
+				calced_width, calced_height);
+				g_free (photo_data);
+		}
+
+		e_contact_photo_free (photo);
+	}
+
+	g_string_append (buffer, "</td><td width=\"5\"></td><td valign=\"top\">\n");
+
+	str = e_contact_get_const (contact, E_CONTACT_FILE_AS);
+
+	if (str) {
+		html = e_text_to_html (str, 0);
+		g_string_append_printf (buffer, "<b>%s</b>", html);
+		g_free (html);
+	} else {
+		str = e_contact_get_const (contact, E_CONTACT_FULL_NAME);
+
+		if (str) {
+			html = e_text_to_html (str, 0);
+			g_string_append_printf (buffer, "<b>%s</b>", html);
+			g_free (html);
+		}
+	}
+
+	g_string_append (buffer, "<hr>");
+
+	if (e_contact_get (contact, E_CONTACT_IS_LIST)) {
+		GList *email_list;
+		GList *l;
+
+		g_string_append (
+			buffer,
+			"<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">"
+			"<tr><td valign=\"top\">");
+		g_string_append_printf (
+			buffer,
+			"<b>%s:</b>&nbsp;<td>", _ ("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);
+				g_string_append_printf (buffer, "%s, ", html);
+				g_free (html);
+			}
+		}
+
+		g_string_append (buffer, "</td></tr></table>");
+
+	} else {
+
+		gboolean comma = FALSE;
+		str = e_contact_get_const (contact, E_CONTACT_TITLE);
+
+		if (str) {
+			html = e_text_to_html (str, 0);
+			g_string_append_printf (buffer, "<b>%s:</b> %s<br>", _ ("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);					\
+			\
+			g_string_append_printf (buffer, "%s%s", comma ? ", " : "", html);	\
+			g_free (html);								\
+			comma = TRUE;								\
+		}
+
+		g_string_append_printf (buffer, "<b>%s:</b> ", _ ("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 ();
+
+		g_string_append (buffer, "<br>");
+
+		#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);
+			g_string_append_printf (
+				buffer, "<b>%s:</b> %s<br>",
+				_ ("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);
+			g_string_append_printf (
+				buffer, "<b>%s:</b> %s<br>",
+				_ ("Blog"), html);
+		}
+	}
+
+	g_string_append (buffer, "</td></tr></table>\n");
+
+	g_string_append (buffer, "</body></html>\n");
+}
+
+static CamelStream*
+format_contact (EABContactFormatter *formatter,
+                GCancellable *cancellable)
+{
+	GString *buffer;
+	CamelStream *stream;
+
+	buffer = g_string_new ("");
+
+        if (formatter->priv->mode == EAB_CONTACT_DISPLAY_RENDER_NORMAL) {
+                render_normal (formatter, buffer);
+	} else {
+                render_compact (formatter, buffer);
+	}
+
+	stream = camel_stream_mem_new ();
+	camel_stream_write_string (stream, buffer->str, cancellable, NULL);
+
+	g_string_free (buffer, TRUE);
+
+	return stream;
+}
+
+static void
+do_start_async_formatter (GSimpleAsyncResult *result,
+                          GObject *object,
+                          GCancellable *cancellable)
+{
+        EABContactFormatter *formatter;
+	CamelStream *stream;
+
+        formatter = EAB_CONTACT_FORMATTER (object);
+
+        stream = format_contact (formatter, cancellable);
+
+	g_simple_async_result_set_op_res_gpointer (result, stream, NULL);
+}
+
+static void
+eab_contact_formatter_set_property (GObject *object,
+				    guint property_id,
+				    const GValue *value,
+				    GParamSpec *pspec)
+{				
+	EABContactFormatter *formatter = EAB_CONTACT_FORMATTER (object);
+
+	switch (property_id) {
+		case PROP_DISPLAY_MODE:
+			eab_contact_formatter_set_display_mode (
+				formatter, g_value_get_int (value));
+			return;
+		case PROP_RENDER_MAPS:
+			eab_contact_formatter_set_render_maps (
+				formatter, g_value_get_boolean (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+eab_contact_formatter_get_property (GObject *object,
+				    guint property_id,
+				    GValue *value,
+				    GParamSpec *pspec)
+{
+	EABContactFormatter *formatter = EAB_CONTACT_FORMATTER (object);
+
+	switch (property_id) {
+		case PROP_DISPLAY_MODE:
+			g_value_set_int (value,
+				eab_contact_formatter_get_display_mode (
+					formatter));
+			return;
+		case PROP_RENDER_MAPS:
+			g_value_set_boolean (value,
+				eab_contact_formatter_get_render_maps (
+					formatter));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+
+
+static void
+eab_contact_formatter_finalize (GObject *object)
+{
+	EABContactFormatter *formatter;
+
+	formatter = EAB_CONTACT_FORMATTER (object);
+
+        if (formatter->priv->contact) {
+                g_object_unref (formatter->priv->contact);
+                formatter->priv->contact = NULL;
+        }
+
+        G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+eab_contact_formatter_class_init (EABContactFormatterClass *klass)
+{
+        GObjectClass *object_class;
+
+        parent_class = g_type_class_peek_parent (klass);
+        g_type_class_add_private (klass, sizeof (EABContactFormatterClass));
+
+        object_class = G_OBJECT_CLASS (klass);
+        object_class->finalize = eab_contact_formatter_finalize;
+	object_class->set_property = eab_contact_formatter_set_property;
+	object_class->get_property = eab_contact_formatter_get_property;
+
+        g_object_class_install_property (
+                object_class,
+                PROP_DISPLAY_MODE,
+                g_param_spec_int (
+                        "display-mode",
+                        "",
+                        "",
+                        EAB_CONTACT_DISPLAY_RENDER_NORMAL,
+                        EAB_CONTACT_DISPLAY_RENDER_COMPACT,
+                        EAB_CONTACT_DISPLAY_RENDER_NORMAL,
+                        G_PARAM_READWRITE));
+
+        g_object_class_install_property (
+                object_class,
+                PROP_RENDER_MAPS,
+                g_param_spec_boolean (
+                        "render-maps",
+                        "",
+                        "",
+                        FALSE,
+                        G_PARAM_READWRITE));
+}
+
+static void
+eab_contact_formatter_init (EABContactFormatter *formatter)
+{
+        formatter->priv = EAB_CONTACT_FORMATTER_GET_PRIVATE (formatter);
+
+        formatter->priv->contact = NULL;
+        formatter->priv->mode = EAB_CONTACT_DISPLAY_RENDER_NORMAL;
+        formatter->priv->render_maps = FALSE;
+}
+
+void
+eab_contact_formatter_set_display_mode (EABContactFormatter *formatter,
+                                        EABContactDisplayMode mode)
+{
+        g_return_if_fail (EAB_IS_CONTACT_FORMATTER (formatter));
+
+        if (formatter->priv->mode == mode)
+                return;
+
+        formatter->priv->mode = mode;
+
+        g_object_notify (G_OBJECT (formatter), "display-mode");
+}
+
+EABContactDisplayMode
+eab_contact_formatter_get_display_mode (EABContactFormatter *formatter)
+{
+        g_return_val_if_fail (EAB_IS_CONTACT_FORMATTER (formatter),
+                              EAB_CONTACT_DISPLAY_RENDER_NORMAL);
+
+        return formatter->priv->mode;
+}
+
+void
+eab_contact_formatter_set_render_maps (EABContactFormatter *formatter,
+                                       gboolean render_maps)
+{
+        g_return_if_fail (EAB_IS_CONTACT_FORMATTER (formatter));
+
+        if (formatter->priv->render_maps == render_maps)
+                return;
+
+        formatter->priv->render_maps = render_maps;
+
+        g_object_notify (G_OBJECT (formatter), "render-maps");
+}
+
+gboolean
+eab_contact_formatter_get_render_maps (EABContactFormatter *formatter)
+{
+        g_return_val_if_fail (EAB_IS_CONTACT_FORMATTER (formatter), FALSE);
+
+        return formatter->priv->render_maps;
+}
+
+void
+eab_contact_formatter_format_contact_sync (EABContactFormatter *formatter,
+                                           EContact *contact,
+					   CamelStream *stream,
+                                           GCancellable *cancellable)
+{
+	CamelStream *out;
+
+        g_return_if_fail (EAB_IS_CONTACT_FORMATTER (formatter));
+        g_return_if_fail (E_IS_CONTACT (contact));
+
+        g_object_ref (contact);
+
+        if (formatter->priv->contact)
+                g_object_unref (formatter->priv->contact);
+
+	formatter->priv->contact = contact;
+
+        out = format_contact (formatter, cancellable);
+
+	g_seekable_seek (G_SEEKABLE (out), 0, G_SEEK_SET, cancellable, NULL);
+	camel_stream_write_to_stream (out, stream, cancellable, NULL);
+
+	g_object_unref (out);
+}
+
+
+void
+eab_contact_formatter_format_contact_async (EABContactFormatter *formatter,
+                                            EContact *contact,
+                                            GCancellable *cancellable,
+                                            GAsyncReadyCallback callback,
+                                            gpointer user_data)
+{
+        GSimpleAsyncResult *result;
+
+        g_return_if_fail (EAB_IS_CONTACT_FORMATTER (formatter));
+        g_return_if_fail (E_IS_CONTACT (contact));
+        g_return_if_fail (callback != NULL);
+
+        g_object_ref (contact);
+        if (formatter->priv->contact)
+                g_object_unref (formatter->priv->contact);
+
+	formatter->priv->contact = contact;	
+
+
+        result = g_simple_async_result_new (
+                        G_OBJECT (formatter),
+                        callback, user_data,
+                        eab_contact_formatter_format_contact_async);
+
+        g_simple_async_result_run_in_thread (
+                result, do_start_async_formatter,
+		G_PRIORITY_DEFAULT, cancellable);
+}
diff --git a/addressbook/gui/widgets/eab-contact-formatter.h b/addressbook/gui/widgets/eab-contact-formatter.h
new file mode 100644
index 0000000..4a0e95f
--- /dev/null
+++ b/addressbook/gui/widgets/eab-contact-formatter.h
@@ -0,0 +1,89 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef EAB_CONTACT_FORMATTER_H
+#define EAB_CONTACT_FORMATTER_H
+
+#include <libebook/e-contact.h>
+#include <addressbook/gui/widgets/eab-contact-display.h>
+
+#include <camel/camel.h>
+
+/* Standard GObject macros */
+#define EAB_TYPE_CONTACT_FORMATTER \
+(eab_contact_formatter_get_type ())
+#define EAB_CONTACT_FORMATTER(obj) \
+(G_TYPE_CHECK_INSTANCE_CAST \
+((obj), EAB_TYPE_CONTACT_FORMATTER, EABContactFormatter))
+#define EAB_CONTACT_FORMATTER_CLASS(cls) \
+(G_TYPE_CHECK_CLASS_CAST \
+((cls), EAB_TYPE_CONTACT_FORMATTER, EABContactFormatterClass))
+#define EAB_IS_CONTACT_FORMATTER(obj) \
+(G_TYPE_CHECK_INSTANCE_TYPE \
+((obj), EAB_TYPE_CONTACT_FORMATTER))
+#define EAB_IS_CONTACT_FORMATTER_CLASS(cls) \
+(G_TYPE_CHECK_CLASS_TYPE \
+((cls), EAB_TYPE_CONTACT_FORMATTER))
+#define EAB_CONTACT_FORMATTER_GET_CLASS(obj) \
+(G_TYPE_ISNTANCE_GET_CLASS \
+((obj), EAB_TYPE_CONTACT_FORMATTER, EABContactFormatterClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EABContactFormatter EABContactFormatter;
+typedef struct _EABContactFormatterClass EABContactFormatterClass;
+typedef struct _EABContactFormatterPrivate EABContactFormatterPrivate;
+
+struct _EABContactFormatter {
+        GObject parent;
+        EABContactFormatterPrivate *priv;
+};
+
+struct _EABContactFormatterClass {
+        GObjectClass parent_class;
+};
+
+GType           eab_contact_formatter_get_type  ();
+
+void            eab_contact_formatter_set_render_maps
+                                                (EABContactFormatter *formatter,
+                                                 gboolean render_maps);
+gboolean        eab_contact_formatter_get_render_maps
+                                                (EABContactFormatter *formatter);
+
+void            eab_contact_formatter_set_display_mode
+                                                (EABContactFormatter *formatter,
+                                                 EABContactDisplayMode mode);
+EABContactDisplayMode
+                eab_contact_formatter_get_display_mode
+                                                (EABContactFormatter *formatter);
+
+void            eab_contact_formatter_format_contact_sync
+                                                (EABContactFormatter *formatter,
+                                                 EContact *contact,
+						 CamelStream *stream,
+                                                 GCancellable *cancellable);
+
+void            eab_contact_formatter_format_contact_async
+                                                (EABContactFormatter *formatter,
+                                                 EContact *contact,
+                                                 GCancellable *cancellable,
+                                                 GAsyncReadyCallback callback,
+                                                 gpointer user_data);
+
+G_END_DECLS
+
+#endif



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]