[evolution] Bug #515004 - Allow toggling between text and HTML view of mail



commit 99a875edae6c57fd6540818d3f0da994b135a068
Author: Dan VrÃtil <dvratil redhat com>
Date:   Tue Jun 26 13:39:47 2012 +0200

    Bug #515004 - Allow toggling between text and HTML view of mail

 data/webview.css                                   |    4 +-
 em-format/e-mail-formatter-text-html.c             |    3 +-
 em-format/e-mail-formatter-text-plain.c            |   26 +-
 mail/Makefile.am                                   |    2 +
 mail/e-mail-display-popup-extension.c              |   55 +++
 mail/e-mail-display-popup-extension.h              |   64 ++++
 mail/e-mail-display.c                              |   78 +++--
 modules/prefer-plain/Makefile.am                   |    2 +
 .../e-mail-display-popup-prefer-plain.c            |  380 ++++++++++++++++++++
 .../e-mail-display-popup-prefer-plain.h            |   30 ++
 modules/prefer-plain/e-mail-parser-prefer-plain.c  |  270 ++++++--------
 .../prefer-plain/evolution-module-prefer-plain.c   |    2 +
 widgets/misc/e-web-view.c                          |    5 +-
 13 files changed, 732 insertions(+), 189 deletions(-)
---
diff --git a/data/webview.css b/data/webview.css
index 09f9404..a8a936d 100644
--- a/data/webview.css
+++ b/data/webview.css
@@ -1,6 +1,6 @@
 html, body {
-  padding: 0;
-  margin: 0;
+ padding: 0;
+ margin: 0;
 }
 
 img {
diff --git a/em-format/e-mail-formatter-text-html.c b/em-format/e-mail-formatter-text-html.c
index 8834994..e5d25a3 100644
--- a/em-format/e-mail-formatter-text-html.c
+++ b/em-format/e-mail-formatter-text-html.c
@@ -309,12 +309,13 @@ emfe_text_html_format (EMailFormatterExtension *extension,
 			"<div class=\"part-container-nostyle\">"
 			"<iframe width=\"100%%\" height=\"10\" "
 			" frameborder=\"0\" src=\"%s\" "
-			" id=\"%s.iframe\" "
+			" id=\"%s.iframe\" name=\"%s\" "
 			" style=\"border: 1px solid #%06x; background-color: #%06x;\">"
 			"</iframe>"
 			"</div>",
 			uri,
 			part->id,
+			part->id,
 			e_color_to_value ((GdkColor *)
 				e_mail_formatter_get_color (
 					formatter, E_MAIL_FORMATTER_COLOR_FRAME)),
diff --git a/em-format/e-mail-formatter-text-plain.c b/em-format/e-mail-formatter-text-plain.c
index a8cb7f2..7859a41 100644
--- a/em-format/e-mail-formatter-text-plain.c
+++ b/em-format/e-mail-formatter-text-plain.c
@@ -114,12 +114,8 @@ emfe_text_plain_format (EMailFormatterExtension *extension,
 
 		content = g_strdup_printf (
 			"<div class=\"part-container\" style=\""
-			"border-color: #%06x;"
-			"background-color: #%06x; color: #%06x;\">"
-			"<div class=\"part-container-inner-margin pre\">\n",
-			e_color_to_value ((GdkColor *)
-				e_mail_formatter_get_color (
-					formatter, E_MAIL_FORMATTER_COLOR_FRAME)),
+			"border: none; padding: 10px; margin: 0; "
+			"background-color: #%06x; color: #%06x;\">\n",
 			e_color_to_value ((GdkColor *)
 				e_mail_formatter_get_color (
 					formatter, E_MAIL_FORMATTER_COLOR_CONTENT)),
@@ -134,7 +130,7 @@ emfe_text_plain_format (EMailFormatterExtension *extension,
 		g_object_unref (filtered_stream);
 		g_free (content);
 
-		camel_stream_write_string (stream, "</div></div>\n", cancellable, NULL);
+		camel_stream_write_string (stream, "</div>\n", cancellable, NULL);
 
 		if (context->mode == E_MAIL_FORMATTER_MODE_RAW) {
 			camel_stream_write_string (stream, "</body></html>",
@@ -153,10 +149,20 @@ emfe_text_plain_format (EMailFormatterExtension *extension,
 			NULL);
 
 		str = g_strdup_printf (
+			"<div class=\"part-container-nostyle\" >"
 			"<iframe width=\"100%%\" height=\"10\""
-			" id=\"%s.iframe\" "
-			" frameborder=\"0\" src=\"%s\"></iframe>",
-			part->id, uri);
+			" id=\"%s.iframe\" name=\"%s\" "
+			" frameborder=\"0\" src=\"%s\" "
+			" style=\"border: 1px solid #%06x; background-color: #%06x;\">"
+			"</iframe>"
+			"</div>",
+			part->id, part->id, uri,
+			e_color_to_value ((GdkColor *)
+				e_mail_formatter_get_color (
+					formatter, E_MAIL_FORMATTER_COLOR_FRAME)),
+			e_color_to_value ((GdkColor *)
+				e_mail_formatter_get_color (
+					formatter, E_MAIL_FORMATTER_COLOR_CONTENT)));
 
 		camel_stream_write_string (stream, str, cancellable, NULL);
 
diff --git a/mail/Makefile.am b/mail/Makefile.am
index cd02ad6..9dda24f 100644
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@ -67,6 +67,7 @@ mailinclude_HEADERS =					\
 	e-mail-config-welcome-page.h			\
 	e-mail-config-window.h				\
 	e-mail-display.h				\
+	e-mail-display-popup-extension.h		\
 	e-mail-folder-pane.h				\
 	e-mail-junk-options.h				\
 	e-mail-label-action.h				\
@@ -146,6 +147,7 @@ libevolution_mail_la_SOURCES =				\
 	e-mail-config-welcome-page.c			\
 	e-mail-config-window.c				\
 	e-mail-display.c				\
+	e-mail-display-popup-extension.c		\
 	e-mail-folder-pane.c				\
 	e-mail-junk-options.c				\
 	e-mail-label-action.c				\
diff --git a/mail/e-mail-display-popup-extension.c b/mail/e-mail-display-popup-extension.c
new file mode 100644
index 0000000..a444179
--- /dev/null
+++ b/mail/e-mail-display-popup-extension.c
@@ -0,0 +1,55 @@
+/*
+ * e-mail-display-popup-extension.c
+ *
+ * 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/>
+ *
+ */
+
+#include "e-mail-display-popup-extension.h"
+#include "e-mail-display.h"
+
+G_DEFINE_INTERFACE (
+	EMailDisplayPopupExtension,
+	e_mail_display_popup_extension,
+	G_TYPE_OBJECT)
+
+
+static void
+e_mail_display_popup_extension_default_init (EMailDisplayPopupExtensionInterface *iface)
+{
+
+}
+
+/**
+ * e_mail_display_popup_extension_update_actions:
+ *
+ * @extension: An object derived from #EMailDisplayPopupExtension
+ * @context: A #WebKitHitTestResult describing context of the popup menu
+ *
+ * When #EMailDisplay is about to display a popup menu, it calls this function
+ * on every extension so that they can add their items to the menu.
+ */
+void
+e_mail_display_popup_extension_update_actions (EMailDisplayPopupExtension *extension,
+					       WebKitHitTestResult *context)
+{
+	EMailDisplayPopupExtensionInterface *iface;
+
+	g_return_if_fail (E_IS_MAIL_DISPLAY_POPUP_EXTENSION (extension));
+
+	iface = E_MAIL_DISPLAY_POPUP_EXTENSION_GET_INTERFACE (extension);
+	g_return_if_fail (iface->update_actions != NULL);
+
+	iface->update_actions (extension, context);
+}
diff --git a/mail/e-mail-display-popup-extension.h b/mail/e-mail-display-popup-extension.h
new file mode 100644
index 0000000..307071e
--- /dev/null
+++ b/mail/e-mail-display-popup-extension.h
@@ -0,0 +1,64 @@
+/*
+ * e-mail-dispaly-popup-extension.h
+ *
+ * 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 E_MAIL_DISPLAY_POPUP_EXTENSION_H
+#define E_MAIL_DISPLAY_POPUP_EXTENSION_H
+
+#include <glib-object.h>
+#include <webkit/webkit.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_DISPLAY_POPUP_EXTENSION \
+	(e_mail_display_popup_extension_get_type ())
+#define E_MAIL_DISPLAY_POPUP_EXTENSION(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_MAIL_DISPLAY_POPUP_EXTENSION, EMailDisplayPopupExtension))
+#define E_MAIL_DISPLAY_POPUP_EXTENSION_INTERFACE(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_MAIL_DISPLAY_POPUP_EXTENSION, EMailDisplayPopupExtensionInterface))
+#define E_IS_MAIL_DISPLAY_POPUP_EXTENSION(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_MAIL_DISPLAY_POPUP_EXTENSION))
+#define E_IS_MAIL_DISPLAY_POPUP_EXTENSION_INTERFACE(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_MAIL_DISPLAY_POPUP_EXTENSION))
+#define E_MAIL_DISPLAY_POPUP_EXTENSION_GET_INTERFACE(obj) \
+	(G_TYPE_INSTANCE_GET_INTERFACE \
+	((obj), E_TYPE_MAIL_DISPLAY_POPUP_EXTENSION, EMailDisplayPopupExtensionInterface))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailDisplayPopupExtension EMailDisplayPopupExtension;
+typedef struct _EMailDisplayPopupExtensionInterface EMailDisplayPopupExtensionInterface;
+
+struct _EMailDisplayPopupExtensionInterface {
+	GTypeInterface parent_interface;
+
+	void	(*update_actions)		(EMailDisplayPopupExtension *extension,
+						 WebKitHitTestResult *context);
+};
+
+GType		e_mail_display_popup_extension_get_type	(void);
+
+void		e_mail_display_popup_extension_update_actions
+							(EMailDisplayPopupExtension *extension,
+							 WebKitHitTestResult *context);
+
+G_END_DECLS
+
+#endif /* E_MAIL_DISPLAY_POPUP_EXTENSION_H */
diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c
index dab8c3b..6e0f0a3 100644
--- a/mail/e-mail-display.c
+++ b/mail/e-mail-display.c
@@ -24,6 +24,7 @@
 #endif
 
 #include "e-mail-display.h"
+#include "e-mail-display-popup-extension.h"
 
 #include <glib/gi18n.h>
 #include <gdk/gdk.h>
@@ -52,7 +53,10 @@
 
 #define d(x)
 
-G_DEFINE_TYPE (EMailDisplay, e_mail_display, E_TYPE_WEB_VIEW)
+G_DEFINE_TYPE (
+	EMailDisplay,
+	e_mail_display,
+	E_TYPE_WEB_VIEW);
 
 #define E_MAIL_DISPLAY_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE \
@@ -161,49 +165,67 @@ static GtkActionEntry image_entries[] = {
 
 };
 
-static void
-mail_display_update_actions (EWebView *web_view,
-                             GdkEventButton *event)
+static gboolean
+mail_display_button_press_event (GtkWidget *widget,
+				 GdkEventButton *event)
 {
 	WebKitHitTestResult *hit_test;
 	WebKitHitTestResultContext context;
 	gchar *image_src;
 	gboolean visible;
 	GtkAction *action;
-
-	/* Chain up first! */
-	E_WEB_VIEW_CLASS (e_mail_display_parent_class)->
-		update_actions (web_view, event);
+	GList *extensions, *iter;
+	EWebView *web_view = E_WEB_VIEW (widget);
 
 	hit_test = webkit_web_view_get_hit_test_result (
 			WEBKIT_WEB_VIEW (web_view), event);
+
 	g_object_get (
 		G_OBJECT (hit_test),
 		"context", &context,
 	        "image-uri", &image_src,
 		NULL);
 
-	if (!(context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE))
-		return;
+	if ((context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE)) {
+		visible = image_src && g_str_has_prefix (image_src, "cid:");
+		if (!visible && image_src) {
+			CamelStream *image_stream;
 
-	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);
 
-		image_stream = camel_data_cache_get (emd_global_http_cache, "http", image_src, NULL);
+			visible = image_stream != NULL;
 
-		visible = image_stream != NULL;
+			if (image_stream)
+				g_object_unref (image_stream);
+		}
+
+		if (image_src)
+			g_free (image_src);
 
-		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);
 	}
 
-	if (image_src)
-		g_free (image_src);
+	extensions = e_extensible_list_extensions (
+			E_EXTENSIBLE (web_view), E_TYPE_EXTENSION);
+	for (iter = extensions; iter; iter = g_list_next (iter)) {
+		EExtension *extension = iter->data;
+
+		if (!E_IS_MAIL_DISPLAY_POPUP_EXTENSION (extension))
+			continue;
 
-	action = e_web_view_get_action (web_view, "image-save");
-	if (action)
-		gtk_action_set_visible (action, visible);
+		e_mail_display_popup_extension_update_actions (
+			E_MAIL_DISPLAY_POPUP_EXTENSION (extension), hit_test);
+	}
+	g_list_free (extensions);
+
+	g_object_unref (hit_test);
+
+	/* Chain up to parent's button_press_event() method. */
+	return GTK_WIDGET_CLASS (e_mail_display_parent_class)->button_press_event (widget, event);
 }
 
 static void
@@ -231,6 +253,15 @@ mail_display_update_formatter_colors (EMailDisplay *display)
 }
 
 static void
+mail_display_constructed (GObject *object)
+{
+	e_extensible_load_extensions (E_EXTENSIBLE (object));
+
+	/* Chain up to parent's constructed() method. */
+	G_OBJECT_CLASS (e_mail_display_parent_class)->constructed (object);
+}
+
+static void
 mail_display_set_property (GObject *object,
                            guint property_id,
                            const GValue *value,
@@ -1358,17 +1389,18 @@ e_mail_display_class_init (EMailDisplayClass *class)
 	g_type_class_add_private (class, sizeof (EMailDisplayPrivate));
 
 	object_class = G_OBJECT_CLASS (class);
+	object_class->constructed = mail_display_constructed;
 	object_class->set_property = mail_display_set_property;
 	object_class->get_property = mail_display_get_property;
 	object_class->dispose = mail_display_dispose;
 
 	web_view_class = E_WEB_VIEW_CLASS (class);
 	web_view_class->set_fonts = mail_display_set_fonts;
-	web_view_class->update_actions = mail_display_update_actions;
 
 	widget_class = GTK_WIDGET_CLASS (class);
 	widget_class->realize = mail_display_realize;
 	widget_class->style_set = mail_display_style_set;
+	widget_class->button_press_event = mail_display_button_press_event;
 
 	g_object_class_install_property (
 		object_class,
diff --git a/modules/prefer-plain/Makefile.am b/modules/prefer-plain/Makefile.am
index e4e6b56..18cb743 100644
--- a/modules/prefer-plain/Makefile.am
+++ b/modules/prefer-plain/Makefile.am
@@ -14,6 +14,8 @@ module_prefer_plain_la_CPPFLAGS =				\
 module_prefer_plain_la_SOURCES =				\
 	e-mail-parser-prefer-plain.c					\
 	e-mail-parser-prefer-plain.h					\
+	e-mail-display-popup-prefer-plain.c				\
+	e-mail-display-popup-prefer-plain.h				\
 	evolution-module-prefer-plain.c
 
 module_prefer_plain_la_LIBADD =				\
diff --git a/modules/prefer-plain/e-mail-display-popup-prefer-plain.c b/modules/prefer-plain/e-mail-display-popup-prefer-plain.c
new file mode 100644
index 0000000..75c74db
--- /dev/null
+++ b/modules/prefer-plain/e-mail-display-popup-prefer-plain.c
@@ -0,0 +1,380 @@
+/*
+ * 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 "e-mail-display-popup-prefer-plain.h"
+#include "mail/e-mail-display-popup-extension.h"
+#include "mail/e-mail-display.h"
+#include <shell/e-shell.h>
+#include <shell/e-shell-window.h>
+#include "mail/e-mail-browser.h"
+
+#include <libebackend/libebackend.h>
+
+#include <glib/gi18n-lib.h>
+
+#define d(x)
+
+typedef struct _EMailDisplayPopupPreferPlain {
+	EExtension parent;
+
+	WebKitDOMDocument *document;
+	gchar *text_plain_id;
+	gchar *text_html_id;
+
+	GtkActionGroup *action_group;
+
+} EMailDisplayPopupPreferPlain;
+
+typedef struct _EMailDisplayPopupPreferPlainClass {
+	EExtensionClass parent_class;
+} EMailDisplayPopupPreferPlainClass;
+
+#define E_MAIL_DISPLAY_POPUP_PREFER_PLAIN(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), e_mail_display_popup_prefer_plain_get_type(), EMailDisplayPopupPreferPlain))
+
+GType e_mail_display_popup_prefer_plain_get_type (void);
+static void e_mail_display_popup_extension_interface_init (EMailDisplayPopupExtensionInterface *iface);
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (
+	EMailDisplayPopupPreferPlain,
+	e_mail_display_popup_prefer_plain,
+	E_TYPE_EXTENSION,
+	0,
+	G_IMPLEMENT_INTERFACE_DYNAMIC (
+		E_TYPE_MAIL_DISPLAY_POPUP_EXTENSION,
+		e_mail_display_popup_extension_interface_init));
+
+static const gchar *ui_webview =
+"<ui>"
+"  <popup name='context'>"
+"    <placeholder name='custom-actions-2'>"
+"      <separator/>"
+"      <menuitem action='show-plain-text-part'/>"
+"      <menuitem action='show-text-html-part'/>"
+"      <separator/>"
+"    </placeholder>"
+"  </popup>"
+"</ui>";
+
+static const gchar *ui_reader =
+"<ui>"
+"  <popup name='mail-preview-popup'>"
+"    <placeholder name='mail-preview-popup-actions'>"
+"      <separator/>"
+"      <menuitem action='show-plain-text-part'/>"
+"      <menuitem action='show-text-html-part'/>"
+"      <separator/>"
+"    </placeholder>"
+"  </popup>"
+"</ui>";
+
+
+static void
+toggle_part (GtkAction *action,
+	     EMailDisplayPopupExtension *extension)
+{
+	EMailDisplayPopupPreferPlain *pp_extension = (EMailDisplayPopupPreferPlain *) extension;
+	WebKitDOMDocument *doc = pp_extension->document;
+	WebKitDOMDOMWindow *window;
+	WebKitDOMElement *frame_element;
+	SoupURI *soup_uri;
+	GHashTable *query;
+	gchar *uri;
+
+	uri = webkit_dom_document_get_document_uri (doc);
+	soup_uri = soup_uri_new (uri);
+	g_free (uri);
+
+	query = soup_form_decode (soup_uri->query);
+	g_hash_table_replace (query, g_strdup ("part_id"),
+		pp_extension->text_html_id ?
+			pp_extension->text_html_id :
+			pp_extension->text_plain_id);
+
+	soup_uri_set_query_from_form (soup_uri, query);
+	g_hash_table_destroy (query);
+
+	uri = soup_uri_to_string (soup_uri, FALSE);
+	soup_uri_free (soup_uri);
+
+	/* Get frame's window and from the window the actual <iframe> element */
+	window = webkit_dom_document_get_default_view (doc);
+	frame_element = webkit_dom_dom_window_get_frame_element (window);
+	webkit_dom_html_iframe_element_set_src (
+		WEBKIT_DOM_HTML_IFRAME_ELEMENT (frame_element), uri);
+
+	g_free (uri);
+}
+
+GtkActionEntry entries[] = {
+
+	{ "show-plain-text-part",
+	   NULL,
+	   N_("Display plain text version"),
+	   NULL,
+	   N_("Display plain text version of multipart/alternative message"),
+	   NULL
+	},
+
+	{ "show-text-html-part",
+	  NULL,
+	  N_("Display HTML version"),
+	  NULL,
+	  N_("Display HTML version of multipart/alternative message"),
+	  NULL
+	}
+};
+
+const gint ID_LEN = G_N_ELEMENTS(".alternative-prefer-plain.");
+
+static void
+set_text_plain_id (EMailDisplayPopupPreferPlain *extension,
+		   const gchar *id)
+{
+	g_free (extension->text_plain_id);
+	extension->text_plain_id = g_strdup (id);
+}
+
+static void
+set_text_html_id (EMailDisplayPopupPreferPlain *extension,
+		  const gchar *id)
+{
+	g_free (extension->text_html_id);
+	extension->text_html_id = g_strdup (id);
+}
+
+
+static GtkActionGroup*
+create_group (EMailDisplayPopupExtension *extension)
+{
+	EExtensible *extensible;
+	EWebView *web_view;
+	GtkUIManager *ui_manager;
+	GtkActionGroup *group;
+	GtkAction *action;
+	EShell *shell;
+	GtkWindow *shell_window;
+
+	extensible = e_extension_get_extensible (E_EXTENSION (extension));
+	web_view = E_WEB_VIEW (extensible);
+
+	group = gtk_action_group_new ("prefer-plain");
+	gtk_action_group_add_actions (group, entries, G_N_ELEMENTS (entries), NULL);
+
+	ui_manager = e_web_view_get_ui_manager (web_view);
+	gtk_ui_manager_insert_action_group (ui_manager, group, 0);
+	gtk_ui_manager_add_ui_from_string (ui_manager, ui_webview, -1, NULL);
+
+	action = gtk_action_group_get_action (group, "show-plain-text-part");
+	g_signal_connect (action, "activate",
+		G_CALLBACK (toggle_part), extension);
+
+	action = gtk_action_group_get_action (group, "show-text-html-part");
+	g_signal_connect (action, "activate",
+		G_CALLBACK (toggle_part), extension);
+
+
+	shell = e_shell_get_default ();
+	shell_window = e_shell_get_active_window (shell);
+	if (E_IS_SHELL_WINDOW (shell_window)) {
+		ui_manager = e_shell_window_get_ui_manager (E_SHELL_WINDOW (shell_window));
+	} else if (E_IS_MAIL_BROWSER (shell_window)) {
+		ui_manager = e_mail_browser_get_ui_manager (E_MAIL_BROWSER (shell_window));
+	} else {
+		return NULL;
+	}
+
+	gtk_ui_manager_insert_action_group (ui_manager, group, 0);
+	gtk_ui_manager_add_ui_from_string (ui_manager, ui_reader, -1, NULL);
+
+	return group;
+}
+
+static void
+mail_display_popup_prefer_plain_update_actions (EMailDisplayPopupExtension *extension,
+						WebKitHitTestResult *context)
+{
+	EMailDisplay *display;
+	GtkAction *action;
+	WebKitDOMNode *node;
+	gchar *uri, *part_id, *pos, *prefix;
+	SoupURI *soup_uri;
+	GHashTable *query;
+	EMailPartList *part_list;
+	GSList *iter;
+	gboolean is_text_plain;
+	const gchar *action_name;
+	EMailDisplayPopupPreferPlain *pp_extension;
+
+	display = E_MAIL_DISPLAY (e_extension_get_extensible (
+			E_EXTENSION (extension)));
+
+	pp_extension = E_MAIL_DISPLAY_POPUP_PREFER_PLAIN (extension);
+
+	if (!pp_extension->action_group)
+		pp_extension->action_group = create_group (extension);
+
+	g_object_get (context, "inner-node", &node, NULL);
+
+	if (!node) {
+		gtk_action_group_set_visible (pp_extension->action_group, FALSE);
+		return;
+	}
+
+	pp_extension->document = webkit_dom_node_get_owner_document (node);
+	uri = webkit_dom_document_get_document_uri (pp_extension->document);
+
+	soup_uri = soup_uri_new (uri);
+	if (!soup_uri || !soup_uri->query) {
+		gtk_action_group_set_visible (pp_extension->action_group, FALSE);
+		if (soup_uri)
+			soup_uri_free (soup_uri);
+		g_free (uri);
+		return;
+	}
+
+	query = soup_form_decode (soup_uri->query);
+	part_id = g_hash_table_lookup (query, "part_id");
+	if (part_id == NULL) {
+		gtk_action_group_set_visible (pp_extension->action_group, FALSE);
+		g_hash_table_destroy (query);
+		soup_uri_free (soup_uri);
+		g_free (uri);
+		return;
+	}
+
+	pos = strstr (part_id, ".alternative-prefer-plain.");
+	if (!pos) {
+		gtk_action_group_set_visible (pp_extension->action_group, FALSE);
+		g_hash_table_destroy (query);
+		soup_uri_free (soup_uri);
+		g_free (uri);
+		return;
+	}
+
+	/* Don't display the actions on any other than text/plain or text/html parts */
+	if (!strstr (pos, "plain_text") && !strstr (pos, "text_html")) {
+		gtk_action_group_set_visible (pp_extension->action_group, FALSE);
+		g_hash_table_destroy (query);
+		soup_uri_free (soup_uri);
+		g_free (uri);
+		return;
+	}
+
+	/* Check whether the displayed part is text_plain */
+	is_text_plain = (strstr (pos + ID_LEN, "plain_text") != NULL);
+
+	/* It is! Hide the menu action */
+	if (is_text_plain) {
+		action = gtk_action_group_get_action (
+			pp_extension->action_group, "show-plain-text-part");
+		gtk_action_set_visible (action, FALSE);
+	} else {
+		action = gtk_action_group_get_action (
+			pp_extension->action_group, "show-text-html-part");
+		gtk_action_set_visible (action, FALSE);
+	}
+
+	/* Now check whether HTML version exists, if it does enable the action */
+	prefix = g_strndup (part_id, (pos - part_id) + ID_LEN - 1);
+
+	action_name = NULL;
+	part_list = e_mail_display_get_parts_list (display);
+	for (iter = part_list->list; iter; iter = g_slist_next (iter)) {
+		EMailPart *p = iter->data;
+		if (!p)
+			continue;
+
+		if (g_str_has_prefix (p->id, prefix) &&
+		    (strstr (p->id, "text_html") || strstr (p->id, "plain_text"))) {
+
+			pos = strstr (p->id, ".alternative-prefer-plain.");
+
+			if (is_text_plain) {
+				if (strstr (pos + ID_LEN, "text_html") != NULL) {
+					action_name = "show-text-html-part";
+					set_text_html_id (pp_extension, p->id);
+					set_text_plain_id (pp_extension, NULL);
+					break;
+				}
+			} else {
+				if (strstr (pos + ID_LEN, "plain_text") != NULL) {
+					action_name = "show-plain-text-part";
+					set_text_html_id (pp_extension, NULL);
+					set_text_plain_id (pp_extension, p->id);
+					break;
+				}
+			}
+		}
+	}
+
+	if (action_name) {
+		action = gtk_action_group_get_action (
+			pp_extension->action_group, action_name);
+		gtk_action_group_set_visible (pp_extension->action_group, TRUE);
+		gtk_action_set_visible (action, TRUE);
+	} else {
+		gtk_action_group_set_visible (pp_extension->action_group, FALSE);
+	}
+
+	g_free (prefix);
+	g_hash_table_destroy (query);
+	soup_uri_free (soup_uri);
+	g_free (uri);
+}
+
+void
+e_mail_display_popup_prefer_plain_type_register (GTypeModule *type_module)
+{
+	e_mail_display_popup_prefer_plain_register_type (type_module);
+}
+
+static void
+e_mail_display_popup_prefer_plain_class_init (EMailDisplayPopupPreferPlainClass *klass)
+{
+	EExtensionClass *extension_class;
+
+	e_mail_display_popup_prefer_plain_parent_class = g_type_class_peek_parent (klass);
+
+	extension_class = E_EXTENSION_CLASS (klass);
+	extension_class->extensible_type = E_TYPE_MAIL_DISPLAY;
+}
+
+static void
+e_mail_display_popup_extension_interface_init (EMailDisplayPopupExtensionInterface *iface)
+{
+	iface->update_actions = mail_display_popup_prefer_plain_update_actions;
+}
+
+void
+e_mail_display_popup_prefer_plain_class_finalize (EMailDisplayPopupPreferPlainClass *klass)
+{
+
+}
+
+
+static void
+e_mail_display_popup_prefer_plain_init (EMailDisplayPopupPreferPlain *extension)
+{
+	extension->action_group = NULL;
+	extension->text_html_id = NULL;
+	extension->text_plain_id = NULL;
+	extension->document = NULL;
+}
diff --git a/modules/prefer-plain/e-mail-display-popup-prefer-plain.h b/modules/prefer-plain/e-mail-display-popup-prefer-plain.h
new file mode 100644
index 0000000..432ed4a
--- /dev/null
+++ b/modules/prefer-plain/e-mail-display-popup-prefer-plain.h
@@ -0,0 +1,30 @@
+/*
+ * e-mail-display-popup-prefer-plain.h
+ *
+ * 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 E_MAIL_DISPLAY_POPUP_PREFER_PLAIN_H
+#define E_MAIL_DISPLAY_POPUP_PREFER_PLAIN_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+void e_mail_display_popup_prefer_plain_type_register (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_MAIL_DISPLAY_POPUP_PREFER_PLAIN_H */
diff --git a/modules/prefer-plain/e-mail-parser-prefer-plain.c b/modules/prefer-plain/e-mail-parser-prefer-plain.c
index 1906563..a6f0f4c 100644
--- a/modules/prefer-plain/e-mail-parser-prefer-plain.c
+++ b/modules/prefer-plain/e-mail-parser-prefer-plain.c
@@ -49,9 +49,9 @@ static void e_mail_parser_mail_extension_interface_init (EMailExtensionInterface
 static void e_mail_parser_parser_extension_interface_init (EMailParserExtensionInterface *iface);
 
 enum {
-	EPP_NORMAL,
-	EPP_PREFER,
-	EPP_TEXT
+	PREFER_HTML,
+	PREFER_PLAIN,
+	ONLY_PLAIN
 };
 
 G_DEFINE_DYNAMIC_TYPE_EXTENDED (
@@ -151,48 +151,19 @@ make_part_attachment (EMailParser *parser,
 	return parts;
 }
 
-static GSList *
-export_as_attachments (CamelMultipart *mp,
-                       EMailParser *parser,
-                       CamelMimePart *except,
-                       GString *part_id,
-                       GCancellable *cancellable)
+static void
+hide_parts (GSList *parts)
 {
-	gint i, nparts;
-	CamelMimePart *part;
-	gint len;
-	GSList *parts;
+	GSList *iter;
 
-	if (!mp || !CAMEL_IS_MULTIPART (mp))
-		return NULL;
+	for (iter = parts; iter; iter = g_slist_next (iter)) {
+		EMailPart *p = iter->data;
 
-	len = part_id->len;
-	nparts = camel_multipart_get_number (mp);
-	parts = NULL;
-	for (i = 0; i < nparts; i++) {
-		part = camel_multipart_get_part (mp, i);
-
-		if (part != except) {
-			CamelMultipart *multipart = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part);
-
-			g_string_append_printf (part_id, ".aleternative-prefer-plain.%d", i);
-			if (CAMEL_IS_MULTIPART (multipart)) {
-				parts = g_slist_concat (parts,
-						export_as_attachments (
-							multipart, parser,
-							except, part_id,
-							cancellable));
-			} else {
-				parts = g_slist_concat (parts,
-						make_part_attachment (
-							parser, part, part_id,
-							FALSE, cancellable));
-			}
-			g_string_truncate (part_id, len);
-		}
-	}
+		if (!p)
+			continue;
 
-	return parts;
+		p->is_hidden = TRUE;
+	}
 }
 
 static GSList *
@@ -204,150 +175,149 @@ empe_prefer_plain_parse (EMailParserExtension *extension,
 {
 	EMailParserPreferPlain *emp_pp;
 	CamelMultipart *mp;
-	CamelMimePart *display_part = NULL, *calendar_part = NULL;
-	gint i, nparts, partidlen, displayid = 0, calendarid = 0;
+	gint i, nparts, partidlen;
 	GSList *parts;
+	CamelContentType *ct;
 
 	emp_pp = (EMailParserPreferPlain *) extension;
 
-	/* We 'can' parse HTML as well!
-	 * The reason simply is to convert the HTML part to attachment in some
-	 * cases, otherwise we will return NULL and fallback to "normal" parser. */
-	if (camel_content_type_is (camel_mime_part_get_content_type (part), "text", "html")) {
-		GQueue *extensions;
-		EMailExtensionRegistry *reg;
+	ct = camel_mime_part_get_content_type (part);
 
-		reg = e_mail_parser_get_extension_registry (parser);
-		extensions = e_mail_extension_registry_get_for_mime_type (
-					reg, "text/html");
+	/* We can actually parse HTML, but just to discard it when
+	 * "Only ever show plain text" mode is set */
+	if (camel_content_type_is (ct, "text", "html")) {
 
-		if (emp_pp->mode != EPP_TEXT
-			|| strstr (part_id->str, ".alternative-prefer-plain.") != NULL
-			|| e_mail_part_is_inline (part, extensions)) {
+		/* Prevent recursion, fall back to next (real text/html) parser */
+		if (strstr (part_id->str, ".alternative-prefer-plain.") != NULL)
+			return NULL;
 
+		/* Not enforcing text/plain, so use real parser */
+		if (emp_pp->mode != ONLY_PLAIN)
 			return NULL;
 
-		} else if (emp_pp->show_suppressed) {
-			return make_part_attachment (
-				parser, part, part_id,
-				TRUE, cancellable);
+		/* Enforcing text/plain, but wants HTML as attachment */
+		if (emp_pp->show_suppressed) {
+			return make_part_attachment (parser, part, part_id,
+				FALSE, cancellable);
 		}
 
-		/* Return an empty item. We MUST return something, otherwise
-		 * the parser would think we have failed to parse the part
-		 * and would let a fallback extension to parse it and we don't
-		 * want that... */
-		/* FIXME: In theory we could parse it anyway and just set
-		 * is_hidden to TRUE....? */
+		/* Enforcing text/plain, does not want HTML part as attachment
+		 * so return nothing (can't return NULL as parser would fall
+		 * back to next extension) */
 		return g_slist_alloc ();
 	}
 
-	mp  = (CamelMultipart *) camel_medium_get_content ((CamelMedium *) part);
-	partidlen = part_id->len;
-
 	parts = NULL;
-	if (emp_pp->mode == EPP_NORMAL) {
-		gboolean have_plain = FALSE;
-
-		/* Try to find text/html part even when not as last and force
-		 * to show it.  Old handler will show the last part of
-		 * multipart/alternate, but if we can offer HTML, then
-		 * offer it, regardless of position in multipart.  But do
-		 * this when have only text/plain and text/html parts,
-		 * not more. */
-		nparts = camel_multipart_get_number (mp);
-		for (i = 0; i < nparts; i++) {
-			CamelContentType *content_type;
+	partidlen = part_id->len;
 
-			part = camel_multipart_get_part (mp, i);
+	mp = (CamelMultipart *) camel_medium_get_content (CAMEL_MEDIUM (part));
 
-			if (!part)
-				continue;
+	if (!CAMEL_IS_MULTIPART (mp)) {
+		return e_mail_parser_parse_part_as (
+			parser, part, part_id,
+			"application/vnd.evolution.source", cancellable);
+	}
 
-			content_type = camel_mime_part_get_content_type (part);
+	nparts = camel_multipart_get_number (mp);
+	for (i = 0; i < nparts; i++) {
 
-			if (camel_content_type_is (content_type, "text", "html")) {
-				displayid = i;
-				display_part = part;
+		CamelMimePart *sp;
+		GSList *sparts = NULL;
 
-				if (have_plain)
-					break;
-			} else if (camel_content_type_is (content_type, "text", "plain")) {
-				have_plain = TRUE;
+		sp = camel_multipart_get_part (mp, i);
+		ct = camel_mime_part_get_content_type (sp);
 
-				if (display_part)
-					break;
+		g_string_truncate (part_id, partidlen);
+		g_string_append_printf (part_id, ".alternative-prefer-plain.%d", i);
+
+		if (camel_content_type_is (ct, "text", "html")) {
+
+			if (emp_pp->mode != PREFER_HTML) {
+				if (emp_pp->show_suppressed) {
+					sparts = make_part_attachment (
+						parser, sp, part_id,
+						FALSE, cancellable);
+				} else {
+					sparts = e_mail_parser_parse_part (
+						parser, sp, part_id, cancellable);
+					hide_parts (sparts);
+				}
+			} else {
+				sparts = e_mail_parser_parse_part (
+					parser, sp, part_id, cancellable);
 			}
+
+			parts = g_slist_concat (parts, sparts);
+			continue;
 		}
 
-		if (display_part && have_plain && nparts == 2) {
-			g_string_append_printf (part_id, ".alternative-prefer-plain.%d", displayid);
-			/* FIXME Not passing a GCancellable here. */
-			parts = e_mail_parser_parse_part_as (
-				parser, display_part, part_id,
-				"text/html", cancellable);
+		if (camel_content_type_is (ct, "text", "plain")) {
 
-			g_string_truncate (part_id, partidlen);
-		} else {
-			/* Parser will automatically fallback to next extension */
-			return NULL;
+			sparts = e_mail_parser_parse_part (
+					parser, sp, part_id, cancellable);
 
+			if (emp_pp->mode == PREFER_HTML) {
+				hide_parts (sparts);
+			}
+
+			parts = g_slist_concat (parts, sparts);
+			continue;
 		}
 
-		return parts;
+		/* Always show calendar part! */
+		if (camel_content_type_is (ct, "text", "calendar") ||
+		    camel_content_type_is (ct, "text", "x-calendar")) {
 
-	} else if (!CAMEL_IS_MULTIPART (mp)) {
-		return e_mail_parser_parse_part_as (
-			parser, part, part_id,
-			"application/vnd.evolution.source", cancellable);
-	}
+			sparts = e_mail_parser_parse_part (
+					parser, sp, part_id, cancellable);
 
-	nparts = camel_multipart_get_number (mp);
-	for (i = 0; i < nparts; i++) {
-		CamelContentType *ct;
-
-		part = camel_multipart_get_part (mp, i);
-
-		if (!part)
+			parts = g_slist_concat (parts, sparts);
 			continue;
-
-		ct = camel_mime_part_get_content_type (part);
-		if (!display_part && camel_content_type_is (ct, "text", "plain")) {
-			displayid = i;
-			display_part = part;
-		} else if (!calendar_part && (camel_content_type_is (ct, "text", "calendar") || camel_content_type_is (ct, "text", "x-calendar"))) {
-			calendarid = i;
-			calendar_part = part;
 		}
-	}
 
-	/* if we found a text part, show it */
-	if (display_part) {
-		g_string_append_printf(part_id, ".alternative-prefer-plain.%d", displayid);
-		parts = g_slist_concat (parts,
-				e_mail_parser_parse_part_as (
-					parser, display_part, part_id,
-				  	"text/plain", cancellable));
+		/* Multiparts can represent a text/html with inline images or so */
+		if (camel_content_type_is (ct, "multipart", "*")) {
+			sparts = e_mail_parser_parse_part (
+					parser, sp, part_id, cancellable);
 
-		g_string_truncate (part_id, partidlen);
-	}
+			if (emp_pp->mode != PREFER_HTML) {
+				hide_parts (sparts);
+			} else {
+				GSList *iter;
+				gboolean has_html = FALSE;
+
+				/* Check whether the multipart contains a
+				 * text/html part and hide the whole multipart if
+				 * it does not. Otherwise assume that it's what
+				 * we wan't to display */
+				for (iter = sparts; iter; iter = g_slist_next (iter)) {
+					EMailPart *p = iter->data;
+					if (!p)
+						continue;
+
+					if (strstr (p->id, ".text_html") != NULL) {
+						has_html = TRUE;
+						break;
+					}
+				}
+				if (!has_html)
+					hide_parts (sparts);
+			}
+
+			parts = g_slist_concat (parts, sparts);
+			continue;
+		}
 
-	/* all other parts are attachments */
-	if (emp_pp->show_suppressed) {
-		parts = g_slist_concat (parts,
-				export_as_attachments (
-					mp, parser, display_part, part_id,
+		/* Parse everything else as an attachment */
+		sparts = e_mail_parser_parse_part (
+				parser, sp, part_id, cancellable);
+		parts = g_slist_concat (
+				parts,
+			  	e_mail_parser_wrap_as_attachment (
+					parser, sp, sparts, part_id,
 					cancellable));
-	} else if (calendar_part) {
-		g_string_append_printf(part_id, ".alternative-prefer-plain.%d", calendarid);
-		parts = g_slist_concat (parts,
-				make_part_attachment (
-					parser, calendar_part, part_id,
-					FALSE, NULL));
 	}
 
-	g_string_truncate (part_id, partidlen);
-
 	return parts;
 }
 
@@ -465,9 +435,9 @@ e_mail_parser_prefer_plain_class_init (EMailParserPreferPlainClass *class)
 			"mode",
 			"Mode",
 			NULL,
-			EPP_NORMAL,
-			EPP_TEXT,
-			EPP_NORMAL,
+			PREFER_HTML,
+			ONLY_PLAIN,
+			PREFER_HTML,
 			G_PARAM_READABLE | G_PARAM_WRITABLE));
 
 	g_object_class_install_property (
diff --git a/modules/prefer-plain/evolution-module-prefer-plain.c b/modules/prefer-plain/evolution-module-prefer-plain.c
index cb81932..9bb6450 100644
--- a/modules/prefer-plain/evolution-module-prefer-plain.c
+++ b/modules/prefer-plain/evolution-module-prefer-plain.c
@@ -17,6 +17,7 @@
  */
 
 #include "e-mail-parser-prefer-plain.h"
+#include "e-mail-display-popup-prefer-plain.h"
 
 #include <gmodule.h>
 #include <gio/gio.h>
@@ -49,6 +50,7 @@ e_module_load (GTypeModule *type_module)
 	}
 
 	e_mail_parser_prefer_plain_type_register (type_module);
+	e_mail_display_popup_prefer_plain_type_register (type_module);
 
 	g_strfreev (disabled_plugins);
 	g_object_unref (settings);
diff --git a/widgets/misc/e-web-view.c b/widgets/misc/e-web-view.c
index 20b5569..8d5d614 100644
--- a/widgets/misc/e-web-view.c
+++ b/widgets/misc/e-web-view.c
@@ -851,6 +851,8 @@ web_view_constructed (GObject *object)
 	g_object_unref (settings);
 #endif
 
+	e_extensible_load_extensions (E_EXTENSIBLE (object));
+
 	/* Chain up to parent's constructed() method. */
 	G_OBJECT_CLASS (e_web_view_parent_class)->constructed (object);
 }
@@ -1861,9 +1863,6 @@ e_web_view_init (EWebView *web_view)
 	id = "org.gnome.evolution.webview";
 	e_plugin_ui_register_manager (ui_manager, id, web_view);
 	e_plugin_ui_enable_manager (ui_manager, id);
-
-	e_extensible_load_extensions (E_EXTENSIBLE (web_view));
-
 }
 
 GtkWidget *



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