[evolution] WebKit port - port addressbook, calendar and update composer to keep working with GtkHtml



commit a269411bacc7a7ce549db591204a868a7a8b2184
Author: Dan VrÃtil <dvratil redhat com>
Date:   Wed Mar 28 18:39:13 2012 +0200

    WebKit port - port addressbook, calendar and update composer to keep working with GtkHtml

 addressbook/gui/widgets/Makefile.am             |    3 +
 addressbook/gui/widgets/eab-contact-display.c   | 1189 ++--------------------
 addressbook/gui/widgets/eab-contact-formatter.c | 1267 +++++++++++++++++++++++
 addressbook/gui/widgets/eab-contact-formatter.h |   89 ++
 addressbook/importers/Makefile.am               |    5 +-
 calendar/gui/Makefile.am                        |    1 +
 calendar/gui/e-cal-component-preview.c          |   91 +-
 composer/e-composer-actions.c                   |    2 +-
 composer/e-composer-activity.c                  |   10 +-
 composer/e-composer-private.c                   |    2 +-
 composer/e-composer-private.h                   |    2 +-
 composer/e-msg-composer.c                       |   39 +-
 composer/e-msg-composer.h                       |    5 +-
 e-util/e-marshal.list                           |    1 +
 14 files changed, 1497 insertions(+), 1209 deletions(-)
---
diff --git a/addressbook/gui/widgets/Makefile.am b/addressbook/gui/widgets/Makefile.am
index 546a218..19c9c4f 100644
--- a/addressbook/gui/widgets/Makefile.am
+++ b/addressbook/gui/widgets/Makefile.am
@@ -10,6 +10,7 @@ libeabwidgets_la_CPPFLAGS =				\
 	-DEVOLUTION_GALVIEWSDIR=\""$(viewsdir)"\"	\
 	-DEVOLUTION_RULEDIR=\"$(ruledir)\"		\
 	-DEVOLUTION_IMAGESDIR=\"${imagesdir}\"		\
+	-DEVOLUTION_PRIVDATADIR=\"${privdatadir}\"	\
 	-I$(top_srcdir)					\
 	-I$(top_srcdir)/filter				\
 	-I$(top_srcdir)/widgets				\
@@ -32,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 8ade5c5..fe1728c 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"
@@ -39,9 +40,6 @@
 
 #include <string.h>
 #include <glib/gi18n.h>
-#include <gtkhtml/gtkhtml.h>
-#include <gtkhtml/gtkhtml-stream.h>
-#include <gtkhtml/gtkhtml-embedded.h>
 
 #define EAB_CONTACT_DISPLAY_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE \
@@ -52,18 +50,13 @@
 
 struct _EABContactDisplayPrivate {
 	EContact *contact;
-	EABContactDisplayMode mode;
-	GtkOrientation orientation;
-	gboolean show_maps;
-
-	GHashTable *closed_lists; /* see render_contact_list_ * */
+        EABContactFormatter *formatter;
 };
 
 enum {
 	PROP_0,
 	PROP_CONTACT,
 	PROP_MODE,
-	PROP_ORIENTATION,
 	PROP_SHOW_MAPS
 };
 
@@ -72,35 +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 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</head>\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 =
 "<ui>"
 "  <popup name='context'>"
@@ -202,899 +166,37 @@ static GtkActionEntry internal_mailto_entries[] = {
 };
 
 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><td valign=\"top\" width=\"100\" align=\"right\" nowrap><font color=" HEADER_COLOR ">%s:</font>%s</td><td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\"></td></tr>", html, html_label, map_link->str);
