aboutsummaryrefslogtreecommitdiffstats
path: root/mail/e-mail-display.c
diff options
context:
space:
mode:
authorDan Vrátil <dvratil@redhat.com>2012-03-29 00:38:11 +0800
committerDan Vrátil <dvratil@redhat.com>2012-03-29 00:38:25 +0800
commit6d2c382788a4042d53f49a080acd11b499aa52f6 (patch)
tree3834f0836340918ba17594a603ba61c13b9929a0 /mail/e-mail-display.c
parent6bd1c6833a2c51898ac45865767dd01ba66a95c5 (diff)
downloadgsoc2013-evolution-6d2c382788a4042d53f49a080acd11b499aa52f6.tar
gsoc2013-evolution-6d2c382788a4042d53f49a080acd11b499aa52f6.tar.gz
gsoc2013-evolution-6d2c382788a4042d53f49a080acd11b499aa52f6.tar.bz2
gsoc2013-evolution-6d2c382788a4042d53f49a080acd11b499aa52f6.tar.lz
gsoc2013-evolution-6d2c382788a4042d53f49a080acd11b499aa52f6.tar.xz
gsoc2013-evolution-6d2c382788a4042d53f49a080acd11b499aa52f6.tar.zst
gsoc2013-evolution-6d2c382788a4042d53f49a080acd11b499aa52f6.zip
WebKit port - port formatter and mail module
Diffstat (limited to 'mail/e-mail-display.c')
-rw-r--r--mail/e-mail-display.c1430
1 files changed, 1298 insertions, 132 deletions
diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c
index 7461e595f3..07f45ad461 100644
--- a/mail/e-mail-display.c
+++ b/mail/e-mail-display.c
@@ -23,14 +23,33 @@
#include <config.h>
#endif
+#define LIBSOUP_USE_UNSTABLE_REQUEST_API
+
#include "e-mail-display.h"
#include <glib/gi18n.h>
+#include <gdk/gdk.h>
+#include "e-util/e-marshal.h"
#include "e-util/e-util.h"
#include "e-util/e-plugin-ui.h"
#include "mail/em-composer-utils.h"
#include "mail/em-utils.h"
+#include "mail/e-mail-request.h"
+#include "mail/em-format-html-display.h"
+#include "mail/e-mail-attachment-bar.h"
+#include "widgets/misc/e-attachment-button.h"
+
+#include <camel/camel.h>
+
+#include <libsoup/soup.h>
+#include <libsoup/soup-requester.h>
+
+#include <JavaScriptCore/JavaScript.h>
+
+#define d(x)
+
+G_DEFINE_TYPE (EMailDisplay, e_mail_display, E_TYPE_WEB_VIEW)
#define E_MAIL_DISPLAY_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
@@ -38,13 +57,29 @@
struct _EMailDisplayPrivate {
EMFormatHTML *formatter;
+
+ EMFormatWriteMode mode;
+ gboolean headers_collapsable;
+ gboolean headers_collapsed;
+
+ GtkActionGroup *mailto_actions;
+ GtkActionGroup *images_actions;
+
+ gint force_image_load: 1;
};
enum {
PROP_0,
- PROP_FORMATTER
+ PROP_FORMATTER,
+ PROP_MODE,
+ PROP_HEADERS_COLLAPSABLE,
+ PROP_HEADERS_COLLAPSED,
};
+static gpointer parent_class;
+
+static CamelDataCache *emd_global_http_cache = 0;
+
static const gchar *ui =
"<ui>"
" <popup name='context'>"
@@ -61,6 +96,15 @@ static const gchar *ui =
" </popup>"
"</ui>";
+static const gchar *image_ui =
+"<ui>"
+" <popup name='context'>"
+" <placeholder name='custom-actions-2'>"
+" <menuitem action='image-save'/>"
+" </placeholder>"
+" </popup>"
+"</ui>";
+
static GtkActionEntry mailto_entries[] = {
{ "add-to-address-book",
@@ -88,7 +132,7 @@ static GtkActionEntry mailto_entries[] = {
NULL,
N_("Send _Reply To..."),
NULL,
- N_("Send a reply message to this address"),
+ N_("Send a reply message to this address"),
NULL /* Handled by EMailReader */ },
/*** Menus ***/
@@ -101,7 +145,54 @@ static GtkActionEntry mailto_entries[] = {
NULL }
};
-G_DEFINE_TYPE (EMailDisplay, e_mail_display, E_TYPE_WEB_VIEW)
+static GtkActionEntry image_entries[] = {
+
+ { "image-save",
+ GTK_STOCK_SAVE,
+ N_("Save _Image..."),
+ NULL,
+ N_("Save the image to a file"),
+ NULL /* Handled by EMailReader */ },
+
+};
+
+static void
+mail_display_webview_update_actions (EWebView *web_view,
+ gpointer user_data)
+{
+ const gchar *image_src;
+ gboolean visible;
+ GtkAction *action;
+
+ g_return_if_fail (web_view != NULL);
+
+ image_src = e_web_view_get_cursor_image_src (web_view);
+ visible = image_src && g_str_has_prefix (image_src, "cid:");
+ if (!visible && image_src) {
+ CamelStream *image_stream;
+
+ image_stream = camel_data_cache_get (emd_global_http_cache, "http", image_src, NULL);
+
+ visible = image_stream != NULL;
+
+ if (image_stream)
+ g_object_unref (image_stream);
+ }
+
+ action = e_web_view_get_action (web_view, "image-save");
+ if (action)
+ gtk_action_set_visible (action, visible);
+}
+
+static void
+formatter_image_loading_policy_changed_cb (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ EMailDisplay *display = user_data;
+
+ e_mail_display_load_images (display);
+}
static void
mail_display_update_formatter_colors (EMailDisplay *display)
@@ -115,6 +206,9 @@ mail_display_update_formatter_colors (EMailDisplay *display)
state = gtk_widget_get_state (GTK_WIDGET (display));
formatter = display->priv->formatter;
+ if (!display->priv->formatter)
+ return;
+
style = gtk_widget_get_style (GTK_WIDGET (display));
if (style == NULL)
return;
@@ -156,6 +250,21 @@ mail_display_set_property (GObject *object,
E_MAIL_DISPLAY (object),
g_value_get_object (value));
return;
+ case PROP_MODE:
+ e_mail_display_set_mode (
+ E_MAIL_DISPLAY (object),
+ g_value_get_int (value));
+ return;
+ case PROP_HEADERS_COLLAPSABLE:
+ e_mail_display_set_headers_collapsable (
+ E_MAIL_DISPLAY (object),
+ g_value_get_boolean (value));
+ return;
+ case PROP_HEADERS_COLLAPSED:
+ e_mail_display_set_headers_collapsed (
+ E_MAIL_DISPLAY (object),
+ g_value_get_boolean (value));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -173,6 +282,21 @@ mail_display_get_property (GObject *object,
value, e_mail_display_get_formatter (
E_MAIL_DISPLAY (object)));
return;
+ case PROP_MODE:
+ g_value_set_int (
+ value, e_mail_display_get_mode (
+ E_MAIL_DISPLAY (object)));
+ return;
+ case PROP_HEADERS_COLLAPSABLE:
+ g_value_set_boolean (
+ value, e_mail_display_get_headers_collapsable (
+ E_MAIL_DISPLAY (object)));
+ return;
+ case PROP_HEADERS_COLLAPSED:
+ g_value_set_boolean (
+ value, e_mail_display_get_headers_collapsed (
+ E_MAIL_DISPLAY (object)));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -191,14 +315,14 @@ mail_display_dispose (GObject *object)
}
/* Chain up to parent's dispose() method. */
- G_OBJECT_CLASS (e_mail_display_parent_class)->dispose (object);
+ G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
mail_display_realize (GtkWidget *widget)
{
/* Chain up to parent's realize() method. */
- GTK_WIDGET_CLASS (e_mail_display_parent_class)->realize (widget);
+ GTK_WIDGET_CLASS (parent_class)->realize (widget);
mail_display_update_formatter_colors (E_MAIL_DISPLAY (widget));
}
@@ -207,62 +331,28 @@ static void
mail_display_style_set (GtkWidget *widget,
GtkStyle *previous_style)
{
- EMailDisplayPrivate *priv;
+ EMailDisplay *display = E_MAIL_DISPLAY (widget);
- priv = E_MAIL_DISPLAY_GET_PRIVATE (widget);
+ mail_display_update_formatter_colors (display);
/* Chain up to parent's style_set() method. */
- GTK_WIDGET_CLASS (e_mail_display_parent_class)->
- style_set (widget, previous_style);
-
- mail_display_update_formatter_colors (E_MAIL_DISPLAY (widget));
- em_format_queue_redraw (EM_FORMAT (priv->formatter));
-}
-
-static void
-mail_display_load_string (EWebView *web_view,
- const gchar *string)
-{
- EMailDisplayPrivate *priv;
-
- priv = E_MAIL_DISPLAY_GET_PRIVATE (web_view);
- g_return_if_fail (priv->formatter != NULL);
-
- if (em_format_busy (EM_FORMAT (priv->formatter)))
- return;
-
- /* Chain up to parent's load_string() method. */
- E_WEB_VIEW_CLASS (e_mail_display_parent_class)->
- load_string (web_view, string);
-}
-
-static void
-mail_display_url_requested (GtkHTML *html,
- const gchar *uri,
- GtkHTMLStream *stream)
-{
- /* XXX Sadly, we must block the default method
- * until EMFormatHTML is made asynchronous. */
+ GTK_WIDGET_CLASS (parent_class)->style_set (widget, previous_style);
}
static gboolean
mail_display_process_mailto (EWebView *web_view,
- const gchar *mailto_uri)
+ const gchar *mailto_uri,
+ gpointer user_data)
{
- g_return_val_if_fail (web_view != NULL, FALSE);
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
g_return_val_if_fail (mailto_uri != NULL, FALSE);
- g_return_val_if_fail (E_IS_MAIL_DISPLAY (web_view), FALSE);
if (g_ascii_strncasecmp (mailto_uri, "mailto:", 7) == 0) {
- EMailDisplayPrivate *priv;
EMFormat *format;
CamelFolder *folder = NULL;
EShell *shell;
- priv = E_MAIL_DISPLAY_GET_PRIVATE (web_view);
- g_return_val_if_fail (priv->formatter != NULL, FALSE);
-
- format = EM_FORMAT (priv->formatter);
+ format = (EMFormat *) E_MAIL_DISPLAY (web_view)->priv->formatter;
if (format != NULL && format->folder != NULL)
folder = format->folder;
@@ -277,79 +367,825 @@ mail_display_process_mailto (EWebView *web_view,
return FALSE;
}
-static void
-mail_display_link_clicked (GtkHTML *html,
- const gchar *uri)
+static gboolean
+mail_display_link_clicked (WebKitWebView *web_view,
+ WebKitWebFrame *frame,
+ WebKitNetworkRequest *request,
+ WebKitWebNavigationAction *navigation_action,
+ WebKitWebPolicyDecision *policy_decision,
+ gpointer user_data)
{
- EMailDisplayPrivate *priv;
+ EMailDisplay *display;
+ const gchar *uri = webkit_network_request_get_uri (request);
- priv = E_MAIL_DISPLAY_GET_PRIVATE (html);
- g_return_if_fail (priv->formatter != NULL);
-
- if (g_str_has_prefix (uri, "##")) {
- guint32 flags;
-
- flags = priv->formatter->header_wrap_flags;
-
- if (strcmp (uri, "##TO##") == 0) {
- if (!(flags & EM_FORMAT_HTML_HEADER_TO))
- flags |= EM_FORMAT_HTML_HEADER_TO;
- else
- flags &= ~EM_FORMAT_HTML_HEADER_TO;
- } else if (strcmp (uri, "##CC##") == 0) {
- if (!(flags & EM_FORMAT_HTML_HEADER_CC))
- flags |= EM_FORMAT_HTML_HEADER_CC;
- else
- flags &= ~EM_FORMAT_HTML_HEADER_CC;
- } else if (strcmp (uri, "##BCC##") == 0) {
- if (!(flags & EM_FORMAT_HTML_HEADER_BCC))
- flags |= EM_FORMAT_HTML_HEADER_BCC;
- else
- flags &= ~EM_FORMAT_HTML_HEADER_BCC;
- } else if (strcmp (uri, "##HEADERS##") == 0) {
- EMFormatHTMLHeadersState state;
-
- state = em_format_html_get_headers_state (
- priv->formatter);
-
- if (state == EM_FORMAT_HTML_HEADERS_STATE_COLLAPSED)
- state = EM_FORMAT_HTML_HEADERS_STATE_EXPANDED;
- else
- state = EM_FORMAT_HTML_HEADERS_STATE_COLLAPSED;
-
- em_format_html_set_headers_state (
- priv->formatter, state);
- }
+ display = E_MAIL_DISPLAY (web_view);
+ if (display->priv->formatter == NULL)
+ return FALSE;
- priv->formatter->header_wrap_flags = flags;
- em_format_queue_redraw (EM_FORMAT (priv->formatter));
-
- } else if (mail_display_process_mailto (E_WEB_VIEW (html), uri)) {
+ if (mail_display_process_mailto (E_WEB_VIEW (web_view), uri, NULL)) {
/* do nothing, function handled the "mailto:" uri already */
- } else if (*uri == '#')
- gtk_html_jump_to_anchor (html, uri + 1);
+ webkit_web_policy_decision_ignore (policy_decision);
+ return TRUE;
- else if (g_ascii_strncasecmp (uri, "thismessage:", 12) == 0)
+ } else if (g_ascii_strncasecmp (uri, "thismessage:", 12) == 0) {
/* ignore */ ;
+ webkit_web_policy_decision_ignore (policy_decision);
+ return TRUE;
- else if (g_ascii_strncasecmp (uri, "cid:", 4) == 0)
+ } else if (g_ascii_strncasecmp (uri, "cid:", 4) == 0) {
/* ignore */ ;
+ webkit_web_policy_decision_ignore (policy_decision);
+ return TRUE;
+
+ }
+
+ /* Let webkit handle it */
+ return FALSE;
+}
+
+static void
+webkit_request_load_from_file (WebKitNetworkRequest *request,
+ const gchar *path)
+{
+ gchar *data = NULL;
+ gsize length = 0;
+ gboolean status;
+ gchar *b64, *new_uri;
+ gchar *ct;
+
+ status = g_file_get_contents (path, &data, &length, NULL);
+ if (!status)
+ return;
+
+ b64 = g_base64_encode ((guchar *) data, length);
+ ct = g_content_type_guess (path, NULL, 0, NULL);
+
+ new_uri = g_strdup_printf ("data:%s;base64,%s", ct, b64);
+ webkit_network_request_set_uri (request, new_uri);
+
+ g_free (b64);
+ g_free (new_uri);
+ g_free (ct);
+ g_free (data);
+}
+
+static void
+mail_display_resource_requested (WebKitWebView *web_view,
+ WebKitWebFrame *frame,
+ WebKitWebResource *resource,
+ WebKitNetworkRequest *request,
+ WebKitNetworkResponse *response,
+ gpointer user_data)
+{
+ EMailDisplay *display = E_MAIL_DISPLAY (web_view);
+ EMFormat *formatter = EM_FORMAT (display->priv->formatter);
+ const gchar *uri = webkit_network_request_get_uri (request);
+
+ if (!formatter) {
+ webkit_network_request_set_uri (request, "invalid://uri");
+ return;
+ }
+
+ /* Redirect cid:part_id to mail://mail_id/cid:part_id */
+ if (g_str_has_prefix (uri, "cid:")) {
+
+ /* Always write raw content of CID object */
+ gchar *new_uri = em_format_build_mail_uri (formatter->folder,
+ formatter->message_uid,
+ "part_id", G_TYPE_STRING, uri,
+ "mode", G_TYPE_INT, EM_FORMAT_WRITE_MODE_RAW, NULL);
+
+ webkit_network_request_set_uri (request, new_uri);
+
+ g_free (new_uri);
+
+ /* WebKit won't allow to load a local file when displaing "remote" mail://,
+ protocol, so we need to handle this manually */
+ } else if (g_str_has_prefix (uri, "file:")) {
+ gchar *path;
+
+ path = g_filename_from_uri (uri, NULL, NULL);
+ if (!path)
+ return;
+
+ webkit_request_load_from_file (request, path);
+
+ g_free (path);
+
+ /* Redirect http(s) request to evo-http(s) protocol. See EMailRequest for
+ * further details about this. */
+ } else if (g_str_has_prefix (uri, "http:") || g_str_has_prefix (uri, "https")) {
+
+ gchar *new_uri, *mail_uri, *enc;
+ SoupURI *soup_uri;
+ GHashTable *query;
+ gchar *uri_md5;
+ CamelStream *stream;
+
+ /* Open Evolution's cache */
+ uri_md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, uri, -1);
+ stream = camel_data_cache_get (
+ emd_global_http_cache, "http", uri_md5, NULL);
+ g_free (uri_md5);
+
+ /* If the URI is not cached and we are not allowed to load it
+ * then redirect to invalid URI, so that webkit would display
+ * a native placeholder for it. */
+ if (!stream && !display->priv->force_image_load &&
+ !em_format_html_can_load_images (display->priv->formatter)) {
+ webkit_network_request_set_uri (request, "invalid://protocol");
+ return;
+ }
+
+ new_uri = g_strconcat ("evo-", uri, NULL);
+ mail_uri = em_format_build_mail_uri (formatter->folder,
+ formatter->message_uid, NULL, NULL);
+
+ soup_uri = soup_uri_new (new_uri);
+ if (soup_uri->query) {
+ query = soup_form_decode (soup_uri->query);
+ } else {
+ query = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, g_free);
+ }
+ enc = soup_uri_encode (mail_uri, NULL);
+ g_hash_table_insert (query, g_strdup ("__evo-mail"), enc);
+
+ if (display->priv->force_image_load) {
+ g_hash_table_insert (query,
+ g_strdup ("__evo-load-images"),
+ g_strdup ("true"));
+ }
+
+ g_free (mail_uri);
+
+ soup_uri_set_query_from_form (soup_uri, query);
+ g_free (new_uri);
+
+ new_uri = soup_uri_to_string (soup_uri, FALSE);
+ webkit_network_request_set_uri (request, new_uri);
+
+ g_free (new_uri);
+ soup_uri_free (soup_uri);
+ g_hash_table_unref (query);
+ }
+}
+
+static WebKitDOMElement *
+find_element_by_id (WebKitDOMDocument *document,
+ const gchar *id)
+{
+ WebKitDOMNodeList *frames;
+ WebKitDOMElement *element;
+ gulong i, length;
+
+ /* Try to look up the element in this DOM document */
+ element = webkit_dom_document_get_element_by_id (document, id);
+ if (element)
+ return element;
+
+ /* If the element is not here then recursively scan all frames */
+ frames = webkit_dom_document_get_elements_by_tag_name(document, "iframe");
+ length = webkit_dom_node_list_get_length (frames);
+ for (i = 0; i < length; i++) {
+
+ WebKitDOMHTMLIFrameElement *iframe =
+ WEBKIT_DOM_HTML_IFRAME_ELEMENT (
+ webkit_dom_node_list_item (frames, i));
+
+ WebKitDOMDocument *frame_doc =
+ webkit_dom_html_iframe_element_get_content_document (iframe);
+
+ WebKitDOMElement *el =
+ find_element_by_id (frame_doc, id);
+
+ if (el)
+ return el;
+ }
+
+ return NULL;
+}
+
+static void
+mail_display_plugin_widget_resize (GObject *object,
+ gpointer dummy,
+ EMailDisplay *display)
+{
+ GtkWidget *widget;
+ WebKitDOMElement *parent_element;
+ gchar *dim;
+ gint height;
+
+ widget = GTK_WIDGET (object);
+ gtk_widget_get_preferred_height (widget, &height, NULL);
+ parent_element = g_object_get_data (object, "parent_element");
+
+ if (!parent_element || !WEBKIT_DOM_IS_ELEMENT (parent_element)) {
+ d(printf("%s: %s does not have (valid) parent element!\n",
+ G_STRFUNC, (gchar *) g_object_get_data (object, "uri")));
+ return;
+ }
+
+ /* Int -> Str */
+ dim = g_strdup_printf ("%d", height);
+
+ /* Set height of the containment <object> to match height of the
+ * GtkWidget it contains */
+ webkit_dom_html_object_element_set_height (
+ WEBKIT_DOM_HTML_OBJECT_ELEMENT (parent_element), dim);
+ g_free (dim);
+}
+
+static void
+mail_display_plugin_widget_realize_cb (GtkWidget *widget,
+ gpointer user_data)
+{
+ /* Initial resize of the <object> element when the widget
+ * is displayed for the first time. */
+ mail_display_plugin_widget_resize (G_OBJECT (widget), NULL, user_data);
+}
+
+static void
+plugin_widget_set_parent_element (GtkWidget *widget,
+ EMailDisplay *display)
+{
+ const gchar *uri;
+ WebKitDOMDocument *document;
+ WebKitDOMElement *element;
+
+ uri = g_object_get_data (G_OBJECT (widget), "uri");
+ if (!uri || !*uri)
+ return;
+
+ document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (display));
+ element = find_element_by_id (document, uri);
+
+ if (!element || !WEBKIT_DOM_IS_ELEMENT (element)) {
+ g_warning ("Failed to find parent <object> for '%s' - no ID set?", uri);
+ return;
+ }
+
+ /* Assign the WebKitDOMElement to "parent_element" data of the GtkWidget
+ * and the GtkWidget to "widget" data of the DOM Element */
+ g_object_set_data (G_OBJECT (widget), "parent_element", element);
+ g_object_set_data (G_OBJECT (element), "widget", widget);
+}
+
+static void
+attachment_button_expanded (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ EAttachmentButton *button = E_ATTACHMENT_BUTTON (object);
+ WebKitDOMElement *attachment = user_data;
+ WebKitDOMCSSStyleDeclaration *css;
+ gboolean expanded;
+
+ d(printf("Attachment button %s (%p) expansion state toggled!\n",
+ (gchar *) g_object_get_data (object, "uri"), object));
+
+ expanded = e_attachment_button_get_expanded (button) &&
+ gtk_widget_get_visible (GTK_WIDGET (button));
+
+ if (!WEBKIT_DOM_IS_ELEMENT (attachment)) {
+ d(printf("%s: Parent element for button %s does not exist!\n",
+ G_STRFUNC, (gchar *) g_object_get_data (object, "uri")));
+ return;
+ }
+
+ /* Show or hide the DIV which contains the attachment (iframe, image...) */
+ css = webkit_dom_element_get_style (attachment);
+ webkit_dom_css_style_declaration_set_property (
+ css, "display", expanded ? "block" : "none", "", NULL);
+}
+
+static void
+constraint_widget_visibility (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ GtkWidget *widget = GTK_WIDGET (object);
+ EAttachmentButton *button = user_data;
+
+ gboolean can_show = e_attachment_button_get_expanded (button);
+ gboolean is_visible = gtk_widget_get_visible (widget);
+
+ if (is_visible && !can_show)
+ gtk_widget_hide (widget);
+ else if (!is_visible && can_show)
+ gtk_widget_show (widget);
+
+ /* Otherwise it's OK */
+}
+
+static void
+bind_iframe_content_visibility (EAttachmentButton *button,
+ WebKitDOMElement *iframe)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMNodeList *nodes;
+ gulong i, length;
+
+ if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (iframe))
+ return;
+
+ document = webkit_dom_html_iframe_element_get_content_document (
+ WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe));
+ nodes = webkit_dom_document_get_elements_by_tag_name (document, "object");
+ length = webkit_dom_node_list_get_length (nodes);
- else {
- /* Chain up to parent's link_clicked() method. */
- GTK_HTML_CLASS (e_mail_display_parent_class)->
- link_clicked (html, uri);
+ d(printf("Found %ld objects within iframe %s\n", length,
+ webkit_dom_html_iframe_element_get_name (
+ WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe))));
+
+ /* Iterate through all <object>s and bind visibility of their widget
+ * with expanded-state of related attachment button */
+ for (i = 0; i < length; i++) {
+
+ WebKitDOMNode *node = webkit_dom_node_list_item (nodes, i);
+ GtkWidget *widget;
+
+ widget = g_object_get_data (G_OBJECT (node), "widget");
+ if (!widget)
+ continue;
+
+ d(printf("Binding visibility of widget %s (%p) with button %s (%p)\n",
+ (gchar *) g_object_get_data (G_OBJECT (widget), "uri"), widget,
+ (gchar *) g_object_get_data (G_OBJECT (button), "uri"), button));
+
+ g_object_bind_property (
+ button, "expanded",
+ widget, "visible",
+ G_BINDING_SYNC_CREATE);
+
+ /* Ensure that someone won't attempt to _show() the widget when
+ * it is supposed to be hidden and vice versa. */
+ g_signal_connect (widget, "notify::visible",
+ G_CALLBACK (constraint_widget_visibility), button);
}
}
static void
+bind_attachment_iframe_visibility (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ WebKitWebFrame *webframe;
+ const gchar *frame_name;
+ gchar *button_uri;
+ WebKitDOMDocument *document;
+ WebKitDOMElement *attachment;
+ WebKitDOMElement *button_element;
+ WebKitDOMNodeList *nodes;
+ gulong i, length;
+ GtkWidget *button;
+
+ /* Whenever an <iframe> is loaded, bind visibility of all GtkWidgets
+ * the document within the <iframe> contains with "expanded" property
+ * of the EAttachmentButton */
+
+ webframe = WEBKIT_WEB_FRAME (object);
+ if (webkit_web_frame_get_load_status (webframe) != WEBKIT_LOAD_FINISHED)
+ return;
+
+ frame_name = webkit_web_frame_get_name (webframe);
+
+ d(printf("Rebinding visibility of frame %s because it's URL changed\n",
+ frame_name));
+
+ /* Get DOMDocument of the main document */
+ document = webkit_web_view_get_dom_document (
+ webkit_web_frame_get_web_view (webframe));
+ if (!document)
+ return;
+
+ /* Find the <DIV> containing the <iframe> and related EAttachmentButton
+ * within the DOM */
+ attachment = find_element_by_id (document, frame_name);
+ if (!attachment)
+ return;
+
+ button_uri = g_strconcat (frame_name, ".attachment_button", NULL);
+ button_element = find_element_by_id (document, button_uri);
+ g_free (button_uri);
+ if (!button_element)
+ return;
+
+ button = g_object_get_data (G_OBJECT (button_element), "widget");
+
+ /* Get <iframe> representing the attachment content */
+ nodes = webkit_dom_element_get_elements_by_tag_name (attachment, "iframe");
+ length = webkit_dom_node_list_get_length (nodes);
+ for (i = 0; i < length; i++) {
+
+ WebKitDOMNode *node =
+ webkit_dom_node_list_item (nodes, i);
+
+ if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (node))
+ continue;
+
+ /* Bind visibility of all GtkWidget within the
+ * iframe with "expanded" property of the button */
+ bind_iframe_content_visibility (
+ E_ATTACHMENT_BUTTON (button),
+ WEBKIT_DOM_ELEMENT (node));
+ }
+}
+
+static GtkWidget *
+mail_display_plugin_widget_requested (WebKitWebView *web_view,
+ gchar *mime_type,
+ gchar *uri,
+ GHashTable *param,
+ gpointer user_data)
+{
+ EMFormat *emf;
+ EMailDisplay *display;
+ EMFormatPURI *puri;
+ GtkWidget *widget;
+ gchar *puri_uri;
+
+ puri_uri = g_hash_table_lookup (param, "data");
+ if (!puri_uri || !g_str_has_prefix (uri, "mail://"))
+ return NULL;
+
+ display = E_MAIL_DISPLAY (web_view);
+ emf = (EMFormat *) display->priv->formatter;
+
+ puri = em_format_find_puri (emf, puri_uri);
+ if (!puri) {
+ return NULL;
+ }
+
+ if (puri->widget_func)
+ widget = puri->widget_func (emf, puri, NULL);
+ else
+ widget = NULL;
+
+ if (!widget)
+ return NULL;
+
+ if (E_IS_ATTACHMENT_BUTTON (widget)) {
+ /* Attachment button has URI different then the actual PURI because
+ * that URI identifies the attachment itself */
+ gchar *button_uri = g_strconcat (puri_uri, ".attachment_button", NULL);
+ g_object_set_data_full (G_OBJECT (widget), "uri",
+ button_uri, (GDestroyNotify) g_free);
+ } else {
+ g_object_set_data_full (G_OBJECT (widget), "uri",
+ g_strdup (puri_uri), (GDestroyNotify) g_free);
+ }
+
+ /* Set widget's <object> container as GObject data "parent_element" */
+ plugin_widget_set_parent_element (widget, display);
+
+ /* Resizing a GtkWidget requires changing size of parent
+ * <object> HTML element in DOM. */
+ g_signal_connect (widget, "realize",
+ G_CALLBACK (mail_display_plugin_widget_realize_cb), display);
+ g_signal_connect (widget, "size-allocate",
+ G_CALLBACK (mail_display_plugin_widget_resize), display);
+
+ /* Embed the attachment bar into the GtkBox before we do anything
+ * further with the widget. */
+ if (E_IS_MAIL_ATTACHMENT_BAR (widget)) {
+
+ /* When EMailAttachmentBar is expanded/collapsed it does not
+ * emit size-allocate signal despite it changes it's height. */
+ GtkWidget *box = NULL;
+
+ /* Only when packed in box, EMailAttachmentBar reports correct
+ * height */
+ box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+ gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 0);
+
+ g_signal_connect (widget, "notify::expanded",
+ G_CALLBACK (mail_display_plugin_widget_resize), display);
+ g_signal_connect (widget, "notify::active-view",
+ G_CALLBACK (mail_display_plugin_widget_resize), display);
+
+ /* Show the EAttachmentBar but not the containing layout */
+ gtk_widget_show (widget);
+
+ widget = box;
+
+ } else if (E_IS_ATTACHMENT_BUTTON (widget)) {
+
+ /* Bind visibility of DOM element containing related
+ * attachment with 'expanded' property of this
+ * attachment button. */
+ WebKitDOMElement *attachment;
+ WebKitDOMDocument *document;
+
+ document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (display));
+ attachment = find_element_by_id (document, puri_uri);
+ if (!attachment) {
+ e_attachment_button_set_expandable (
+ E_ATTACHMENT_BUTTON (widget), FALSE);
+ } else {
+ const CamelContentDisposition *disposition;
+ WebKitDOMNodeList *nodes;
+ gulong i, length;
+
+ /* Show/hide the attachment when the EAttachmentButton
+ * is expanded/collapsed or shown/hidden */
+ g_signal_connect_data (widget, "notify::expanded",
+ G_CALLBACK (attachment_button_expanded),
+ g_object_ref (attachment), (GClosureNotify) g_object_unref, 0);
+ g_signal_connect_data (widget, "notify::visible",
+ G_CALLBACK (attachment_button_expanded),
+ g_object_ref (attachment), (GClosureNotify) g_object_unref, 0);
+ /* Initial synchronization */
+ attachment_button_expanded (G_OBJECT (widget),
+ NULL, attachment);
+
+ /* Find all <iframes> within the attachment and bind
+ * it's visiblity to expanded state of the attachment btn */
+ nodes = webkit_dom_element_get_elements_by_tag_name (
+ attachment, "iframe");
+ length = webkit_dom_node_list_get_length (nodes);
+ for (i = 0; i < length; i++) {
+
+ WebKitDOMNode *node =
+ webkit_dom_node_list_item (nodes, i);
+
+ if (!WEBKIT_DOM_IS_HTML_IFRAME_ELEMENT (node))
+ continue;
+
+ bind_iframe_content_visibility (
+ E_ATTACHMENT_BUTTON (widget),
+ WEBKIT_DOM_ELEMENT (node));
+ }
+
+ /* Expand inlined attachments */
+ disposition =
+ camel_mime_part_get_content_disposition (puri->part);
+ if (disposition &&
+ g_ascii_strncasecmp (
+ disposition->disposition, "inline", 6) == 0) {
+
+ e_attachment_button_set_expanded (
+ E_ATTACHMENT_BUTTON (widget), TRUE);
+ }
+ }
+ }
+
+ d(printf("Created widget %s (%p)\n", puri_uri, widget));
+ return widget;
+}
+
+static void
+toggle_headers_visibility (WebKitDOMElement *button,
+ WebKitDOMEvent *event,
+ WebKitWebView *web_view)
+{
+ WebKitDOMDocument *document;
+ WebKitDOMElement *short_headers, *full_headers;
+ WebKitDOMCSSStyleDeclaration *css_short, *css_full;
+ gboolean expanded;
+ const gchar *path;
+
+ document = webkit_web_view_get_dom_document (web_view);
+
+ short_headers = webkit_dom_document_get_element_by_id (
+ document, "__evo-short-headers");
+ if (!short_headers)
+ return;
+
+ css_short = webkit_dom_element_get_style (short_headers);
+
+ full_headers = webkit_dom_document_get_element_by_id (
+ document, "__evo-full-headers");
+ if (!full_headers)
+ return;
+
+ css_full = webkit_dom_element_get_style (full_headers);
+
+ expanded = (g_strcmp0 (webkit_dom_css_style_declaration_get_property_value (
+ css_full, "display"), "block") == 0);
+
+ webkit_dom_css_style_declaration_set_property (css_full, "display",
+ expanded ? "none" : "block", "", NULL);
+ webkit_dom_css_style_declaration_set_property (css_short, "display",
+ expanded ? "block" : "none", "", NULL);
+
+ if (expanded)
+ path = "evo-file://" EVOLUTION_IMAGESDIR "/plus.png";
+ else
+ path = "evo-file://" EVOLUTION_IMAGESDIR "/minus.png";
+
+ webkit_dom_html_image_element_set_src (
+ WEBKIT_DOM_HTML_IMAGE_ELEMENT (button), path);
+
+ e_mail_display_set_headers_collapsed (E_MAIL_DISPLAY (web_view), expanded);
+
+ d(printf("Headers %s!\n", expanded ? "collapsed" : "expanded"));
+}
+
+static const gchar* addresses[] = { "to", "cc", "bcc" };
+
+static void
+toggle_address_visibility (WebKitDOMElement *button,
+ WebKitDOMEvent *event,
+ const gchar *address)
+{
+ WebKitDOMElement *full_addr, *ellipsis;
+ WebKitDOMCSSStyleDeclaration *css_full, *css_ellipsis;
+ WebKitDOMDocument *document;
+ gchar *id;
+ const gchar *path;
+ gboolean expanded;
+
+ document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (button));
+
+ id = g_strconcat ("__evo-moreaddr-", address, NULL);
+ full_addr = webkit_dom_document_get_element_by_id (document, id);
+ g_free (id);
+
+ if (!full_addr)
+ return;
+
+ css_full = webkit_dom_element_get_style (full_addr);
+
+ id = g_strconcat ("__evo-moreaddr-ellipsis-", address, NULL);
+ ellipsis = webkit_dom_document_get_element_by_id (document, id);
+ g_free (id);
+
+ if (!ellipsis)
+ return;
+
+ css_ellipsis = webkit_dom_element_get_style (ellipsis);
+
+ expanded = (g_strcmp0 (
+ webkit_dom_css_style_declaration_get_property_value (
+ css_full, "display"), "inline") == 0);
+
+ webkit_dom_css_style_declaration_set_property (
+ css_full, "display", (expanded ? "none" : "inline"), "", NULL);
+ webkit_dom_css_style_declaration_set_property (
+ css_ellipsis, "display", (expanded ? "inline" : "none"), "", NULL);
+
+ if (expanded) {
+ path = "evo-file://" EVOLUTION_IMAGESDIR "/plus.png";
+ } else {
+ path = "evo-file://" EVOLUTION_IMAGESDIR "/minus.png";
+ }
+
+ if (!WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (button)) {
+ id = g_strconcat ("__evo-moreaddr-img-", address, NULL);
+ button = webkit_dom_document_get_element_by_id (document, id);
+ g_free (id);
+
+ if (!button)
+ return;
+ }
+
+ webkit_dom_html_image_element_set_src (
+ WEBKIT_DOM_HTML_IMAGE_ELEMENT (button), path);
+
+}
+
+static void
+setup_DOM_bindings (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ WebKitWebView *web_view;
+ WebKitWebFrame *frame;
+ WebKitLoadStatus load_status;
+ WebKitDOMDocument *document;
+ WebKitDOMElement *button;
+ gint i = 0;
+
+ frame = WEBKIT_WEB_FRAME (object);
+ load_status = webkit_web_frame_get_load_status (frame);
+ if (load_status != WEBKIT_LOAD_FINISHED)
+ return;
+
+ web_view = webkit_web_frame_get_web_view (frame);
+ document = webkit_web_view_get_dom_document (web_view);
+
+ button = webkit_dom_document_get_element_by_id (
+ document, "__evo-collapse-headers-img");
+ if (!button)
+ return;
+
+ d(printf("Conntecting to __evo-collapsable-headers-img::click event\n"));
+
+ webkit_dom_event_target_add_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (button), "click",
+ G_CALLBACK (toggle_headers_visibility), FALSE, web_view);
+
+ for (i = 0; i < 3; i++) {
+ gchar *id;
+ id = g_strconcat ("__evo-moreaddr-img-", addresses[i], NULL);
+ button = webkit_dom_document_get_element_by_id (document, id);
+ g_free (id);
+
+ if (!button)
+ continue;
+
+ webkit_dom_event_target_add_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (button), "click",
+ G_CALLBACK (toggle_address_visibility), FALSE,
+ (gpointer) addresses[i]);
+
+ id = g_strconcat ("__evo-moreaddr-ellipsis-", addresses[i], NULL);
+ button = webkit_dom_document_get_element_by_id (document, id);
+ g_free (id);
+
+ if (!button)
+ continue;
+
+ webkit_dom_event_target_add_event_listener (
+ WEBKIT_DOM_EVENT_TARGET (button), "click",
+ G_CALLBACK (toggle_address_visibility), FALSE,
+ (gpointer) addresses[i]);
+ }
+}
+
+static void
+puri_bind_dom (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ WebKitWebFrame *frame;
+ WebKitLoadStatus load_status;
+ WebKitWebView *web_view;
+ WebKitDOMDocument *document;
+ EMailDisplay *display;
+ GList *iter;
+ EMFormat *emf;
+ const gchar *frame_puri;
+
+ frame = WEBKIT_WEB_FRAME (object);
+ load_status = webkit_web_frame_get_load_status (frame);
+
+ if (load_status != WEBKIT_LOAD_FINISHED)
+ return;
+
+ frame_puri = webkit_web_frame_get_name (frame);
+ web_view = webkit_web_frame_get_web_view (frame);
+ display = E_MAIL_DISPLAY (web_view);
+
+ emf = EM_FORMAT (display->priv->formatter);
+ if (!emf)
+ return;
+
+ iter = g_hash_table_lookup (
+ emf->mail_part_table,
+ webkit_web_frame_get_name (frame));
+
+ document = webkit_web_view_get_dom_document (web_view);
+
+ while (iter) {
+
+ EMFormatPURI *puri = iter->data;
+
+ if (!puri)
+ continue;
+
+ /* Iterate only the PURI rendered in the frame and all it's "subPURIs" */
+ if (!g_str_has_prefix (puri->uri, frame_puri))
+ break;
+
+ if (puri->bind_func) {
+ WebKitDOMElement *el = find_element_by_id (document, puri->uri);
+ if (el) {
+ d(printf("bind_func for %s\n", puri->uri));
+ puri->bind_func (el, puri);
+ }
+ }
+
+ iter = iter->next;
+ }
+}
+
+static void
+mail_display_frame_created (WebKitWebView *web_view,
+ WebKitWebFrame *frame,
+ gpointer user_data)
+{
+ d(printf("Frame %s created!\n", webkit_web_frame_get_name (frame)));
+
+ /* Re-bind visibility of this newly created <iframe> with
+ * related EAttachmentButton whenever content of this <iframe> is
+ * (re)loaded */
+ g_signal_connect (frame, "notify::load-status",
+ G_CALLBACK (bind_attachment_iframe_visibility), NULL);
+
+ /* Call bind_func of all PURIs written in this frame */
+ g_signal_connect (frame, "notify::load-status",
+ G_CALLBACK (puri_bind_dom), NULL);
+}
+
+static void
e_mail_display_class_init (EMailDisplayClass *class)
{
GObjectClass *object_class;
GtkWidgetClass *widget_class;
- EWebViewClass *web_view_class;
- GtkHTMLClass *html_class;
+ parent_class = g_type_class_peek_parent (class);
g_type_class_add_private (class, sizeof (EMailDisplayPrivate));
object_class = G_OBJECT_CLASS (class);
@@ -361,14 +1197,6 @@ e_mail_display_class_init (EMailDisplayClass *class)
widget_class->realize = mail_display_realize;
widget_class->style_set = mail_display_style_set;
- web_view_class = E_WEB_VIEW_CLASS (class);
- web_view_class->load_string = mail_display_load_string;
- web_view_class->process_mailto = mail_display_process_mailto;
-
- html_class = GTK_HTML_CLASS (class);
- html_class->url_requested = mail_display_url_requested;
- html_class->link_clicked = mail_display_link_clicked;
-
g_object_class_install_property (
object_class,
PROP_FORMATTER,
@@ -378,38 +1206,122 @@ e_mail_display_class_init (EMailDisplayClass *class)
NULL,
EM_TYPE_FORMAT_HTML,
G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MODE,
+ g_param_spec_int (
+ "mode",
+ "Display Mode",
+ NULL,
+ 0,
+ G_MAXINT,
+ EM_FORMAT_WRITE_MODE_NORMAL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_HEADERS_COLLAPSABLE,
+ g_param_spec_boolean (
+ "headers-collapsable",
+ "Headers Collapsable",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_HEADERS_COLLAPSED,
+ g_param_spec_boolean (
+ "headers-collapsed",
+ "Headers Collapsed",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
}
static void
e_mail_display_init (EMailDisplay *display)
{
- EWebView *web_view;
GtkUIManager *ui_manager;
- GtkActionGroup *action_group;
GError *error = NULL;
-
- web_view = E_WEB_VIEW (display);
+ SoupSession *session;
+ SoupSessionFeature *feature;
+ const gchar *user_cache_dir;
+ WebKitWebSettings *settings;
+ WebKitWebFrame *main_frame;
display->priv = E_MAIL_DISPLAY_GET_PRIVATE (display);
- /* EWebView's action groups are added during its instance
- * initialization function (like what we're in now), so it
- * is safe to fetch them this early in construction. */
- action_group = e_web_view_get_action_group (web_view, "mailto");
-
- /* We don't actually handle the actions we're adding.
- * EMailReader handles them. How devious is that? */
- gtk_action_group_add_actions (
- action_group, mailto_entries,
- G_N_ELEMENTS (mailto_entries), display);
-
- /* Because we are loading from a hard-coded string, there is
- * no chance of I/O errors. Failure here implies a malformed
- * UI definition. Full stop. */
- ui_manager = e_web_view_get_ui_manager (web_view);
+ display->priv->force_image_load = FALSE;
+ display->priv->mailto_actions = gtk_action_group_new ("mailto");
+ gtk_action_group_add_actions (display->priv->mailto_actions, mailto_entries,
+ G_N_ELEMENTS (mailto_entries), NULL);
+
+ display->priv->images_actions = gtk_action_group_new ("image");
+ gtk_action_group_add_actions (display->priv->images_actions, image_entries,
+ G_N_ELEMENTS (image_entries), NULL);
+
+ webkit_web_view_set_full_content_zoom (WEBKIT_WEB_VIEW (display), TRUE);
+
+ settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (display));
+ g_object_set (settings, "enable-frame-flattening", TRUE, NULL);
+
+ g_signal_connect (display, "navigation-policy-decision-requested",
+ G_CALLBACK (mail_display_link_clicked), NULL);
+ g_signal_connect (display, "resource-request-starting",
+ G_CALLBACK (mail_display_resource_requested), NULL);
+ g_signal_connect (display, "process-mailto",
+ G_CALLBACK (mail_display_process_mailto), NULL);
+ g_signal_connect (display, "update-actions",
+ G_CALLBACK (mail_display_webview_update_actions), NULL);
+ g_signal_connect (display, "create-plugin-widget",
+ G_CALLBACK (mail_display_plugin_widget_requested), NULL);
+ g_signal_connect (display, "frame-created",
+ G_CALLBACK (mail_display_frame_created), NULL);
+
+ main_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (display));
+ g_signal_connect (main_frame, "notify::load-status",
+ G_CALLBACK (setup_DOM_bindings), NULL);
+ main_frame = webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (display));
+ g_signal_connect (main_frame, "notify::load-status",
+ G_CALLBACK (puri_bind_dom), NULL);
+
+ /* Because we are loading from a hard-coded string, there is
+ * no chance of I/O errors. Failure here implies a malformed
+ * UI definition. Full stop. */
+ ui_manager = e_web_view_get_ui_manager (E_WEB_VIEW (display));
+ gtk_ui_manager_insert_action_group (ui_manager, display->priv->mailto_actions, 0);
gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
- if (error != NULL)
- g_error ("%s", error->message);
+
+ if (error != NULL) {
+ g_error ("%s", error->message);
+ g_error_free (error);
+ }
+
+ error = NULL;
+ gtk_ui_manager_insert_action_group (ui_manager, display->priv->images_actions, 0);
+ gtk_ui_manager_add_ui_from_string (ui_manager, image_ui, -1, &error);
+
+ if (error != NULL) {
+ g_error ("%s", error->message);
+ g_error_free (error);
+ }
+
+ /* Register our own handler for our own mail:// protocol */
+ session = webkit_get_default_session ();
+ feature = SOUP_SESSION_FEATURE (soup_requester_new ());
+ soup_session_feature_add_feature (feature, E_TYPE_MAIL_REQUEST);
+ soup_session_add_feature (session, feature);
+ g_object_unref (feature);
+
+ /* cache expiry - 2 hour access, 1 day max */
+ user_cache_dir = e_get_user_cache_dir ();
+ emd_global_http_cache = camel_data_cache_new (user_cache_dir, NULL);
+ if (emd_global_http_cache) {
+ camel_data_cache_set_expire_age (emd_global_http_cache, 24 * 60 * 60);
+ camel_data_cache_set_expire_access (emd_global_http_cache, 2 * 60 * 60);
+ }
}
EMFormatHTML *
@@ -427,10 +1339,264 @@ e_mail_display_set_formatter (EMailDisplay *display,
g_return_if_fail (E_IS_MAIL_DISPLAY (display));
g_return_if_fail (EM_IS_FORMAT_HTML (formatter));
- if (display->priv->formatter != NULL)
+ g_object_ref (formatter);
+
+ if (display->priv->formatter != NULL) {
+ /* The formatter might still exist after unrefing it, so
+ * we need to stop listening to it's request for redrawing */
+ g_signal_handlers_disconnect_by_func (
+ display->priv->formatter, e_mail_display_reload, display);
g_object_unref (display->priv->formatter);
+ }
+
+ display->priv->formatter = formatter;
+
+ mail_display_update_formatter_colors (display);
- display->priv->formatter = g_object_ref (formatter);
+ g_signal_connect (formatter, "notify::image-loading-policy",
+ G_CALLBACK (formatter_image_loading_policy_changed_cb), display);
+ g_signal_connect_swapped (formatter, "redraw-requested",
+ G_CALLBACK (e_mail_display_reload), display);
+ g_signal_connect_swapped (formatter, "notify::charset",
+ G_CALLBACK (e_mail_display_reload), display);
g_object_notify (G_OBJECT (display), "formatter");
}
+
+EMFormatWriteMode
+e_mail_display_get_mode (EMailDisplay *display)
+{
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display),
+ EM_FORMAT_WRITE_MODE_NORMAL);
+
+ return display->priv->mode;
+}
+
+void
+e_mail_display_set_mode (EMailDisplay *display,
+ EMFormatWriteMode mode)
+{
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+ if (display->priv->mode == mode)
+ return;
+
+ display->priv->mode = mode;
+
+ e_mail_display_reload (display);
+
+ g_object_notify (G_OBJECT (display), "mode");
+}
+
+gboolean
+e_mail_display_get_headers_collapsable (EMailDisplay *display)
+{
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), FALSE);
+
+ return display->priv->headers_collapsable;
+}
+
+void
+e_mail_display_set_headers_collapsable (EMailDisplay *display,
+ gboolean collapsable)
+{
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+ if (display->priv->headers_collapsable == collapsable)
+ return;
+
+ display->priv->headers_collapsable = collapsable;
+ e_mail_display_reload (display);
+
+ g_object_notify (G_OBJECT (display), "headers-collapsable");
+}
+
+gboolean
+e_mail_display_get_headers_collapsed (EMailDisplay *display)
+{
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), FALSE);
+
+ if (display->priv->headers_collapsable)
+ return display->priv->headers_collapsed;
+
+ return FALSE;
+}
+
+void
+e_mail_display_set_headers_collapsed (EMailDisplay *display,
+ gboolean collapsed)
+{
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+ if (display->priv->headers_collapsed == collapsed)
+ return;
+
+ display->priv->headers_collapsed = collapsed;
+
+ g_object_notify (G_OBJECT (display), "headers-collapsed");
+}
+
+void
+e_mail_display_load (EMailDisplay *display,
+ const gchar *msg_uri)
+{
+ EMFormat *emf;
+ gchar *uri;
+
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+ display->priv->force_image_load = FALSE;
+
+ emf = EM_FORMAT (display->priv->formatter);
+
+ uri = em_format_build_mail_uri (emf->folder, emf->message_uid,
+ "mode", G_TYPE_INT, display->priv->mode,
+ "headers_collapsable", G_TYPE_BOOLEAN, display->priv->headers_collapsable,
+ "headers_collapsed", G_TYPE_BOOLEAN, display->priv->headers_collapsed,
+ NULL);
+
+ e_web_view_load_uri (E_WEB_VIEW (display), uri);
+
+ g_free (uri);
+}
+
+void
+e_mail_display_reload (EMailDisplay *display)
+{
+ EWebView *web_view;
+ const gchar *uri;
+ gchar *base;
+ GString *new_uri;
+ GHashTable *table;
+ GHashTableIter table_iter;
+ gpointer key, val;
+ gchar separator;
+
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+ web_view = E_WEB_VIEW (display);
+ uri = e_web_view_get_uri (web_view);
+
+ if (!uri || !*uri)
+ return;
+
+ if (strstr(uri, "?") == NULL) {
+ e_web_view_reload (web_view);
+ return;
+ }
+
+ base = g_strndup (uri, strstr (uri, "?") - uri);
+ new_uri = g_string_new (base);
+ g_free (base);
+
+ table = soup_form_decode (strstr (uri, "?") + 1);
+ g_hash_table_insert (table, g_strdup ("mode"), g_strdup_printf ("%d", display->priv->mode));
+ g_hash_table_insert (table, g_strdup ("headers_collapsable"), g_strdup_printf ("%d", display->priv->headers_collapsable));
+ g_hash_table_insert (table, g_strdup ("headers_collapsed"), g_strdup_printf ("%d", display->priv->headers_collapsed));
+
+ g_hash_table_iter_init (&table_iter, table);
+ separator = '?';
+ while (g_hash_table_iter_next (&table_iter, &key, &val)) {
+ g_string_append_printf (new_uri, "%c%s=%s", separator,
+ (gchar *) key, (gchar *) val);
+
+ if (separator == '?')
+ separator = '&';
+ }
+
+ e_web_view_load_uri (web_view, new_uri->str);
+
+ g_string_free (new_uri, TRUE);
+ g_hash_table_destroy (table);
+}
+
+GtkAction *
+e_mail_display_get_action (EMailDisplay *display,
+ const gchar *action_name)
+{
+ GtkAction *action;
+
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
+ g_return_val_if_fail (action_name != NULL, NULL);
+
+ action = gtk_action_group_get_action (display->priv->mailto_actions, action_name);
+ if (!action)
+ action = gtk_action_group_get_action (display->priv->images_actions, action_name);
+
+ return action;
+}
+
+void
+e_mail_display_set_status (EMailDisplay *display,
+ const gchar *status)
+{
+ gchar *str;
+
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+ str = g_strdup_printf (
+ "<!DOCTYPE>"
+ "<html>"
+ "<head><title>Evolution Mail Display</title></head>"
+ "<body>"
+ "<table border=\"0\" width=\"100%%\" height=\"100%%\">"
+ "<tr height=\"100%%\" valign=\"middle\">"
+ "<td width=\"100%%\" align=\"center\">"
+ "<strong>%s</strong>"
+ "</td>"
+ "</tr>"
+ "</table>"
+ "</body>"
+ "</html>", status);
+
+ e_web_view_load_string (E_WEB_VIEW (display), str);
+ g_free (str);
+
+ gtk_widget_show_all (GTK_WIDGET (display));
+}
+
+gchar *
+e_mail_display_get_selection_plain_text (EMailDisplay *display,
+ gint *len)
+{
+ EWebView *web_view;
+ WebKitWebFrame *frame;
+ const gchar *frame_name;
+ GValue value = {0};
+ GType type;
+ const gchar *str;
+
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
+
+ web_view = E_WEB_VIEW (display);
+ frame = webkit_web_view_get_focused_frame (WEBKIT_WEB_VIEW (web_view));
+ frame_name = webkit_web_frame_get_name (frame);
+
+ type = e_web_view_frame_exec_script (web_view, frame_name, "window.getSelection().toString()", &value);
+ g_return_val_if_fail (type == G_TYPE_STRING, NULL);
+
+ str = g_value_get_string (&value);
+
+ if (len)
+ *len = strlen (str);
+
+ return g_strdup (str);
+}
+
+void
+e_mail_display_load_images (EMailDisplay *display)
+{
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+ display->priv->force_image_load = TRUE;
+ e_web_view_reload (E_WEB_VIEW (display));
+}
+
+void
+e_mail_display_set_force_load_images (EMailDisplay *display,
+ gboolean force_load_images)
+{
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+ display->priv->force_image_load = force_load_images;
+}