-		else
-			g_string_append_printf (buffer, "<tr><td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\"></td><td valign=\"top\" width=\"100\" nowrap><font color=" HEADER_COLOR ">%s:</font>%s</td><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><td valign=\"top\" width=\"100\"><font color=" HEADER_COLOR ">%s:</font>%s</td><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><td valign=\"top\" width=\"100\" align=\"right\"><font color=" HEADER_COLOR ">%s:</font>%s</td><td valign=\"top\" 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
-accum_name_value (GString *buffer,
-                  const gchar *label,
-                  const gchar *str,
-                  const gchar *icon,
-                  guint html_flags)
-{
-	gchar *value = e_text_to_html (str, html_flags);
-
-	if (TEXT_IS_RIGHT_TO_LEFT) {
-		g_string_append_printf (
-			buffer, "<tr>"
-			"<td valign=\"top\" align=\"right\">%s</td> "
-			"<td align=\"right\" valign=\"top\" width=\"100\" nowrap>"
-			"<font color=" HEADER_COLOR ">%s:</font></td>",
-			value, label);
-		g_string_append_printf (
-			buffer, "<td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\">");
-		if (icon != NULL)
-			g_string_append_printf (
-				buffer, "<img width=\"16\" height=\"16\" "
-				"src=\"evo-icon:%s\"></td></tr>", icon);
-		else
-			g_string_append_printf (buffer, "</td></tr>");
-	} else {
-		g_string_append_printf (
-			buffer, "<tr><td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\">");
-		if (icon != NULL)
-			g_string_append_printf (
-				buffer, "<img width=\"16\" height=\"16\" "
-				"src=\"evo-icon:%s\">", icon);
-		g_string_append_printf (
-			buffer, "</td><td valign=\"top\" width=\"100\" nowrap>"
-			"<font color=" HEADER_COLOR ">%s:</font>"
-			"</td> <td valign=\"top\">%s</td></tr>",
-			label, value);
-	}
-
-	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')
-		accum_name_value (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);
-		accum_name_value (buffer, html_label, sdate, icon, html_flags);
-		e_contact_date_free (date);
-	}
-}
-
-static void
-accum_multival_attribute (GString *buffer,
-                          EContact *contact,
-                          const gchar *html_label,
-                          EContactField field,
-                          const gchar *icon,
-                          guint html_flags)
-{
-	GList *val_list, *l;
-
-	/* Workaround till bug [1] is fixed.
-	 * [1] https://bugzilla.gnome.org/show_bug.cgi?id=473862 */
-	icon = NULL;
-
-	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 (buffer, html_label, str, icon, html_flags);
-	}
-	g_list_foreach (val_list, (GFunc) g_free, NULL);
-	g_list_free (val_list);
-}
-
-static void
-start_block (GString *buffer,
-             const gchar *label)
-{
-	g_string_append_printf (
-		buffer, "<tr><td height=\"20\" colspan=\"3\">"
-		"<font color=" HEADER_COLOR "><b>%s</b>"
-		"</font></td></tr>", label);
-}
-
-static void
-end_block (GString *buffer)
-{
-	g_string_append (buffer, "<tr><td height=\"20\">&nbsp;</td></tr>");
-}
-
-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)
+contact_formatting_finished (GObject *object,
+                             GSimpleAsyncResult *result,
+                             gpointer user_data)
 {
-	const gchar *str;
+	EABContactDisplay *display = user_data;
+	CamelStreamMem *stream;
 	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) {
-		g_string_append (buffer, "<img border=\"1\" src=\"internal-contact-photo:\">");
-	} 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))
-		g_string_append (buffer, "<img src=\"evo-icon:" CONTACT_LIST_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 *listId = e_destination_get_contact_uid (destination), *textrep;
-	gchar *name = NULL, *email_addr = NULL;
-
-	if (listId)
-		list_collapsed = GPOINTER_TO_INT (g_hash_table_lookup (display->priv->closed_lists, listId));
-
-	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\"><a href=\"##%s##\"><img src=\"%s/%s.png\"></a></td><td width=\"100%%\">%s",
-			e_destination_get_contact_uid (destination),
-			evolution_imagesdir,
-			(list_collapsed ? "plus" : "minus"),
-			name ? name : email_addr);
-
-		if (!list_collapsed) {
-			const GList *dest, *dests;
-			g_string_append (buffer, "<br><table cellspacing=\"1\">");
-
-			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_vertical (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><td valign=\"top\"><font color=" HEADER_COLOR ">%s</font></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_list_horizontal (GString *buffer,
-                                EContact *contact,
-                                EABContactDisplay *display)
-{
-	EDestination *destination;
-	const GList *dest, *dests;
+	GByteArray *ba;
 
-	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><td colspan=\"2\" valign=\"top\"><font color=" HEADER_COLOR ">%s</font></td></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_list (GString *buffer,
-                     EContact *contact,
-                     EABContactDisplay *display)
-
-{
-	if (display->priv->orientation == GTK_ORIENTATION_VERTICAL)
-		render_contact_list_vertical (buffer, contact, display);
-	else
-		render_contact_list_horizontal (buffer, contact, display);
-}
-
-static void
-render_contact_block (GString *buffer,
-                      EContact *contact)
-{
-	GString *accum;
-	GList *email_list, *l, *email_attr_list, *al;
-	gint email_num = 0;
-	const gchar *nl;
-	gchar *nick = NULL;
-
-	accum = g_string_new ("");
-	nl = "";
-
-	start_block (buffer, "");
-
-	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 (accum, "%s%s%s<a href=\"internal-mailto:%d\";>%s</a>%s <font color=" HEADER_COLOR ">(%s)</font>",
-						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);
-
-	if (accum->len) {
-
-		if (TEXT_IS_RIGHT_TO_LEFT) {
-			g_string_append_printf (
-				buffer, "<tr>"
-				"<td valign=\"top\" align=\"right\">%s</td> "
-				"<td valign=\"top\" align=\"right\" width=\"100\" nowrap>"
-				"<font color=" HEADER_COLOR ">%s:</font>"
-				"</td><td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\">"
-				"</td></tr>", accum->str, _("Email"));
-		} else {
-			g_string_append (
-				buffer, "<tr><td valign=\"top\" width=\"" IMAGE_COL_WIDTH "\">");
-			g_string_append_printf (
-				buffer, "</td><td valign=\"top\" width=\"100\" nowrap>"
-				"<font color=" HEADER_COLOR ">%s:</font></td> "
-				"<td valign=\"top\" nowrap>%s</td></tr>",
-				_("Email"), accum->str);
-		}
-	}
-
-	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)
-			g_string_append_printf (
-				buffer, "%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)
-		g_string_append_printf (buffer, "%s", accum->str);
+	stream = g_simple_async_result_get_op_res_gpointer (result);
+	ba = camel_stream_mem_get_byte_array (stream);
 
-	end_block (buffer);
-
-	g_string_free (accum, TRUE);
-	g_free (nick);
-
-}
-
-static void
-render_work_block (GString *buffer,
-                   EContact *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 (accum->len > 0) {
-		start_block (buffer, _("Work"));
-		g_string_append_printf (buffer, "%s", accum->str);
-		end_block (buffer);
-	}
-
-	g_string_free (accum, TRUE);
-}
-
-static void
-render_personal_block (GString *buffer,
-                       EContact *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 (accum->len > 0) {
-		start_block (buffer, _("Personal"));
-		g_string_append_printf (buffer, "%s", accum->str);
-		end_block (buffer);
-	}
-
-	g_string_free (accum, TRUE);
-}
-
-static void
-render_note_block (GString *buffer,
-                   EContact *contact)
-{
-	const gchar *str;
-	gchar *html;
-
-	str = e_contact_get_const (contact, E_CONTACT_NOTE);
-	if (!str || !*str)
-		return;
-
-	html = e_text_to_html (str,  E_TEXT_TO_HTML_CONVERT_ADDRESSES | E_TEXT_TO_HTML_CONVERT_URLS | E_TEXT_TO_HTML_CONVERT_NL);
-
-	start_block (buffer, _("Note"));
-	g_string_append_printf (buffer, "<tr><td>%s</td></tr>", html);
-	end_block (buffer);
+	html = g_strndup ((gchar *) ba->data, ba->len);
+	e_web_view_load_string (E_WEB_VIEW (display), html);
 
 	g_free (html);
+	g_object_unref (stream);
 }
 
 static void
-render_address_map (GString *buffer,
-                    EContact *contact,
-                    gint map_type)
-{
-#ifdef WITH_CONTACT_MAPS
-	if (map_type == E_CONTACT_ADDRESS_WORK) {
-		g_string_append (buffer, "<object classid=\"address-map-work\"></object>");
-	 } else {
- 		g_string_append (buffer, "<object classid=\"address-map-home\"></object>");
-	 }
-#endif
-}
-
-static void
-render_contact_horizontal (GString *buffer,
-                           EContact *contact,
-                           gboolean show_maps)
-{
-	g_string_append (buffer, "<table border=\"0\">");
-	render_title_block (buffer, contact);
-	g_string_append (buffer, "</table>");
-
-	g_string_append (buffer, "<table border=\"0\">");
-	render_contact_block (buffer, contact);
-	render_work_block (buffer, contact);
-	g_string_append (buffer, "<tr><td></td><td colspan=\"2\">");
-	if (show_maps)
-		render_address_map (buffer, contact, E_CONTACT_ADDRESS_WORK);
-	g_string_append (buffer, "<br></td></tr>");
-	render_personal_block (buffer, contact);
-	g_string_append (buffer, "<tr><td></td><td colspan=\"2\">");
-	if (show_maps)
-		render_address_map (buffer, contact, E_CONTACT_ADDRESS_HOME);
-	g_string_append (buffer, "<br></td></tr>");
-	g_string_append (buffer, "</table>");
-
-	g_string_append (buffer, "<table border=\"0\">");
-	render_note_block (buffer, contact);
-	g_string_append (buffer, "</table>");
-}
-
-static void
-render_contact_vertical (GString *buffer,
-                         EContact *contact,
-                         gboolean show_maps)
-{
-	/* First row: photo & name */
-	g_string_append (buffer, "<tr><td colspan=\"3\">");
-	render_title_block (buffer, contact);
-	g_string_append (buffer, "</td></tr>");
-
-	/* Second row: addresses etc. */
-	g_string_append (buffer, "<tr>");
-
-	/* First column: email, IM */
-	g_string_append (buffer, "<td valign=\"top\">");
-	g_string_append (buffer, "<table border=\"0\">");
-	render_contact_block (buffer, contact);
-	g_string_append (buffer, "</table></td>");
-
-	/* Second column: Work */
-	g_string_append (buffer, "<td width=\"30\"></td><td valign=\"top\"><table border=\"0\">");
-	render_work_block (buffer, contact);
-	g_string_append (buffer, "</table>");
-	if (show_maps)
-		render_address_map (buffer, contact, E_CONTACT_ADDRESS_WORK);
-	g_string_append (buffer, "</td>");
-
-	/* Third column: Personal */
-	g_string_append (buffer, "<td width=\"30\"></td><td valign=\"top\"><table border=\"0\">");
-	render_personal_block (buffer, contact);
-	g_string_append (buffer, "</table>");
-	if (show_maps)
-		render_address_map (buffer, contact, E_CONTACT_ADDRESS_HOME);
-	g_string_append (buffer, "</td>");
-
-	/* Third row: note */
-	g_string_append (buffer, "<tr><td colspan=\"3\"><table border=\"0\"");
-	render_note_block (buffer, contact);
-	g_string_append (buffer, "</table></td></tr>");
-
-	g_string_append (buffer, "</table>\n");
-}
-
-static void
-render_contact (GString *buffer,
-                EContact *contact,
-                GtkOrientation orientation,
-                gboolean show_maps)
-{
-	if (orientation == GTK_ORIENTATION_VERTICAL)
-		render_contact_vertical (buffer, contact, show_maps);
-	else
-		render_contact_horizontal (buffer, contact, show_maps);
-}
-
-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_printf (
-		buffer, "<body><table><tr>"
-		"<td %s>\n", TEXT_IS_RIGHT_TO_LEFT ? "align=\"right\"" : "");
-
-	if (contact) {
-		GtkOrientation orientation;
-		orientation = display->priv->orientation;
-
-		if (e_contact_get (contact, E_CONTACT_IS_LIST))
-			render_contact_list (buffer, contact, display);
-		else
-			render_contact (buffer, contact, orientation, display->priv->show_maps);
-
-	}
-
-	g_string_append (buffer, "</td></tr></table></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)
+load_contact (EABContactDisplay *display)
 {
-	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
-				g_string_append_printf (
-					buffer,
-					"<img width=\"%d\" height=\"%d\" src=\"internal-contact-photo:\">",
-					calced_width, calced_height);
-
-			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);
+	if (!display->priv->contact)
+		return;
 
-	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
@@ -1116,12 +218,6 @@ contact_display_set_property (GObject *object,
 				g_value_get_int (value));
 			return;
 
-		case PROP_ORIENTATION:
-			eab_contact_display_set_orientation (
-				EAB_CONTACT_DISPLAY (object),
-				g_value_get_int (value));
-			return;
-
 		case PROP_SHOW_MAPS:
 			eab_contact_display_set_show_maps (
 				EAB_CONTACT_DISPLAY (object),
@@ -1151,12 +247,6 @@ contact_display_get_property (GObject *object,
 				EAB_CONTACT_DISPLAY (object)));
 			return;
 
-		case PROP_ORIENTATION:
-			g_value_set_int (
-				value, eab_contact_display_get_orientation (
-				EAB_CONTACT_DISPLAY (object)));
-			return;
-
 		case PROP_SHOW_MAPS:
 			g_value_set_boolean (
 				value, eab_contact_display_get_show_maps (
@@ -1179,85 +269,11 @@ contact_display_dispose (GObject *object)
 		priv->contact = NULL;
 	}
 
-	if (priv->closed_lists != NULL) {
-		g_hash_table_unref (priv->closed_lists);
-		priv->closed_lists = NULL;
-	}
-
 	/* Chain up to parent's dispose() method. */
 	G_OBJECT_CLASS (parent_class)->dispose (object);
 }
 
 static void
-contact_display_url_requested (GtkHTML *html,
-                               const gchar *uri,
-                               GtkHTMLStream *handle)
-{
-	EABContactDisplay *display;
-	GtkHTMLClass *class;
-	gsize length;
-
-	display = EAB_CONTACT_DISPLAY (html);
-	class = GTK_HTML_CLASS (parent_class);
-
-	/* internal-contact-photo: */
-	if (strcmp (uri, "internal-contact-photo:") == 0) {
-		EContactPhoto *photo;
-		EContact *contact;
-
-		contact = eab_contact_display_get_contact (display);
-		photo = e_contact_get (contact, E_CONTACT_PHOTO);
-		if (photo == NULL)
-			photo = e_contact_get (contact, E_CONTACT_LOGO);
-
-		if (photo->type == E_CONTACT_PHOTO_TYPE_INLINED)
-			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);
-
-		return;
-	}
-
-	/* evo-icon:<<themed-icon-name>> */
-	length = strlen ("evo-icon:");
-	if (g_ascii_strncasecmp (uri, "evo-icon:", length) == 0) {
-		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, uri + length, GTK_ICON_SIZE_MENU, 0);
-		g_return_if_fail (icon_info != 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);
-		}
-
-		/* Chain up with the URI for the icon file. */
-		class->url_requested (html, icon_uri, handle);
-
-		gtk_icon_info_free (icon_info);
-		g_free (icon_uri);
-
-		return;
-	}
-
-	/* Chain up to parent's uri_requested() method. */
-	class->url_requested (html, uri, handle);
-}
-
-static void
 contact_display_hovering_over_link (EWebView *web_view,
                                     const gchar *title,
                                     const gchar *uri)
@@ -1310,19 +326,6 @@ contact_display_link_clicked (EWebView *web_view,
 		index = atoi (uri + length);
 		contact_display_emit_send_message (display, index);
 		return;
-	} else if (g_str_has_prefix (uri, "##") && g_str_has_suffix (uri, "##")) {
-		gchar *list_id = g_strndup (uri + 2, strlen (uri) - 4);
-
-		if (g_hash_table_lookup (display->priv->closed_lists, list_id)) {
-			g_hash_table_remove (display->priv->closed_lists, list_id);
-			g_free (list_id);
-		} else {
-			g_hash_table_insert (display->priv->closed_lists, list_id, GINT_TO_POINTER (TRUE));
-		}
-
-		eab_contact_display_render_normal (display, display->priv->contact);
-
-		return;
 	}
 
 	/* Chain up to parent's link_clicked() method. */
@@ -1341,9 +344,11 @@ handle_map_scroll_event (GtkWidget *widget,
 	return TRUE;
 }
 
-static void
-contact_display_object_requested (GtkHTML *html,
-                                  GtkHTMLEmbedded *eb,
+static GtkWidget *
+contact_display_object_requested (WebKitWebView *web_view,
+                                  gchar *mime_type,
+                                  gchar *uri,
+                                  GHashTable *param,
                                   EABContactDisplay *display)
 {
 	EContact *contact = display->priv->contact;
@@ -1351,18 +356,18 @@ contact_display_object_requested (GtkHTML *html,
 	const gchar *contact_uid = e_contact_get_const (contact, E_CONTACT_UID);
 	gchar *full_name;
 	EContactAddress *address;
+	GtkWidget *map = NULL;
 
-	if (g_ascii_strcasecmp (eb->classid, "address-map-work") == 0) {
+	if (strstr (mime_type, "work") != NULL) {
 		address = e_contact_get (contact, E_CONTACT_ADDRESS_WORK);
 		full_name = g_strconcat (name, " (", _("Work"), ")", NULL);
-	} else {
+	} else if (strstr (mime_type, "home") != NULL) {
 		address = e_contact_get (contact, E_CONTACT_ADDRESS_HOME);
 		full_name = g_strconcat (name, " (", _("Home"), ")", NULL);
 	}
 
 	if (address) {
-		GtkWidget *map = e_contact_map_new ();
-		gtk_container_add (GTK_CONTAINER (eb), map);
+		map = e_contact_map_new ();
 		gtk_widget_set_size_request (map, 250, 250);
 		g_signal_connect (
 			E_CONTACT_MAP (map), "contact-added",
@@ -1378,10 +383,15 @@ contact_display_object_requested (GtkHTML *html,
 		e_contact_map_add_marker (
 			E_CONTACT_MAP (map), full_name,
 			contact_uid, address, NULL);
+
+		gtk_widget_show_all (map);
+
+		e_contact_address_free (address);
 	}
 
 	g_free (full_name);
-	e_contact_address_free (address);
+
+	return map;
 }
 #endif
 
@@ -1419,7 +429,6 @@ static void
 eab_contact_display_class_init (EABContactDisplayClass *class)
 {
 	GObjectClass *object_class;
-	GtkHTMLClass *html_class;
 	EWebViewClass *web_view_class;
 
 	parent_class = g_type_class_peek_parent (class);
@@ -1430,9 +439,6 @@ eab_contact_display_class_init (EABContactDisplayClass *class)
 	object_class->get_property = contact_display_get_property;
 	object_class->dispose = contact_display_dispose;
 
-	html_class = GTK_HTML_CLASS (class);
-	html_class->url_requested = contact_display_url_requested;
-
 	web_view_class = E_WEB_VIEW_CLASS (class);
 	web_view_class->hovering_over_link = contact_display_hovering_over_link;
 	web_view_class->link_clicked = contact_display_link_clicked;
@@ -1461,18 +467,6 @@ eab_contact_display_class_init (EABContactDisplayClass *class)
 			EAB_CONTACT_DISPLAY_RENDER_NORMAL,
 			G_PARAM_READWRITE));
 
-	g_object_class_install_property (
-		object_class,
-		PROP_ORIENTATION,
-		g_param_spec_int (
-			"orientation",
-			NULL,
-			NULL,
-			GTK_ORIENTATION_HORIZONTAL,
-			GTK_ORIENTATION_VERTICAL,
-			GTK_ORIENTATION_HORIZONTAL,
-			G_PARAM_READWRITE));
-
 	g_object_class_install_property	(
 		object_class,
 		PROP_SHOW_MAPS,
@@ -1504,18 +498,17 @@ 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->orientation = GTK_ORIENTATION_HORIZONTAL;
-	display->priv->show_maps = FALSE;
-	display->priv->closed_lists = g_hash_table_new_full (g_str_hash, g_str_equal,
-					(GDestroyNotify) g_free, NULL);
+
+	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, "object-requested",
+	g_signal_connect (web_view, "create-plugin-widget",
 		G_CALLBACK (contact_display_object_requested), display);
 #endif
 
@@ -1554,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");
 }
@@ -1584,65 +567,27 @@ 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;
-
-		case EAB_CONTACT_DISPLAY_RENDER_COMPACT:
-			eab_contact_display_render_compact (display, contact);
-			break;
-	}
-
-	g_object_notify (G_OBJECT (display), "mode");
-}
-
-GtkOrientation
-eab_contact_display_get_orientation (EABContactDisplay *display)
-{
-	g_return_val_if_fail (EAB_IS_CONTACT_DISPLAY (display), 0);
-
-	return display->priv->orientation;
-}
-
-void
-eab_contact_display_set_orientation (EABContactDisplay *display,
-                                     GtkOrientation orientation)
-{
-	EABContactDisplayMode mode;
-	EContact *contact;
-
-	g_return_if_fail (EAB_IS_CONTACT_DISPLAY (display));
-
-	display->priv->orientation = orientation;
-	contact = eab_contact_display_get_contact (display);
-	mode = eab_contact_display_get_mode (display);
+		return;
+	};
 
-	switch (mode) {
-		case EAB_CONTACT_DISPLAY_RENDER_NORMAL:
-			eab_contact_display_render_normal (display, contact);
-			break;
+	eab_contact_formatter_set_display_mode (
+		display->priv->formatter, mode);
 
-		case EAB_CONTACT_DISPLAY_RENDER_COMPACT:
-			eab_contact_display_render_compact (display, contact);
-			break;
-	}
+	load_contact (display);
 
-	g_object_notify (G_OBJECT (display), "orientation");
+	g_object_notify (G_OBJECT (display), "mode");
 }
 
 gboolean
@@ -1650,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);
-
-	switch (mode) {
-		case EAB_CONTACT_DISPLAY_RENDER_NORMAL:
-			eab_contact_display_render_normal (display, contact);
-			break;
+	if (eab_contact_formatter_get_render_maps (
+		display->priv->formatter) == show_maps) {
 
-		case EAB_CONTACT_DISPLAY_RENDER_COMPACT:
-			eab_contact_display_render_compact (display, contact);
-			break;
+		return;
 	}
 
+	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..c0ca4ed
--- /dev/null
+++ b/addressbook/gui/widgets/eab-contact-formatter.c
@@ -0,0 +1,1267 @@
+/*
+ * 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
diff --git a/addressbook/importers/Makefile.am b/addressbook/importers/Makefile.am
index 2c5f587..3f2f1db 100644
--- a/addressbook/importers/Makefile.am
+++ b/addressbook/importers/Makefile.am
@@ -10,7 +10,7 @@ libevolution_addressbook_importers_la_CPPFLAGS =	\
 	-I$(top_srcdir)/widgets				\
 	-I$(top_builddir)/addressbook			\
 	$(EVOLUTION_DATA_SERVER_CFLAGS)			\
-	$(GTKHTML_CFLAGS)
+	$(GNOME_PLATFORM_CFLAGS)
 
 libevolution_addressbook_importers_la_SOURCES = \
 	evolution-ldif-importer.c		\
@@ -25,6 +25,7 @@ libevolution_addressbook_importers_la_LIBADD = \
 	$(top_builddir)/addressbook/util/libeabutil.la			\
 	$(top_builddir)/widgets/misc/libemiscwidgets.la			\
 	$(EVOLUTION_DATA_SERVER_LIBS)					\
-	$(GTKHTML_LIBS)
+	$(GNOME_PLATFORM_LIBS)						\
+	$(IMPORTERS_LIBS)
 
 -include $(top_srcdir)/git.mk
diff --git a/calendar/gui/Makefile.am b/calendar/gui/Makefile.am
index f280d3a..7599180 100644
--- a/calendar/gui/Makefile.am
+++ b/calendar/gui/Makefile.am
@@ -66,6 +66,7 @@ libevolution_calendar_la_CPPFLAGS =			\
 	-DEVOLUTION_GALVIEWSDIR=\""$(viewsdir)"\"	\
 	-DEVOLUTION_LOCALEDIR=\""$(localedir)"\"	\
 	-DEVOLUTION_UIDIR=\""$(uidir)"\"		\
+	-DEVOLUTION_PRIVDATADIR=\""${privdatadir}"\"	\
 	-DPREFIX=\""$(prefix)"\"			\
 	$(EVOLUTION_DATA_SERVER_CFLAGS)			\
 	$(GNOME_PLATFORM_CFLAGS)			\
diff --git a/calendar/gui/e-cal-component-preview.c b/calendar/gui/e-cal-component-preview.c
index ce8cdee..c96a9e0 100644
--- a/calendar/gui/e-cal-component-preview.c
+++ b/calendar/gui/e-cal-component-preview.c
@@ -56,6 +56,14 @@ struct _ECalComponentPreviewPrivate {
 	gint comp_sequence;
 };
 
+#define HTML_HEADER "<!doctype html public \"-//W3C//DTD HTML 4.0 TRANSITIONAL//EN\">\n<html>\n"  \
+                    "<head>\n<meta name=\"generator\" content=\"Evolution Calendar Component\">\n" \
+		    "<link type=\"text/css\" rel=\"stylesheet\" href=\"file://" EVOLUTION_PRIVDATADIR "/theme/webview.css\">\n" \
+		    "<style>\n" \
+		    ".description { font-family: monospace; font-size: 1em; }\n" \
+		    "</style>\n" \
+		    "</head>"
+
 static void
 clear_comp_info (ECalComponentPreview *preview)
 {
@@ -191,20 +199,21 @@ cal_component_preview_write_html (GString *buffer,
 	/* write document header */
 	e_cal_component_get_summary (comp, &text);
 
+	g_string_append (buffer, HTML_HEADER);
+	g_string_append (buffer, "<body>");
+
 	if (text.value)
-		g_string_append_printf (
-			buffer, "<HTML><BODY><H1>%s</H1>",
-			text.value);
+		g_string_append_printf (buffer, "<h2>%s</h2>", text.value);
 	else
-		g_string_append_printf (
-			buffer, "<HTML><BODY><H1><I>%s</I></H1>",
-			_("Untitled"));
+		g_string_append_printf (buffer, "<h2><i>%s</i></h2>",_("Untitled"));
+
+	g_string_append (buffer, "<table border=\"0\" cellspacing=\"5\">");
 
 	/* write icons for the categories */
 	string = g_string_new (NULL);
 	e_cal_component_get_categories_list (comp, &list);
 	if (list != NULL)
-		g_string_append_printf (buffer, "<H3>%s ", _("Categories:"));
+		g_string_append_printf (buffer, "<tr><th>%s</th><td>", _("Categories:"));
 	for (iter = list; iter != NULL; iter = iter->next) {
 		const gchar *category = iter->data;
 		const gchar *icon_file;
@@ -215,7 +224,7 @@ cal_component_preview_write_html (GString *buffer,
 
 			uri = g_filename_to_uri (icon_file, NULL, NULL);
 			g_string_append_printf (
-				buffer, "<IMG ALT=\"%s\" SRC=\"%s\">",
+				buffer, "<img alt=\"%s\" src=\"%s\">",
 				category, uri);
 			g_free (uri);
 		} else {
@@ -227,22 +236,14 @@ cal_component_preview_write_html (GString *buffer,
 	if (string->len > 0)
 		g_string_append_printf (buffer, "%s", string->str);
 	if (list != NULL)
-		g_string_append (buffer, "</H3>");
+		g_string_append (buffer, "</td></tr>");
 	e_cal_component_free_categories_list (list);
 	g_string_free (string, TRUE);
 
-	/* Start table */
-	g_string_append (
-		buffer, "<TABLE BORDER=\"0\" WIDTH=\"80%%\">"
-		"<TR><TD VALIGN=\"TOP\" ALIGN=\"RIGHT\" WIDTH=\"15%%\">"
-		"</TD></TR>");
-
 	/* write location */
 	e_cal_component_get_location (comp, &location);
 	if (location)
-		g_string_append_printf (
-			buffer, "<TR><TD VALIGN=\"TOP\" ALIGN=\"RIGHT\" "
-			"WIDTH=\"15%%\"><B>%s</B></TD><TD>%s</TD></TR>",
+		g_string_append_printf (buffer, "<tr><th>%s</th><td>%s</td></tr>",
 			_("Summary:"), text.value);
 
 	/* write start date */
@@ -250,11 +251,8 @@ cal_component_preview_write_html (GString *buffer,
 	if (dt.value != NULL) {
 		str = timet_to_str_with_zone (
 			&dt, client, default_zone, use_24_hour_format);
-		g_string_append_printf (
-			buffer, "<TR><TD VALIGN=\"TOP\" ALIGN=\"RIGHT\">"
-			"<B>%s</B></TD><TD>%s</TD></TR>",
+		g_string_append_printf (buffer, "<tr><th>%s</th><td>%s</td></tr>",
 			_("Start Date:"), str);
-
 		g_free (str);
 	}
 	e_cal_component_free_datetime (&dt);
@@ -264,11 +262,8 @@ cal_component_preview_write_html (GString *buffer,
 	if (dt.value != NULL) {
 		str = timet_to_str_with_zone (
 			&dt, client, default_zone, use_24_hour_format);
-		g_string_append_printf (
-			buffer, "<TR><TD VALIGN=\"TOP\" ALIGN=\"RIGHT\">"
-			"<B>%s</B></TD><TD>%s</TD></TR>",
-			_("Start Date:"), str);
-
+		g_string_append_printf (buffer,"<tr><th>%s</th><td>%s</td></tr>",
+			_("End Date:"), str);
 		g_free (str);
 	}
 	e_cal_component_free_datetime (&dt);
@@ -278,11 +273,8 @@ cal_component_preview_write_html (GString *buffer,
 	if (dt.value != NULL) {
 		str = timet_to_str_with_zone (
 			&dt, client, default_zone, use_24_hour_format);
-		g_string_append_printf (
-			buffer, "<TR><TD VALIGN=\"TOP\" ALIGN=\"RIGHT\">"
-			"<B>%s</B></TD><TD>%s</TD></TR>",
+		g_string_append_printf (buffer, "<tr><th>%s</th><td>%s</td></tr>",
 			_("Due Date:"), str);
-
 		g_free (str);
 	}
 	e_cal_component_free_datetime (&dt);
@@ -292,9 +284,8 @@ cal_component_preview_write_html (GString *buffer,
 	icalprop = icalcomponent_get_first_property (
 		icalcomp, ICAL_STATUS_PROPERTY);
 	if (icalprop != NULL) {
-		g_string_append_printf (
-			buffer, "<TR><TD VALIGN=\"TOP\" ALIGN=\"RIGHT\">"
-			"<B>%s</B></TD>", _("Status:"));
+		g_string_append_printf (buffer, "<tr><th>%s</th>",
+			_("Status:"));
 		e_cal_component_get_status (comp, &status);
 		switch (status) {
 		case ICAL_STATUS_INPROCESS :
@@ -312,16 +303,15 @@ cal_component_preview_write_html (GString *buffer,
 			break;
 		}
 
-		g_string_append_printf (buffer, "<TD>%s</TD></TR>", str);
+		g_string_append_printf (buffer, "<td>%s</td></tr>", str);
 		g_free (str);
 	}
 
 	/* write priority */
 	e_cal_component_get_priority (comp, &priority_value);
 	if (priority_value && *priority_value != 0) {
-		g_string_append_printf (
-			buffer, "<TR><TD VALIGN=\"TOP\" ALIGN=\"RIGHT\">"
-			"<B>%s</B></TD>", _("Priority:"));
+		g_string_append_printf (buffer, "<tr><th>%s</th>",
+			_("Priority:"));
 		if (*priority_value <= 4)
 			str = g_strdup (_("High"));
 		else if (*priority_value == 5)
@@ -329,7 +319,7 @@ cal_component_preview_write_html (GString *buffer,
 		else
 			str = g_strdup (_("Low"));
 
-		g_string_append_printf (buffer, "<TD>%s</TD></TR>", str);
+		g_string_append_printf (buffer, "<td>%s</td></tr>", str);
 
 		g_free (str);
 	}
@@ -338,17 +328,16 @@ cal_component_preview_write_html (GString *buffer,
 		e_cal_component_free_priority (priority_value);
 
 	/* write description and URL */
-	g_string_append (buffer, "<TR><TD COLSPAN=\"2\"><HR></TD></TR>");
+	g_string_append (buffer, "<tr><td colspan=\"2\"><hr></td></tr>");
 
 	e_cal_component_get_description_list (comp, &list);
 	if (list) {
 		GSList *node;
 
-		g_string_append_printf (
-			buffer, "<TR><TD VALIGN=\"TOP\" ALIGN=\"RIGHT\">"
-			"<B>%s</B></TD>", _("Description:"));
+		g_string_append_printf (buffer, "<tr><th>%s</th>",
+			_("Description:"));
 
-		g_string_append (buffer, "<TD><TT>");
+		g_string_append (buffer, "<td class=\"description\">");
 
 		for (node = list; node != NULL; node = node->next) {
 			gchar *html;
@@ -367,7 +356,7 @@ cal_component_preview_write_html (GString *buffer,
 			g_free (html);
 		}
 
-		g_string_append (buffer, "</TT></TD></TR>");
+		g_string_append (buffer, "</td></tr>");
 
 		e_cal_component_free_text_list (list);
 	}
@@ -375,18 +364,14 @@ cal_component_preview_write_html (GString *buffer,
 	/* URL */
 	e_cal_component_get_url (comp, (const gchar **) &str);
 	if (str) {
-		g_string_append_printf (
-			buffer, "<TR><TD VALIGN=\"TOP\" ALIGN=\"RIGHT\">"
-			"<B>%s</B></TD>", _("Web Page:"));
-		g_string_append_printf (
-			buffer, "<TD><A HREF=\"%s\">%s</A></TD></TR>",
-			str, str);
+		g_string_append_printf (buffer, "<tr><th>%s</th><td><a href=\"%s\">%s</a></td></tr>",
+			_("Web Page:"), str, str);
 	}
 
-	g_string_append (buffer, "</TABLE>");
+	g_string_append (buffer, "</table>");
 
 	/* close document */
-	g_string_append (buffer, "</BODY></HTML>");
+	g_string_append (buffer, "</body></html>");
 }
 
 static void
diff --git a/composer/e-composer-actions.c b/composer/e-composer-actions.c
index 11ad9cd..966866b 100644
--- a/composer/e-composer-actions.c
+++ b/composer/e-composer-actions.c
@@ -462,7 +462,7 @@ e_composer_actions_init (EMsgComposer *composer)
 	GtkActionGroup *action_group;
 	GtkUIManager *ui_manager;
 	GtkhtmlEditor *editor;
-	EWebView *web_view;
+	EWebViewGtkHTML *web_view;
 	gboolean visible;
 
 	g_return_if_fail (E_IS_MSG_COMPOSER (composer));
diff --git a/composer/e-composer-activity.c b/composer/e-composer-activity.c
index 603a271..a74e5cd 100644
--- a/composer/e-composer-activity.c
+++ b/composer/e-composer-activity.c
@@ -46,14 +46,14 @@ composer_activity_lock_interface (EComposerActivity *activity)
 {
 	GtkActionGroup *action_group;
 	EMsgComposer *composer;
-	EWebView *web_view;
+	EWebViewGtkHTML *web_view;
 	gboolean editable;
 
 	composer = e_composer_activity_get_composer (activity);
 
 	web_view = e_msg_composer_get_web_view (composer);
-	editable = e_web_view_get_editable (web_view);
-	e_web_view_set_editable (web_view, FALSE);
+	editable = e_web_view_gtkhtml_get_editable (web_view);
+	e_web_view_gtkhtml_set_editable (web_view, FALSE);
 	activity->priv->saved_editable = editable;
 
 	action_group = composer->priv->async_actions;
@@ -65,14 +65,14 @@ composer_activity_unlock_interface (EComposerActivity *activity)
 {
 	GtkActionGroup *action_group;
 	EMsgComposer *composer;
-	EWebView *web_view;
+	EWebViewGtkHTML *web_view;
 	gboolean editable;
 
 	composer = e_composer_activity_get_composer (activity);
 
 	editable = activity->priv->saved_editable;
 	web_view = e_msg_composer_get_web_view (composer);
-	e_web_view_set_editable (web_view, editable);
+	e_web_view_gtkhtml_set_editable (web_view, editable);
 
 	action_group = composer->priv->async_actions;
 	gtk_action_group_set_sensitive (action_group, TRUE);
diff --git a/composer/e-composer-private.c b/composer/e-composer-private.c
index 3441c6b..477aae4 100644
--- a/composer/e-composer-private.c
+++ b/composer/e-composer-private.c
@@ -129,7 +129,7 @@ e_composer_private_constructed (EMsgComposer *composer)
 	EFocusTracker *focus_tracker;
 	EShell *shell;
 	EShellSettings *shell_settings;
-	EWebView *web_view;
+	EWebViewGtkHTML *web_view;
 	GtkhtmlEditor *editor;
 	GtkUIManager *ui_manager;
 	GtkAction *action;
diff --git a/composer/e-composer-private.h b/composer/e-composer-private.h
index a727cf6..990c5b6 100644
--- a/composer/e-composer-private.h
+++ b/composer/e-composer-private.h
@@ -51,7 +51,7 @@
 #include "widgets/misc/e-picture-gallery.h"
 #include "widgets/misc/e-preferences-window.h"
 #include "widgets/misc/e-signature-combo-box.h"
-#include "widgets/misc/e-web-view.h"
+#include "widgets/misc/e-web-view-gtkhtml.h"
 #include "shell/e-shell.h"
 
 #ifdef HAVE_XFREE
diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c
index 8da9912..2555329 100644
--- a/composer/e-msg-composer.c
+++ b/composer/e-msg-composer.c
@@ -193,19 +193,20 @@ emcu_part_to_html (CamelMimePart *part,
 	camel_stream_mem_set_byte_array (mem, buf);
 
 	emfq = em_format_quote_new (NULL, (CamelStream *) mem, EM_FORMAT_QUOTE_KEEP_SIG);
-	((EMFormat *) emfq)->composer = TRUE;
+	em_format_set_composer ((EMFormat *) emfq, TRUE);
 	if (source) {
 		/* Copy over things we can, other things are internal.
 		 * XXX Perhaps need different api than 'clone'. */
-		if (source->default_charset)
+		if (em_format_get_default_charset (source))
 			em_format_set_default_charset (
-				(EMFormat *) emfq, source->default_charset);
-		if (source->charset)
-			em_format_set_default_charset (
-				(EMFormat *) emfq, source->charset);
+				(EMFormat *) emfq, em_format_get_default_charset (source));
+		if (em_format_get_charset (source))
+			em_format_set_charset (
+				(EMFormat *) emfq, em_format_get_charset (source));
 	}
-	em_format_part (
-		EM_FORMAT (emfq), CAMEL_STREAM (mem), part, cancellable);
+
+	em_format_format_text (EM_FORMAT (emfq),
+			CAMEL_STREAM (mem), CAMEL_DATA_WRAPPER (part), cancellable);
 	g_object_unref (emfq);
 
 	camel_stream_write((CamelStream *) mem, "", 1, cancellable, NULL);
@@ -1691,7 +1692,7 @@ msg_composer_paste_clipboard_targets_cb (GtkClipboard *clipboard,
 }
 
 static void
-msg_composer_paste_clipboard_cb (EWebView *web_view,
+msg_composer_paste_clipboard_cb (EWebViewGtkHTML *web_view,
                                  EMsgComposer *composer)
 {
 	GtkClipboard *clipboard;
@@ -1721,7 +1722,7 @@ msg_composer_realize_gtkhtml_cb (GtkWidget *widget,
 
 	/* When redirecting a message, the message body is not
 	 * editable and therefore cannot be a drag destination. */
-	if (!e_web_view_get_editable (E_WEB_VIEW (widget)))
+	if (!e_web_view_gtkhtml_get_editable (E_WEB_VIEW_GTKHTML (widget)))
 		return;
 
 	view = e_msg_composer_get_attachment_view (composer);
@@ -1969,7 +1970,7 @@ msg_composer_constructed (GObject *object)
 	EAttachmentView *view;
 	EAttachmentStore *store;
 	EComposerHeaderTable *table;
-	EWebView *web_view;
+	EWebViewGtkHTML *web_view;
 	GtkUIManager *ui_manager;
 	GtkToggleAction *action;
 	const gchar *id;
@@ -2179,7 +2180,7 @@ msg_composer_key_press_event (GtkWidget *widget,
 	EMsgComposer *composer = E_MSG_COMPOSER (widget);
 	GtkWidget *input_widget;
 	GtkhtmlEditor *editor;
-	EWebView *web_view;
+	EWebViewGtkHTML *web_view;
 
 	editor = GTKHTML_EDITOR (widget);
 	composer = E_MSG_COMPOSER (widget);
@@ -2558,7 +2559,7 @@ e_msg_composer_new (EShell *shell)
 
 	return g_object_new (
 		E_TYPE_MSG_COMPOSER,
-		"html", e_web_view_new (), "shell", shell, NULL);
+		"html", e_web_view_gtkhtml_new (), "shell", shell, NULL);
 }
 
 EFocusTracker *
@@ -3389,7 +3390,7 @@ e_msg_composer_new_redirect (EShell *shell,
 {
 	EMsgComposer *composer;
 	EComposerHeaderTable *table;
-	EWebView *web_view;
+	EWebViewGtkHTML *web_view;
 	const gchar *subject;
 
 	g_return_val_if_fail (E_IS_SHELL (shell), NULL);
@@ -3408,7 +3409,7 @@ e_msg_composer_new_redirect (EShell *shell,
 	e_composer_header_table_set_subject (table, subject);
 
 	web_view = e_msg_composer_get_web_view (composer);
-	e_web_view_set_editable (web_view, FALSE);
+	e_web_view_gtkhtml_set_editable (web_view, FALSE);
 
 	return composer;
 }
@@ -3464,7 +3465,7 @@ e_msg_composer_get_shell (EMsgComposer *composer)
  *
  * Returns: the #EWebView
  **/
-EWebView *
+EWebViewGtkHTML *
 e_msg_composer_get_web_view (EMsgComposer *composer)
 {
 	GtkHTML *html;
@@ -3477,7 +3478,7 @@ e_msg_composer_get_web_view (EMsgComposer *composer)
 	editor = GTKHTML_EDITOR (composer);
 	html = gtkhtml_editor_get_html (editor);
 
-	return E_WEB_VIEW (html);
+	return E_WEB_VIEW_GTKHTML (html);
 }
 
 static void
@@ -4152,7 +4153,7 @@ e_msg_composer_set_body (EMsgComposer *composer,
 {
 	EMsgComposerPrivate *p = composer->priv;
 	EComposerHeaderTable *table;
-	EWebView *web_view;
+	EWebViewGtkHTML *web_view;
 	gchar *buff;
 
 	g_return_if_fail (E_IS_MSG_COMPOSER (composer));
@@ -4168,7 +4169,7 @@ e_msg_composer_set_body (EMsgComposer *composer,
 	gtkhtml_editor_set_html_mode (GTKHTML_EDITOR (composer), FALSE);
 
 	web_view = e_msg_composer_get_web_view (composer);
-	e_web_view_set_editable (web_view, FALSE);
+	e_web_view_gtkhtml_set_editable (web_view, FALSE);
 
 	g_free (p->mime_body);
 	p->mime_body = g_strdup (body);
diff --git a/composer/e-msg-composer.h b/composer/e-msg-composer.h
index 258d260..aa63b0e 100644
--- a/composer/e-msg-composer.h
+++ b/composer/e-msg-composer.h
@@ -30,7 +30,7 @@
 #include <gtkhtml-editor.h>
 #include <misc/e-attachment-view.h>
 #include <misc/e-focus-tracker.h>
-#include <misc/e-web-view.h>
+#include <misc/e-web-view-gtkhtml.h>
 #include <shell/e-shell.h>
 
 #include <composer/e-composer-header-table.h>
@@ -100,7 +100,8 @@ EFocusTracker *	e_msg_composer_get_focus_tracker
 						(EMsgComposer *composer);
 CamelSession *	e_msg_composer_get_session	(EMsgComposer *composer);
 EShell *	e_msg_composer_get_shell	(EMsgComposer *composer);
-EWebView *	e_msg_composer_get_web_view	(EMsgComposer *composer);
+EWebViewGtkHTML *
+		e_msg_composer_get_web_view	(EMsgComposer *composer);
 
 void		e_msg_composer_send		(EMsgComposer *composer);
 void		e_msg_composer_save_to_drafts	(EMsgComposer *composer);
diff --git a/e-util/e-marshal.list b/e-util/e-marshal.list
index bf15633..62be8aa 100644
--- a/e-util/e-marshal.list
+++ b/e-util/e-marshal.list
@@ -39,6 +39,7 @@ NONE:INT,POINTER,INT,OBJECT,INT,INT,BOXED,UINT,UINT
 NONE:INT,POINTER,INT,OBJECT,UINT
 NONE:LONG,LONG
 NONE:OBJECT,BOOLEAN
+NONE:OBJECT,INT
 NONE:OBJECT,DOUBLE,DOUBLE,BOOLEAN
 NONE:OBJECT,OBJECT
 NONE:OBJECT,STRING



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