[evolution] EWebView popup menu enhancements.



commit c5e04ca04066ae2d92d3999626ef91d5d0606cab
Author: Matthew Barnes <mbarnes redhat com>
Date:   Thu Nov 12 21:27:40 2009 -0500

    EWebView popup menu enhancements.
    
    Bumps the GtkHtml dependency to 3.29.2 for gtk_html_unselect_all().

 configure.ac                                    |    2 +-
 modules/addressbook/e-book-shell-content.c      |   30 ++-
 modules/addressbook/e-book-shell-content.h      |    3 +
 modules/addressbook/e-book-shell-view-actions.c |   57 +++-
 modules/calendar/e-memo-shell-content.c         |   10 +-
 modules/calendar/e-memo-shell-view-actions.c    |   57 +++-
 modules/calendar/e-task-shell-content.c         |   10 +-
 modules/calendar/e-task-shell-view-actions.c    |   57 +++-
 plugins/mark-all-read/mark-all-read.c           |   26 +-
 shell/e-shell-utils.c                           |   29 ++
 shell/e-shell-utils.h                           |    4 +
 ui/evolution-contacts.ui                        |    3 +-
 widgets/misc/e-popup-action.c                   |  344 ++++++++++++-----
 widgets/misc/e-popup-action.h                   |   15 +-
 widgets/misc/e-web-view.c                       |  454 ++++++++++++++++++++++-
 widgets/misc/e-web-view.h                       |   21 +
 16 files changed, 926 insertions(+), 196 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 40a426a..0f38234 100644
--- a/configure.ac
+++ b/configure.ac
@@ -46,7 +46,7 @@ m4_define([gtk_minimum_version], [2.16.0])
 m4_define([eds_minimum_version], [evo_version])
 m4_define([gnome_icon_theme_minimum_version], [2.19.91])
 m4_define([gnome_desktop_minimum_version], [2.26.0])
-m4_define([libgtkhtml_minimum_version], [3.29.1])
+m4_define([libgtkhtml_minimum_version], [3.29.2])
 m4_define([gconf_minimum_version], [2.0.0])		dnl XXX Just a Guess
 m4_define([libglade_minimum_version], [2.0.0])		dnl XXX Just a Guess
 m4_define([libgnomecanvas_minimum_version], [2.0.0])	dnl XXX Just a Guess
diff --git a/modules/addressbook/e-book-shell-content.c b/modules/addressbook/e-book-shell-content.c
index 4eccc97..1c121ad 100644
--- a/modules/addressbook/e-book-shell-content.c
+++ b/modules/addressbook/e-book-shell-content.c
@@ -26,6 +26,7 @@
 #include "e-util/e-binding.h"
 #include "e-util/e-selection.h"
 #include "e-util/gconf-bridge.h"
+#include "shell/e-shell-utils.h"
 #include "widgets/misc/e-paned.h"
 
 #define E_BOOK_SHELL_CONTENT_GET_PRIVATE(obj) \
@@ -182,6 +183,10 @@ static void
 book_shell_content_constructed (GObject *object)
 {
 	EBookShellContentPrivate *priv;
+	EShell *shell;
+	EShellView *shell_view;
+	EShellWindow *shell_window;
+	EShellContent *shell_content;
 	GConfBridge *bridge;
 	GtkWidget *container;
 	GtkWidget *widget;
@@ -192,6 +197,11 @@ book_shell_content_constructed (GObject *object)
 	/* Chain up to parent's constructed() method. */
 	G_OBJECT_CLASS (parent_class)->constructed (object);
 
+	shell_content = E_SHELL_CONTENT (object);
+	shell_view = e_shell_content_get_shell_view (shell_content);
+	shell_window = e_shell_view_get_shell_window (shell_view);
+	shell = e_shell_window_get_shell (shell_window);
+
 	container = GTK_WIDGET (object);
 
 	widget = e_paned_new (GTK_ORIENTATION_VERTICAL);
@@ -199,9 +209,7 @@ book_shell_content_constructed (GObject *object)
 	priv->paned = g_object_ref (widget);
 	gtk_widget_show (widget);
 
-	e_binding_new (
-		object, "orientation",
-		widget, "orientation");
+	e_binding_new (object, "orientation", widget, "orientation");
 
 	container = widget;
 
@@ -221,9 +229,7 @@ book_shell_content_constructed (GObject *object)
 	gtk_paned_pack2 (GTK_PANED (container), widget, FALSE, FALSE);
 	gtk_widget_show (widget);
 
-	e_binding_new (
-		object, "preview-visible",
-		widget, "visible");
+	e_binding_new (object, "preview-visible", widget, "visible");
 
 	container = widget;
 
@@ -231,12 +237,13 @@ book_shell_content_constructed (GObject *object)
 	eab_contact_display_set_mode (
 		EAB_CONTACT_DISPLAY (widget),
 		EAB_CONTACT_DISPLAY_RENDER_NORMAL);
+	e_shell_configure_web_view (shell, E_WEB_VIEW (widget));
 	gtk_container_add (GTK_CONTAINER (container), widget);
 	priv->preview = g_object_ref (widget);
 	gtk_widget_show (widget);
 
 	g_signal_connect_swapped (
-		priv->preview, "send-message",
+		widget, "send-message",
 		G_CALLBACK (book_shell_content_send_message_cb), object);
 
 	/* Bind GObject properties to GConf keys. */
@@ -474,6 +481,15 @@ e_book_shell_content_set_current_view (EBookShellContent *book_shell_content,
 	g_object_notify (G_OBJECT (book_shell_content), "current-view");
 }
 
+EABContactDisplay *
+e_book_shell_content_get_preview (EBookShellContent *book_shell_content)
+{
+	g_return_val_if_fail (
+		E_IS_BOOK_SHELL_CONTENT (book_shell_content), NULL);
+
+	return EAB_CONTACT_DISPLAY (book_shell_content->priv->preview);
+}
+
 EContact *
 e_book_shell_content_get_preview_contact (EBookShellContent *book_shell_content)
 {
diff --git a/modules/addressbook/e-book-shell-content.h b/modules/addressbook/e-book-shell-content.h
index 31f8c35..138b60d 100644
--- a/modules/addressbook/e-book-shell-content.h
+++ b/modules/addressbook/e-book-shell-content.h
@@ -93,6 +93,9 @@ EAddressbookView *
 void		e_book_shell_content_set_current_view
 					(EBookShellContent *book_shell_content,
 					 EAddressbookView *addressbook_view);
+EABContactDisplay *
+		e_book_shell_content_get_preview
+					(EBookShellContent *book_shell_content);
 EContact *	e_book_shell_content_get_preview_contact
 					(EBookShellContent *book_shell_content);
 void		e_book_shell_content_set_preview_contact
diff --git a/modules/addressbook/e-book-shell-view-actions.c b/modules/addressbook/e-book-shell-view-actions.c
index 0ec4eac..495aed6 100644
--- a/modules/addressbook/e-book-shell-view-actions.c
+++ b/modules/addressbook/e-book-shell-view-actions.c
@@ -830,18 +830,11 @@ static GtkActionEntry contact_entries[] = {
 
 	{ "contact-open",
 	  NULL,
-	  N_("_Open"),
+	  N_("_Open Contact"),
 	  "<Control>o",
 	  N_("View the current contact"),
 	  G_CALLBACK (action_contact_open_cb) },
 
-	{ "contact-save-as",
-	  GTK_STOCK_SAVE_AS,
-	  N_("Save as vCard..."),
-	  NULL,
-	  N_("Save selected contacts as a vCard"),
-	  G_CALLBACK (action_contact_save_as_cb) },
-
 	{ "contact-select-all",
 	  GTK_STOCK_SELECT_ALL,
 	  NULL,
@@ -923,10 +916,6 @@ static EPopupActionEntry contact_popup_entries[] = {
 	  NULL,
 	  "contact-open" },
 
-	{ "contact-popup-save-as",
-	  NULL,
-	  "contact-save-as" },
-
 	{ "contact-popup-send-message",
 	  NULL,
 	  "contact-send-message" },
@@ -1035,11 +1024,30 @@ static EPopupActionEntry lockdown_printing_popup_entries[] = {
 	  "contact-print" }
 };
 
+static GtkActionEntry lockdown_save_to_disk_entries[] = {
+
+	{ "contact-save-as",
+	  GTK_STOCK_SAVE_AS,
+	  N_("Save as vCard..."),
+	  NULL,
+	  N_("Save selected contacts as a vCard"),
+	  G_CALLBACK (action_contact_save_as_cb) }
+};
+
+static EPopupActionEntry lockdown_save_to_disk_popup_entries[] = {
+
+	{ "contact-popup-save-as",
+	  NULL,
+	  "contact-save-as" }
+};
+
 void
 e_book_shell_view_actions_init (EBookShellView *book_shell_view)
 {
 	EShellView *shell_view;
 	EShellWindow *shell_window;
+	EBookShellContent *book_shell_content;
+	EABContactDisplay *contact_preview;
 	GtkActionGroup *action_group;
 	GConfBridge *bridge;
 	GtkAction *action;
@@ -1049,6 +1057,9 @@ e_book_shell_view_actions_init (EBookShellView *book_shell_view)
 	shell_view = E_SHELL_VIEW (book_shell_view);
 	shell_window = e_shell_view_get_shell_window (shell_view);
 
+	book_shell_content = book_shell_view->priv->book_shell_content;
+	contact_preview = e_book_shell_content_get_preview (book_shell_content);
+
 	/* Contact Actions */
 	action_group = ACTION_GROUP (CONTACTS);
 	gtk_action_group_add_actions (
@@ -1074,11 +1085,22 @@ e_book_shell_view_actions_init (EBookShellView *book_shell_view)
 	action_group = ACTION_GROUP (LOCKDOWN_PRINTING);
 	gtk_action_group_add_actions (
 		action_group, lockdown_printing_entries,
-		G_N_ELEMENTS (lockdown_printing_entries), book_shell_view);
+		G_N_ELEMENTS (lockdown_printing_entries),
+		book_shell_view);
 	e_action_group_add_popup_actions (
 		action_group, lockdown_printing_popup_entries,
 		G_N_ELEMENTS (lockdown_printing_popup_entries));
 
+	/* Lockdown Save-to-Disk Actions */
+	action_group = ACTION_GROUP (LOCKDOWN_SAVE_TO_DISK);
+	gtk_action_group_add_actions (
+		action_group, lockdown_save_to_disk_entries,
+		G_N_ELEMENTS (lockdown_save_to_disk_entries),
+		book_shell_view);
+	e_action_group_add_popup_actions (
+		action_group, lockdown_save_to_disk_popup_entries,
+		G_N_ELEMENTS (lockdown_save_to_disk_popup_entries));
+
 	/* Bind GObject properties to GConf keys. */
 
 	bridge = gconf_bridge_get ();
@@ -1107,6 +1129,15 @@ e_book_shell_view_actions_init (EBookShellView *book_shell_view)
 	e_binding_new (
 		ACTION (CONTACT_PREVIEW), "active",
 		ACTION (CONTACT_VIEW_VERTICAL), "sensitive");
+
+	e_web_view_set_open_proxy (
+		E_WEB_VIEW (contact_preview), ACTION (CONTACT_OPEN));
+
+	e_web_view_set_print_proxy (
+		E_WEB_VIEW (contact_preview), ACTION (CONTACT_PRINT));
+
+	e_web_view_set_save_as_proxy (
+		E_WEB_VIEW (contact_preview), ACTION (CONTACT_SAVE_AS));
 }
 
 void
diff --git a/modules/calendar/e-memo-shell-content.c b/modules/calendar/e-memo-shell-content.c
index 0e8d73b..b877efc 100644
--- a/modules/calendar/e-memo-shell-content.c
+++ b/modules/calendar/e-memo-shell-content.c
@@ -25,6 +25,7 @@
 
 #include "e-util/e-binding.h"
 #include "e-util/gconf-bridge.h"
+#include "shell/e-shell-utils.h"
 #include "widgets/menus/gal-view-etable.h"
 #include "widgets/misc/e-paned.h"
 
@@ -427,9 +428,7 @@ memo_shell_content_constructed (GObject *object)
 	priv->paned = g_object_ref (widget);
 	gtk_widget_show (widget);
 
-	e_binding_new (
-		object, "orientation",
-		widget, "orientation");
+	e_binding_new (object, "orientation", widget, "orientation");
 
 	container = widget;
 
@@ -447,15 +446,14 @@ memo_shell_content_constructed (GObject *object)
 	gtk_paned_pack2 (GTK_PANED (container), widget, FALSE, FALSE);
 	gtk_widget_show (widget);
 
-	e_binding_new (
-		object, "preview-visible",
-		widget, "visible");
+	e_binding_new (object, "preview-visible", widget, "visible");
 
 	container = widget;
 
 	widget = e_cal_component_preview_new ();
 	e_cal_component_preview_set_default_timezone (
 		E_CAL_COMPONENT_PREVIEW (widget), timezone);
+	e_shell_configure_web_view (shell, E_WEB_VIEW (widget));
 	gtk_container_add (GTK_CONTAINER (container), widget);
 	priv->memo_preview = g_object_ref (widget);
 	gtk_widget_show (widget);
diff --git a/modules/calendar/e-memo-shell-view-actions.c b/modules/calendar/e-memo-shell-view-actions.c
index 4ffaa51..80ebca2 100644
--- a/modules/calendar/e-memo-shell-view-actions.c
+++ b/modules/calendar/e-memo-shell-view-actions.c
@@ -682,13 +682,6 @@ static GtkActionEntry memo_entries[] = {
 	  NULL,  /* XXX Add a tooltip! */
 	  G_CALLBACK (action_memo_open_url_cb) },
 
-	{ "memo-save-as",
-	  GTK_STOCK_SAVE_AS,
-	  N_("_Save as iCalendar..."),
-	  NULL,
-	  NULL,  /* XXX Add a tooltip! */
-	  G_CALLBACK (action_memo_save_as_cb) },
-
 	/*** Menus ***/
 
 	{ "memo-preview-menu",
@@ -747,11 +740,7 @@ static EPopupActionEntry memo_popup_entries[] = {
 
 	{ "memo-popup-open-url",
 	  NULL,
-	  "memo-open-url" },
-
-	{ "memo-popup-save-as",
-	  NULL,
-	  "memo-save-as" }
+	  "memo-open-url" }
 };
 
 static GtkToggleActionEntry memo_toggle_entries[] = {
@@ -864,11 +853,30 @@ static EPopupActionEntry lockdown_printing_popup_entries[] = {
 	  "memo-print" }
 };
 
+static GtkActionEntry lockdown_save_to_disk_entries[] = {
+
+	{ "memo-save-as",
+	  GTK_STOCK_SAVE_AS,
+	  N_("_Save as iCalendar..."),
+	  NULL,
+	  NULL,  /* XXX Add a tooltip! */
+	  G_CALLBACK (action_memo_save_as_cb) },
+};
+
+static EPopupActionEntry lockdown_save_to_disk_popup_entries[] = {
+
+	{ "memo-popup-save-as",
+	  NULL,
+	  "memo-save-as" }
+};
+
 void
 e_memo_shell_view_actions_init (EMemoShellView *memo_shell_view)
 {
 	EShellView *shell_view;
 	EShellWindow *shell_window;
+	EMemoShellContent *memo_shell_content;
+	ECalComponentPreview *memo_preview;
 	GtkActionGroup *action_group;
 	GConfBridge *bridge;
 	GtkAction *action;
@@ -878,6 +886,9 @@ e_memo_shell_view_actions_init (EMemoShellView *memo_shell_view)
 	shell_view = E_SHELL_VIEW (memo_shell_view);
 	shell_window = e_shell_view_get_shell_window (shell_view);
 
+	memo_shell_content = memo_shell_view->priv->memo_shell_content;
+	memo_preview = e_memo_shell_content_get_memo_preview (memo_shell_content);
+
 	/* Memo Actions */
 	action_group = ACTION_GROUP (MEMOS);
 	gtk_action_group_add_actions (
@@ -903,11 +914,22 @@ e_memo_shell_view_actions_init (EMemoShellView *memo_shell_view)
 	action_group = ACTION_GROUP (LOCKDOWN_PRINTING);
 	gtk_action_group_add_actions (
 		action_group, lockdown_printing_entries,
-		G_N_ELEMENTS (lockdown_printing_entries), memo_shell_view);
+		G_N_ELEMENTS (lockdown_printing_entries),
+		memo_shell_view);
 	e_action_group_add_popup_actions (
 		action_group, lockdown_printing_popup_entries,
 		G_N_ELEMENTS (lockdown_printing_popup_entries));
 
+	/* Lockdown Save-to-Disk Actions */
+	action_group = ACTION_GROUP (LOCKDOWN_SAVE_TO_DISK);
+	gtk_action_group_add_actions (
+		action_group, lockdown_save_to_disk_entries,
+		G_N_ELEMENTS (lockdown_save_to_disk_entries),
+		memo_shell_view);
+	e_action_group_add_popup_actions (
+		action_group, lockdown_save_to_disk_popup_entries,
+		G_N_ELEMENTS (lockdown_save_to_disk_popup_entries));
+
 	/* Bind GObject properties to GConf keys. */
 
 	bridge = gconf_bridge_get ();
@@ -936,6 +958,15 @@ e_memo_shell_view_actions_init (EMemoShellView *memo_shell_view)
 	e_binding_new (
 		ACTION (MEMO_PREVIEW), "active",
 		ACTION (MEMO_VIEW_VERTICAL), "sensitive");
+
+	e_web_view_set_open_proxy (
+		E_WEB_VIEW (memo_preview), ACTION (MEMO_OPEN));
+
+	e_web_view_set_print_proxy (
+		E_WEB_VIEW (memo_preview), ACTION (MEMO_PRINT));
+
+	e_web_view_set_save_as_proxy (
+		E_WEB_VIEW (memo_preview), ACTION (MEMO_SAVE_AS));
 }
 
 void
diff --git a/modules/calendar/e-task-shell-content.c b/modules/calendar/e-task-shell-content.c
index 8dea4b8..9dfdd91 100644
--- a/modules/calendar/e-task-shell-content.c
+++ b/modules/calendar/e-task-shell-content.c
@@ -25,6 +25,7 @@
 
 #include "e-util/e-binding.h"
 #include "e-util/gconf-bridge.h"
+#include "shell/e-shell-utils.h"
 #include "widgets/menus/gal-view-etable.h"
 #include "widgets/misc/e-paned.h"
 
@@ -425,9 +426,7 @@ task_shell_content_constructed (GObject *object)
 	priv->paned = g_object_ref (widget);
 	gtk_widget_show (widget);
 
-	e_binding_new (
-		object, "orientation",
-		widget, "orientation");
+	e_binding_new (object, "orientation", widget, "orientation");
 
 	container = widget;
 
@@ -445,15 +444,14 @@ task_shell_content_constructed (GObject *object)
 	gtk_paned_pack2 (GTK_PANED (container), widget, FALSE, FALSE);
 	gtk_widget_show (widget);
 
-	e_binding_new (
-		object, "preview-visible",
-		widget, "visible");
+	e_binding_new (object, "preview-visible", widget, "visible");
 
 	container = widget;
 
 	widget = e_cal_component_preview_new ();
 	e_cal_component_preview_set_default_timezone (
 		E_CAL_COMPONENT_PREVIEW (widget), timezone);
+	e_shell_configure_web_view (shell, E_WEB_VIEW (widget));
 	gtk_container_add (GTK_CONTAINER (container), widget);
 	priv->task_preview = g_object_ref (widget);
 	gtk_widget_show (widget);
diff --git a/modules/calendar/e-task-shell-view-actions.c b/modules/calendar/e-task-shell-view-actions.c
index 07558bf..e5063c1 100644
--- a/modules/calendar/e-task-shell-view-actions.c
+++ b/modules/calendar/e-task-shell-view-actions.c
@@ -829,13 +829,6 @@ static GtkActionEntry task_entries[] = {
 	  N_("Delete completed tasks"),
 	  G_CALLBACK (action_task_purge_cb) },
 
-	{ "task-save-as",
-	  GTK_STOCK_SAVE_AS,
-	  N_("_Save as iCalendar..."),
-	  NULL,
-	  NULL,  /* XXX Add a tooltip! */
-	  G_CALLBACK (action_task_save_as_cb) },
-
 	/*** Menus ***/
 
 	{ "task-actions-menu",
@@ -913,11 +906,7 @@ static EPopupActionEntry task_popup_entries[] = {
 
 	{ "task-popup-open-url",
 	  NULL,
-	  "task-open-url" },
-
-	{ "task-popup-save-as",
-	  NULL,
-	  "task-save-as" },
+	  "task-open-url" }
 };
 
 static GtkToggleActionEntry task_toggle_entries[] = {
@@ -1065,11 +1054,30 @@ static EPopupActionEntry lockdown_printing_popup_entries[] = {
 	  "task-print" }
 };
 
+static GtkActionEntry lockdown_save_to_disk_entries[] = {
+
+	{ "task-save-as",
+	  GTK_STOCK_SAVE_AS,
+	  N_("_Save as iCalendar..."),
+	  NULL,
+	  NULL,  /* XXX Add a tooltip! */
+	  G_CALLBACK (action_task_save_as_cb) }
+};
+
+static EPopupActionEntry lockdown_save_to_disk_popup_entries[] = {
+
+	{ "task-popup-save-as",
+	  NULL,
+	  "task-save-as" },
+};
+
 void
 e_task_shell_view_actions_init (ETaskShellView *task_shell_view)
 {
 	EShellView *shell_view;
 	EShellWindow *shell_window;
+	ETaskShellContent *task_shell_content;
+	ECalComponentPreview *task_preview;
 	GtkActionGroup *action_group;
 	GConfBridge *bridge;
 	GtkAction *action;
@@ -1079,6 +1087,9 @@ e_task_shell_view_actions_init (ETaskShellView *task_shell_view)
 	shell_view = E_SHELL_VIEW (task_shell_view);
 	shell_window = e_shell_view_get_shell_window (shell_view);
 
+	task_shell_content = task_shell_view->priv->task_shell_content;
+	task_preview = e_task_shell_content_get_task_preview (task_shell_content);
+
 	/* Task Actions */
 	action_group = ACTION_GROUP (TASKS);
 	gtk_action_group_add_actions (
@@ -1104,11 +1115,22 @@ e_task_shell_view_actions_init (ETaskShellView *task_shell_view)
 	action_group = ACTION_GROUP (LOCKDOWN_PRINTING);
 	gtk_action_group_add_actions (
 		action_group, lockdown_printing_entries,
-		G_N_ELEMENTS (lockdown_printing_entries), task_shell_view);
+		G_N_ELEMENTS (lockdown_printing_entries),
+		task_shell_view);
 	e_action_group_add_popup_actions (
 		action_group, lockdown_printing_popup_entries,
 		G_N_ELEMENTS (lockdown_printing_popup_entries));
 
+	/* Lockdown Save-to-Disk Actions */
+	action_group = ACTION_GROUP (LOCKDOWN_SAVE_TO_DISK);
+	gtk_action_group_add_actions (
+		action_group, lockdown_save_to_disk_entries,
+		G_N_ELEMENTS (lockdown_save_to_disk_entries),
+		task_shell_view);
+	e_action_group_add_popup_actions (
+		action_group, lockdown_save_to_disk_popup_entries,
+		G_N_ELEMENTS (lockdown_save_to_disk_popup_entries));
+
 	/* Bind GObject properties to GConf keys. */
 
 	bridge = gconf_bridge_get ();
@@ -1137,6 +1159,15 @@ e_task_shell_view_actions_init (ETaskShellView *task_shell_view)
 	e_binding_new (
 		ACTION (TASK_PREVIEW), "active",
 		ACTION (TASK_VIEW_VERTICAL), "sensitive");
+
+	e_web_view_set_open_proxy (
+		E_WEB_VIEW (task_preview), ACTION (TASK_OPEN));
+
+	e_web_view_set_print_proxy (
+		E_WEB_VIEW (task_preview), ACTION (TASK_PRINT));
+
+	e_web_view_set_save_as_proxy (
+		E_WEB_VIEW (task_preview), ACTION (TASK_SAVE_AS));
 }
 
 void
diff --git a/plugins/mark-all-read/mark-all-read.c b/plugins/mark-all-read/mark-all-read.c
index 008cc5a..cb36dc0 100644
--- a/plugins/mark-all-read/mark-all-read.c
+++ b/plugins/mark-all-read/mark-all-read.c
@@ -355,7 +355,9 @@ update_actions_cb (EShellView *shell_view, gpointer user_data)
 	EShellSidebar *shell_sidebar;
 	EMFolderTree *folder_tree;
 	gchar *folder_uri;
-	gboolean has_unread = FALSE, applicable = FALSE;
+	gboolean has_unread = FALSE;
+	gboolean applicable = FALSE;
+	gboolean visible;
 
 	g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
 
@@ -368,13 +370,20 @@ update_actions_cb (EShellView *shell_view, gpointer user_data)
 
 		model = em_folder_tree_model_get_default ();
 		if (model) {
-			GtkTreeRowReference *reference = em_folder_tree_model_lookup_uri (model, folder_uri);
+			GtkTreeRowReference *reference;
+
+			reference = em_folder_tree_model_lookup_uri (
+				model, folder_uri);
 			if (reference != NULL) {
-				GtkTreePath *path = gtk_tree_row_reference_get_path (reference);
+				GtkTreePath *path;
 				GtkTreeIter iter;
 
-				gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
-				has_unread_mail (GTK_TREE_MODEL (model), &iter, TRUE, &has_unread, &applicable);
+				path = gtk_tree_row_reference_get_path (reference);
+				gtk_tree_model_get_iter (
+					GTK_TREE_MODEL (model), &iter, path);
+				has_unread_mail (
+					GTK_TREE_MODEL (model), &iter,
+					TRUE, &has_unread, &applicable);
 				gtk_tree_path_free (path);
 			}
 		}
@@ -386,7 +395,8 @@ update_actions_cb (EShellView *shell_view, gpointer user_data)
 	action = gtk_action_group_get_action (action_group, entries[0].name);
 	g_return_if_fail (action != NULL);
 
-	gtk_action_set_sensitive (action, has_unread && applicable);
+	visible = has_unread && applicable;
+	gtk_action_set_visible (action, visible);
 
 	g_free (folder_uri);
 	g_object_unref (folder_tree);
@@ -407,7 +417,9 @@ e_plugin_ui_init (GtkUIManager *ui_manager,
 		action_group, entries,
 		G_N_ELEMENTS (entries), shell_view);
 
-	g_signal_connect (shell_view, "update-actions", G_CALLBACK (update_actions_cb), NULL);
+	g_signal_connect (
+		shell_view, "update-actions",
+		G_CALLBACK (update_actions_cb), NULL);
 
 	return TRUE;
 }
diff --git a/shell/e-shell-utils.c b/shell/e-shell-utils.c
index 570f15b..c9c887c 100644
--- a/shell/e-shell-utils.c
+++ b/shell/e-shell-utils.c
@@ -23,9 +23,38 @@
 
 #include <glib/gi18n-lib.h>
 
+#include "e-util/e-binding.h"
 #include "widgets/misc/e-import-assistant.h"
 
 /**
+ * e_shell_configure_web_view:
+ * @shell: an #EShell
+ * @web_view: an #EWebView
+ *
+ * Adds shell integration to @web_view.  In particular, it configures
+ * @web_view to honor the printing and save-to-disk lockdown options.
+ **/
+void
+e_shell_configure_web_view (EShell *shell,
+                            EWebView *web_view)
+{
+	EShellSettings *shell_settings;
+
+	g_return_if_fail (E_IS_SHELL (shell));
+	g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+	shell_settings = e_shell_get_shell_settings (shell);
+
+	e_binding_new (
+		shell_settings, "disable-printing",
+		web_view, "disable-printing");
+
+	e_binding_new (
+		shell_settings, "disable-save-to-disk",
+		web_view, "disable-save-to-disk");
+}
+
+/**
  * e_shell_run_open_dialog:
  * @shell: an #EShell
  * @title: file chooser dialog title
diff --git a/shell/e-shell-utils.h b/shell/e-shell-utils.h
index 24b44a9..6e26256 100644
--- a/shell/e-shell-utils.h
+++ b/shell/e-shell-utils.h
@@ -29,9 +29,13 @@
 #define E_SHELL_UTILS_H
 
 #include <shell/e-shell.h>
+#include <misc/e-web-view.h>
 
 G_BEGIN_DECLS
 
+void		e_shell_configure_web_view	(EShell *shell,
+						 EWebView *web_view);
+
 GFile *		e_shell_run_open_dialog		(EShell *shell,
 						 const gchar *title,
 						 GtkCallback customize_func,
diff --git a/ui/evolution-contacts.ui b/ui/evolution-contacts.ui
index 6fb31b4..2b95d86 100644
--- a/ui/evolution-contacts.ui
+++ b/ui/evolution-contacts.ui
@@ -65,11 +65,10 @@
     <menuitem action='address-book-popup-properties'/>
   </popup>
   <popup name='contact-popup'>
-    <menuitem action='contact-popup-open'/>
-    <separator/>
     <menuitem action='contact-new'/>
     <menuitem action='contact-new-list'/>
     <separator/>
+    <menuitem action='contact-popup-open'/>
     <menuitem action='contact-popup-save-as'/>
     <menuitem action='contact-popup-forward'/>
     <menuitem action='contact-popup-send-message'/>
diff --git a/widgets/misc/e-popup-action.c b/widgets/misc/e-popup-action.c
index e856a1f..5f060a4 100644
--- a/widgets/misc/e-popup-action.c
+++ b/widgets/misc/e-popup-action.c
@@ -30,23 +30,110 @@
 
 enum {
 	PROP_0,
-	PROP_SOURCE
+	PROP_RELATED_ACTION,
+	PROP_USE_ACTION_APPEARANCE
 };
 
 struct _EPopupActionPrivate {
-	GtkAction *source;
+	GtkAction *related_action;
+	gboolean use_action_appearance;
+	gulong activate_handler_id;
+	gulong notify_handler_id;
 };
 
 static gpointer parent_class;
 
 static void
-popup_action_set_source (EPopupAction *popup_action,
-                         GtkAction *source)
+popup_action_notify_cb (GtkAction *action,
+                        GParamSpec *pspec,
+                        GtkActivatable *activatable)
 {
-	g_return_if_fail (popup_action->priv->source == NULL);
-	g_return_if_fail (GTK_IS_ACTION (source));
+	GtkActivatableIface *iface;
 
-	popup_action->priv->source = g_object_ref (source);
+	iface = GTK_ACTIVATABLE_GET_IFACE (activatable);
+	g_return_if_fail (iface->update != NULL);
+
+	iface->update (activatable, action, pspec->name);
+}
+
+static GtkAction *
+popup_action_get_related_action (EPopupAction *popup_action)
+{
+	return popup_action->priv->related_action;
+}
+
+static void
+popup_action_set_related_action (EPopupAction *popup_action,
+                                 GtkAction *related_action)
+{
+	GtkActivatable *activatable;
+
+	/* Do not call gtk_activatable_do_set_related_action() because
+	 * it assumes the activatable object is a widget and tries to add
+	 * it to the related actions's proxy list.  Instead we'll just do
+	 * the relevant steps manually. */
+
+	activatable = GTK_ACTIVATABLE (popup_action);
+
+	if (related_action == popup_action->priv->related_action)
+		return;
+
+	if (related_action != NULL)
+		g_object_ref (related_action);
+
+	if (popup_action->priv->related_action != NULL) {
+		g_signal_handler_disconnect (
+			popup_action,
+			popup_action->priv->activate_handler_id);
+		g_signal_handler_disconnect (
+			popup_action->priv->related_action,
+			popup_action->priv->notify_handler_id);
+		popup_action->priv->activate_handler_id = 0;
+		popup_action->priv->notify_handler_id = 0;
+		g_object_unref (popup_action->priv->related_action);
+	}
+
+	popup_action->priv->related_action = related_action;
+
+	if (related_action != NULL) {
+		popup_action->priv->activate_handler_id =
+			g_signal_connect_swapped (
+				popup_action, "activate",
+				G_CALLBACK (gtk_action_activate),
+				related_action);
+		popup_action->priv->notify_handler_id =
+			g_signal_connect (
+				related_action, "notify",
+				G_CALLBACK (popup_action_notify_cb),
+				popup_action);
+		gtk_activatable_sync_action_properties (
+			activatable, related_action);
+	} else
+		gtk_action_set_visible (GTK_ACTION (popup_action), FALSE);
+
+	g_object_notify (G_OBJECT (popup_action), "related-action");
+}
+
+static gboolean
+popup_action_get_use_action_appearance (EPopupAction *popup_action)
+{
+	return popup_action->priv->use_action_appearance;
+}
+
+static void
+popup_action_set_use_action_appearance (EPopupAction *popup_action,
+                                        gboolean use_action_appearance)
+{
+	GtkActivatable *activatable;
+	GtkAction *related_action;
+
+	popup_action->priv->use_action_appearance = use_action_appearance;
+
+	g_object_notify (G_OBJECT (popup_action), "use-action-appearance");
+
+	activatable = GTK_ACTIVATABLE (popup_action);
+	related_action = popup_action_get_related_action (popup_action);
+	gtk_activatable_sync_action_properties (activatable, related_action);
 }
 
 static void
@@ -56,11 +143,17 @@ popup_action_set_property (GObject *object,
                            GParamSpec *pspec)
 {
 	switch (property_id) {
-		case PROP_SOURCE:
-			popup_action_set_source (
+		case PROP_RELATED_ACTION:
+			popup_action_set_related_action (
 				E_POPUP_ACTION (object),
 				g_value_get_object (value));
 			return;
+
+		case PROP_USE_ACTION_APPEARANCE:
+			popup_action_set_use_action_appearance (
+				E_POPUP_ACTION (object),
+				g_value_get_boolean (value));
+			return;
 	}
 
 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -73,9 +166,17 @@ popup_action_get_property (GObject *object,
                            GParamSpec *pspec)
 {
 	switch (property_id) {
-		case PROP_SOURCE:
+		case PROP_RELATED_ACTION:
 			g_value_set_object (
-				value, e_popup_action_get_source (
+				value,
+				popup_action_get_related_action (
+				E_POPUP_ACTION (object)));
+			return;
+
+		case PROP_USE_ACTION_APPEARANCE:
+			g_value_set_boolean (
+				value,
+				popup_action_get_use_action_appearance (
 				E_POPUP_ACTION (object)));
 			return;
 	}
@@ -90,9 +191,15 @@ popup_action_dispose (GObject *object)
 
 	priv = E_POPUP_ACTION_GET_PRIVATE (object);
 
-	if (priv->source != NULL) {
-		g_object_unref (priv->source);
-		priv->source = NULL;
+	if (priv->related_action != NULL) {
+		g_signal_handler_disconnect (
+			object,
+			priv->activate_handler_id);
+		g_signal_handler_disconnect (
+			priv->related_action,
+			priv->notify_handler_id);
+		g_object_unref (priv->related_action);
+		priv->related_action = NULL;
 	}
 
 	/* Chain up to parent's dispose() method. */
@@ -100,56 +207,97 @@ popup_action_dispose (GObject *object)
 }
 
 static void
-popup_action_constructed (GObject *object)
+popup_action_update (GtkActivatable *activatable,
+                     GtkAction *action,
+                     const gchar *property_name)
 {
-	EPopupActionPrivate *priv;
-	GObject *source;
-	gchar *icon_name;
-	gchar *label;
-	gchar *stock_id;
-	gchar *tooltip;
+	GObjectClass *class;
+	GParamSpec *pspec;
+	GValue *value;
 
-	priv = E_POPUP_ACTION_GET_PRIVATE (object);
+	/* Ignore "action-group" changes" */
+	if (strcmp (property_name, "action-group") == 0)
+		return;
 
-	source = G_OBJECT (priv->source);
+	/* Ignore "visible" changes. */
+	if (strcmp (property_name, "visible") == 0)
+		return;
 
-	g_object_get (
-		object, "icon-name", &icon_name, "label", &label,
-		"stock-id", &stock_id, "tooltip", &tooltip, NULL);
+	value = g_slice_new0 (GValue);
+	class = G_OBJECT_GET_CLASS (action);
+	pspec = g_object_class_find_property (class, property_name);
+	g_value_init (value, pspec->value_type);
 
-	if (label == NULL)
-		e_binding_new (source, "label", object, "label");
+	g_object_get_property (G_OBJECT (action), property_name, value);
 
-	if (tooltip == NULL)
-		e_binding_new (source, "tooltip", object, "tooltip");
+	if (strcmp (property_name, "sensitive") == 0)
+		property_name = "visible";
+	else if (!gtk_activatable_get_use_action_appearance (activatable))
+		goto exit;
 
-	if (icon_name == NULL && stock_id == NULL) {
-		g_free (icon_name);
-		g_free (stock_id);
+	g_object_set_property (G_OBJECT (activatable), property_name, value);
 
-		g_object_get (
-			source, "icon-name", &icon_name,
-			"stock-id", &stock_id, NULL);
+exit:
+	g_value_unset (value);
+	g_slice_free (GValue, value);
+}
 
-		if (icon_name == NULL) {
-			e_binding_new (
-				source, "icon-name", object, "icon-name");
-			e_binding_new (
-				source, "stock-id", object, "stock-id");
-		} else {
-			e_binding_new (
-				source, "stock-id", object, "stock-id");
-			e_binding_new (
-				source, "icon-name", object, "icon-name");
-		}
-	}
+static void
+popup_action_sync_action_properties (GtkActivatable *activatable,
+                                     GtkAction *action)
+{
+	if (action == NULL)
+		return;
+
+	/* XXX GTK+ 2.18 is still missing accessor functions for
+	 *     "hide-if-empty" and "visible-overflown" properties.
+	 *     These are rarely used so we'll skip them for now. */
+
+	/* A popup action is never shown as insensitive. */
+	gtk_action_set_sensitive (GTK_ACTION (activatable), TRUE);
+
+	gtk_action_set_visible (
+		GTK_ACTION (activatable),
+		gtk_action_get_sensitive (action));
+
+	gtk_action_set_visible_horizontal (
+		GTK_ACTION (activatable),
+		gtk_action_get_visible_horizontal (action));
+
+	gtk_action_set_visible_vertical (
+		GTK_ACTION (activatable),
+		gtk_action_get_visible_vertical (action));
+
+	gtk_action_set_is_important (
+		GTK_ACTION (activatable),
+		gtk_action_get_is_important (action));
 
-	e_binding_new (source, "sensitive", object, "visible");
+	if (!gtk_activatable_get_use_action_appearance (activatable))
+		return;
 
-	g_free (icon_name);
-	g_free (label);
-	g_free (stock_id);
-	g_free (tooltip);
+	gtk_action_set_label (
+		GTK_ACTION (activatable),
+		gtk_action_get_label (action));
+
+	gtk_action_set_short_label (
+		GTK_ACTION (activatable),
+		gtk_action_get_short_label (action));
+
+	gtk_action_set_tooltip (
+		GTK_ACTION (activatable),
+		gtk_action_get_tooltip (action));
+
+	gtk_action_set_stock_id (
+		GTK_ACTION (activatable),
+		gtk_action_get_stock_id (action));
+
+	gtk_action_set_gicon (
+		GTK_ACTION (activatable),
+		gtk_action_get_gicon (action));
+
+	gtk_action_set_icon_name (
+		GTK_ACTION (activatable),
+		gtk_action_get_icon_name (action));
 }
 
 static void
@@ -165,22 +313,32 @@ popup_action_class_init (EPopupActionClass *class)
 	object_class->get_property = popup_action_get_property;
 	object_class->dispose = popup_action_dispose;
 
-	g_object_class_install_property (
+	g_object_class_override_property (
+		object_class,
+		PROP_RELATED_ACTION,
+		"related-action");
+
+	g_object_class_override_property (
 		object_class,
-		PROP_SOURCE,
-		g_param_spec_object (
-			"source",
-			_("Source Action"),
-			_("The source action to proxy"),
-			GTK_TYPE_ACTION,
-			G_PARAM_READWRITE |
-			G_PARAM_CONSTRUCT_ONLY));
+		PROP_USE_ACTION_APPEARANCE,
+		"use-action-appearance");
+}
+
+static void
+popup_action_iface_init (GtkActivatableIface *iface)
+{
+	iface->update = popup_action_update;
+	iface->sync_action_properties = popup_action_sync_action_properties;
 }
 
 static void
 popup_action_init (EPopupAction *popup_action)
 {
 	popup_action->priv = E_POPUP_ACTION_GET_PRIVATE (popup_action);
+	popup_action->priv->use_action_appearance = TRUE;
+
+	/* Remain invisible until we have a related action. */
+	gtk_action_set_visible (GTK_ACTION (popup_action), FALSE);
 }
 
 GType
@@ -202,43 +360,28 @@ e_popup_action_get_type (void)
 			NULL   /* value_table */
 		};
 
+		static const GInterfaceInfo iface_info = {
+			(GInterfaceInitFunc) popup_action_iface_init,
+			(GInterfaceFinalizeFunc) NULL,
+			NULL   /* interface_data */
+		};
+
 		type = g_type_register_static (
 			GTK_TYPE_ACTION, "EPopupAction", &type_info, 0);
+
+		g_type_add_interface_static (
+			type, GTK_TYPE_ACTIVATABLE, &iface_info);
 	}
 
 	return type;
 }
 
 EPopupAction *
-e_popup_action_new (const gchar *name,
-                    const gchar *label,
-                    GtkAction *source)
+e_popup_action_new (const gchar *name)
 {
-	EPopupAction *popup_action;
-
 	g_return_val_if_fail (name != NULL, NULL);
-	g_return_val_if_fail (GTK_IS_ACTION (source), NULL);
 
-	popup_action = g_object_new (
-		E_TYPE_POPUP_ACTION, "name", name,
-		"label", label, "source", source, NULL);
-
-	/* XXX This is a hack to work around the fact that GtkAction's
-	 *     "label" and "tooltip" properties are not constructor
-	 *     properties, even though they're supplied upfront.
-	 *
-	 *     See: http://bugzilla.gnome.org/show_bug.cgi?id=568334 */
-	popup_action_constructed (G_OBJECT (popup_action));
-
-	return popup_action;
-}
-
-GtkAction *
-e_popup_action_get_source (EPopupAction *popup_action)
-{
-	g_return_val_if_fail (E_IS_POPUP_ACTION (popup_action), NULL);
-
-	return popup_action->priv->source;
+	return g_object_new (E_TYPE_POPUP_ACTION, "name", name, NULL);
 }
 
 void
@@ -252,30 +395,31 @@ e_action_group_add_popup_actions (GtkActionGroup *action_group,
 
 	for (ii = 0; ii < n_entries; ii++) {
 		EPopupAction *popup_action;
-		GtkAction *source;
+		GtkAction *related_action;
 		const gchar *label;
 
 		label = gtk_action_group_translate_string (
 			action_group, entries[ii].label);
 
-		source = gtk_action_group_get_action (
-			action_group, entries[ii].source);
+		related_action = gtk_action_group_get_action (
+			action_group, entries[ii].related);
 
-		if (source == NULL) {
+		if (related_action == NULL) {
 			g_warning (
-				"Source action '%s' not found in "
-				"action group '%s'", entries[ii].source,
+				"Related action '%s' not found in "
+				"action group '%s'", entries[ii].related,
 				gtk_action_group_get_name (action_group));
 			continue;
 		}
 
-		popup_action = e_popup_action_new (
-			entries[ii].name, label, source);
+		popup_action = e_popup_action_new (entries[ii].name);
+
+		gtk_activatable_set_related_action (
+			GTK_ACTIVATABLE (popup_action), related_action);
 
-		g_signal_connect_swapped (
-			popup_action, "activate",
-			G_CALLBACK (gtk_action_activate),
-			popup_action->priv->source);
+		if (label != NULL && *label != '\0')
+			gtk_action_set_label (
+				GTK_ACTION (popup_action), label);
 
 		gtk_action_group_add_action (
 			action_group, GTK_ACTION (popup_action));
diff --git a/widgets/misc/e-popup-action.h b/widgets/misc/e-popup-action.h
index d19971f..0246937 100644
--- a/widgets/misc/e-popup-action.h
+++ b/widgets/misc/e-popup-action.h
@@ -28,9 +28,9 @@
  * To use:
  *
  * Create an array of EPopupActionEntry structs.  Add the main menu actions
- * that serve as "sources" for the popup actions to an action group first.
- * Then pass the same action group and the EPopupActionEntry array to
- * e_action_group_add_popup_actions() to add popup actions.
+ * that serve as related actions for the popup actions to an action group
+ * first.  Then pass the same action group and the EPopupActionEntry array
+ * to e_action_group_add_popup_actions() to add popup actions.
  */
 
 #ifndef E_POPUP_ACTION_H
@@ -75,15 +75,12 @@ struct _EPopupActionClass {
 
 struct _EPopupActionEntry {
 	const gchar *name;
-	const gchar *label;	/* optional: overrides the source action */
-	const gchar *source;	/* name of the source action */
+	const gchar *label;	/* optional: overrides the related action */
+	const gchar *related;	/* name of the related action */
 };
 
 GType		e_popup_action_get_type		(void);
-EPopupAction *	e_popup_action_new		(const gchar *name,
-						 const gchar *label,
-						 GtkAction *source);
-GtkAction *	e_popup_action_get_source	(EPopupAction *popup_action);
+EPopupAction *	e_popup_action_new		(const gchar *name);
 
 void		e_action_group_add_popup_actions
 						(GtkActionGroup *action_group,
diff --git a/widgets/misc/e-web-view.c b/widgets/misc/e-web-view.c
index 3a3e62b..5d56735 100644
--- a/widgets/misc/e-web-view.c
+++ b/widgets/misc/e-web-view.c
@@ -29,8 +29,11 @@
 #include <camel/camel-url.h>
 
 #include "e-util/e-util.h"
+#include "e-util/e-binding.h"
 #include "e-util/e-plugin-ui.h"
 
+#include "e-popup-action.h"
+
 #define E_WEB_VIEW_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE \
 	((obj), E_TYPE_WEB_VIEW, EWebViewPrivate))
@@ -41,6 +44,14 @@ struct _EWebViewPrivate {
 	GList *requests;
 	GtkUIManager *ui_manager;
 	gchar *selected_uri;
+
+	GtkAction *open_proxy;
+	GtkAction *print_proxy;
+	GtkAction *save_as_proxy;
+
+	/* Lockdown Options */
+	guint disable_printing     : 1;
+	guint disable_save_to_disk : 1;
 };
 
 struct _EWebViewRequest {
@@ -56,6 +67,11 @@ enum {
 	PROP_0,
 	PROP_ANIMATE,
 	PROP_CARET_MODE,
+	PROP_DISABLE_PRINTING,
+	PROP_DISABLE_SAVE_TO_DISK,
+	PROP_OPEN_PROXY,
+	PROP_PRINT_PROXY,
+	PROP_SAVE_AS_PROXY,
 	PROP_SELECTED_URI
 };
 
@@ -73,15 +89,22 @@ static guint signals[LAST_SIGNAL];
 static const gchar *ui =
 "<ui>"
 "  <popup name='context'>"
+"    <menuitem action='clipboard-copy'/>"
+"    <separator/>"
 "    <placeholder name='custom-actions-1'>"
+"      <menuitem action='open'/>"
+"      <menuitem action='save-as'/>"
 "      <menuitem action='http-open'/>"
 "      <menuitem action='send-message'/>"
+"      <menuitem action='print'/>"
 "    </placeholder>"
 "    <placeholder name='custom-actions-2'>"
 "      <menuitem action='uri-copy'/>"
 "      <menuitem action='mailto-copy'/>"
 "    </placeholder>"
 "    <placeholder name='custom-actions-3'/>"
+"    <separator/>"
+"    <menuitem action='select-all'/>"
 "  </popup>"
 "</ui>";
 
@@ -217,6 +240,13 @@ web_view_request_read_cb (GFile *file,
 }
 
 static void
+action_clipboard_copy_cb (GtkAction *action,
+                          EWebView *web_view)
+{
+	e_web_view_clipboard_copy (web_view);
+}
+
+static void
 action_http_open_cb (GtkAction *action,
                      EWebView *web_view)
 {
@@ -266,6 +296,13 @@ action_mailto_copy_cb (GtkAction *action,
 }
 
 static void
+action_select_all_cb (GtkAction *action,
+                      EWebView *web_view)
+{
+	e_web_view_select_all (web_view);
+}
+
+static void
 action_send_message_cb (GtkAction *action,
                         EWebView *web_view)
 {
@@ -333,6 +370,26 @@ static GtkActionEntry mailto_entries[] = {
 	  G_CALLBACK (action_send_message_cb) }
 };
 
+static GtkActionEntry selection_entries[] = {
+
+	{ "clipboard-copy",
+	  GTK_STOCK_COPY,
+	  NULL,
+	  NULL,
+	  N_("Copy the selection to the clipboard"),
+	  G_CALLBACK (action_clipboard_copy_cb) },
+};
+
+static GtkActionEntry standard_entries[] = {
+
+	{ "select-all",
+	  GTK_STOCK_SELECT_ALL,
+	  NULL,
+	  NULL,
+	  N_("Select all text and images"),
+	  G_CALLBACK (action_select_all_cb) }
+};
+
 static gboolean
 web_view_button_press_event_cb (EWebView *web_view,
                                 GdkEventButton *event,
@@ -420,6 +477,36 @@ web_view_set_property (GObject *object,
 				g_value_get_boolean (value));
 			return;
 
+		case PROP_DISABLE_PRINTING:
+			e_web_view_set_disable_printing (
+				E_WEB_VIEW (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_DISABLE_SAVE_TO_DISK:
+			e_web_view_set_disable_save_to_disk (
+				E_WEB_VIEW (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_OPEN_PROXY:
+			e_web_view_set_open_proxy (
+				E_WEB_VIEW (object),
+				g_value_get_object (value));
+			return;
+
+		case PROP_PRINT_PROXY:
+			e_web_view_set_print_proxy (
+				E_WEB_VIEW (object),
+				g_value_get_object (value));
+			return;
+
+		case PROP_SAVE_AS_PROXY:
+			e_web_view_set_save_as_proxy (
+				E_WEB_VIEW (object),
+				g_value_get_object (value));
+			return;
+
 		case PROP_SELECTED_URI:
 			e_web_view_set_selected_uri (
 				E_WEB_VIEW (object),
@@ -449,6 +536,36 @@ web_view_get_property (GObject *object,
 				E_WEB_VIEW (object)));
 			return;
 
+		case PROP_DISABLE_PRINTING:
+			g_value_set_boolean (
+				value, e_web_view_get_disable_printing (
+				E_WEB_VIEW (object)));
+			return;
+
+		case PROP_DISABLE_SAVE_TO_DISK:
+			g_value_set_boolean (
+				value, e_web_view_get_disable_save_to_disk (
+				E_WEB_VIEW (object)));
+			return;
+
+		case PROP_OPEN_PROXY:
+			g_value_set_object (
+				value, e_web_view_get_open_proxy (
+				E_WEB_VIEW (object)));
+			return;
+
+		case PROP_PRINT_PROXY:
+			g_value_set_object (
+				value, e_web_view_get_print_proxy (
+				E_WEB_VIEW (object)));
+			return;
+
+		case PROP_SAVE_AS_PROXY:
+			g_value_set_object (
+				value, e_web_view_get_save_as_proxy (
+				E_WEB_VIEW (object)));
+			return;
+
 		case PROP_SELECTED_URI:
 			g_value_set_string (
 				value, e_web_view_get_selected_uri (
@@ -471,6 +588,21 @@ web_view_dispose (GObject *object)
 		priv->ui_manager = NULL;
 	}
 
+	if (priv->open_proxy != NULL) {
+		g_object_unref (priv->open_proxy);
+		priv->open_proxy = NULL;
+	}
+
+	if (priv->print_proxy != NULL) {
+		g_object_unref (priv->print_proxy);
+		priv->print_proxy = NULL;
+	}
+
+	if (priv->save_as_proxy != NULL) {
+		g_object_unref (priv->save_as_proxy);
+		priv->save_as_proxy = NULL;
+	}
+
 	/* Chain up to parent's dispose() method. */
 	G_OBJECT_CLASS (parent_class)->dispose (object);
 }
@@ -639,8 +771,8 @@ web_view_popup_event (EWebView *web_view,
                       GdkEventButton *event,
                       const gchar *uri)
 {
-	if (uri == NULL)
-		return FALSE;
+	if (uri != NULL)
+		e_web_view_unselect_all (web_view);
 
 	e_web_view_set_selected_uri (web_view, uri);
 	e_web_view_show_popup_menu (web_view, event, NULL, NULL);
@@ -661,40 +793,68 @@ web_view_stop_loading (EWebView *web_view)
 static void
 web_view_update_actions (EWebView *web_view)
 {
-	CamelURL *curl;
 	GtkActionGroup *action_group;
-	gboolean scheme_is_http;
-	gboolean scheme_is_mailto;
-	gboolean uri_is_valid;
+	gboolean have_selection;
+	gboolean scheme_is_http = FALSE;
+	gboolean scheme_is_mailto = FALSE;
+	gboolean uri_is_valid = FALSE;
 	gboolean visible;
+	const gchar *group_name;
 	const gchar *uri;
 
 	uri = e_web_view_get_selected_uri (web_view);
-	g_return_if_fail (uri != NULL);
+	have_selection = e_web_view_is_selection_active (web_view);
 
 	/* Parse the URI early so we know if the actions will work. */
-	curl = camel_url_new (uri, NULL);
-	uri_is_valid = (curl != NULL);
-	camel_url_free (curl);
+	if (uri != NULL) {
+		CamelURL *curl;
+
+		curl = camel_url_new (uri, NULL);
+		uri_is_valid = (curl != NULL);
+		camel_url_free (curl);
 
-	scheme_is_http =
-		(g_ascii_strncasecmp (uri, "http:", 5) == 0) ||
-		(g_ascii_strncasecmp (uri, "https:", 6) == 0);
+		scheme_is_http =
+			(g_ascii_strncasecmp (uri, "http:", 5) == 0) ||
+			(g_ascii_strncasecmp (uri, "https:", 6) == 0);
 
-	scheme_is_mailto =
-		(g_ascii_strncasecmp (uri, "mailto:";, 7) == 0);
+		scheme_is_mailto =
+			(g_ascii_strncasecmp (uri, "mailto:";, 7) == 0);
+	}
 
 	/* Allow copying the URI even if it's malformed. */
-	visible = !scheme_is_mailto;
-	action_group = e_web_view_get_action_group (web_view, "uri");
+	group_name = "uri";
+	visible = (uri != NULL) && !scheme_is_mailto;
+	action_group = e_web_view_get_action_group (web_view, group_name);
 	gtk_action_group_set_visible (action_group, visible);
 
+	group_name = "http";
 	visible = uri_is_valid && scheme_is_http;
-	action_group = e_web_view_get_action_group (web_view, "http");
+	action_group = e_web_view_get_action_group (web_view, group_name);
 	gtk_action_group_set_visible (action_group, visible);
 
+	group_name = "mailto";
 	visible = uri_is_valid && scheme_is_mailto;
-	action_group = e_web_view_get_action_group (web_view, "mailto");
+	action_group = e_web_view_get_action_group (web_view, group_name);
+	gtk_action_group_set_visible (action_group, visible);
+
+	group_name = "selection";
+	visible = have_selection;
+	action_group = e_web_view_get_action_group (web_view, group_name);
+	gtk_action_group_set_visible (action_group, visible);
+
+	group_name = "standard";
+	visible = (uri == NULL);
+	action_group = e_web_view_get_action_group (web_view, group_name);
+	gtk_action_group_set_visible (action_group, visible);
+
+	group_name = "lockdown-printing";
+	visible = (uri == NULL) && !web_view->priv->disable_printing;
+	action_group = e_web_view_get_action_group (web_view, group_name);
+	gtk_action_group_set_visible (action_group, visible);
+
+	group_name = "lockdown-save-to-disk";
+	visible = (uri == NULL) && !web_view->priv->disable_save_to_disk;
+	action_group = e_web_view_get_action_group (web_view, group_name);
 	gtk_action_group_set_visible (action_group, visible);
 }
 
@@ -751,6 +911,56 @@ web_view_class_init (EWebViewClass *class)
 
 	g_object_class_install_property (
 		object_class,
+		PROP_DISABLE_PRINTING,
+		g_param_spec_boolean (
+			"disable-printing",
+			"Disable Printing",
+			NULL,
+			FALSE,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_DISABLE_SAVE_TO_DISK,
+		g_param_spec_boolean (
+			"disable-save-to-disk",
+			"Disable Save-to-Disk",
+			NULL,
+			FALSE,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_OPEN_PROXY,
+		g_param_spec_object (
+			"open-proxy",
+			"Open Proxy",
+			NULL,
+			GTK_TYPE_ACTION,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_PRINT_PROXY,
+		g_param_spec_object (
+			"print-proxy",
+			"Print Proxy",
+			NULL,
+			GTK_TYPE_ACTION,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SAVE_AS_PROXY,
+		g_param_spec_object (
+			"save-as-proxy",
+			"Save As Proxy",
+			NULL,
+			GTK_TYPE_ACTION,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
 		PROP_SELECTED_URI,
 		g_param_spec_string (
 			"selected-uri",
@@ -804,6 +1014,7 @@ web_view_init (EWebView *web_view)
 {
 	GtkUIManager *ui_manager;
 	GtkActionGroup *action_group;
+	EPopupAction *popup_action;
 	const gchar *domain = GETTEXT_PACKAGE;
 	const gchar *id;
 	GError *error = NULL;
@@ -844,6 +1055,60 @@ web_view_init (EWebView *web_view)
 		action_group, mailto_entries,
 		G_N_ELEMENTS (mailto_entries), web_view);
 
+	action_group = gtk_action_group_new ("selection");
+	gtk_action_group_set_translation_domain (action_group, domain);
+	gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+	g_object_unref (action_group);
+
+	gtk_action_group_add_actions (
+		action_group, selection_entries,
+		G_N_ELEMENTS (selection_entries), web_view);
+
+	action_group = gtk_action_group_new ("standard");
+	gtk_action_group_set_translation_domain (action_group, domain);
+	gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+	g_object_unref (action_group);
+
+	gtk_action_group_add_actions (
+		action_group, standard_entries,
+		G_N_ELEMENTS (standard_entries), web_view);
+
+	popup_action = e_popup_action_new ("open");
+	gtk_action_group_add_action (action_group, GTK_ACTION (popup_action));
+	g_object_unref (popup_action);
+
+	e_mutual_binding_new (
+		web_view, "open-proxy",
+		popup_action, "related-action");
+
+	/* Support lockdown. */
+
+	action_group = gtk_action_group_new ("lockdown-printing");
+	gtk_action_group_set_translation_domain (action_group, domain);
+	gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+	g_object_unref (action_group);
+
+	popup_action = e_popup_action_new ("print");
+	gtk_action_group_add_action (action_group, GTK_ACTION (popup_action));
+	g_object_unref (popup_action);
+
+	e_mutual_binding_new (
+		web_view, "print-proxy",
+		popup_action, "related-action");
+
+	action_group = gtk_action_group_new ("lockdown-save-to-disk");
+	gtk_action_group_set_translation_domain (action_group, domain);
+	gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+	g_object_unref (action_group);
+
+	popup_action = e_popup_action_new ("save-as");
+	gtk_action_group_add_action (action_group, GTK_ACTION (popup_action));
+	g_object_unref (popup_action);
+
+	e_mutual_binding_new (
+		web_view, "save-as-proxy",
+		popup_action, "related-action");
+
 	/* 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. */
@@ -960,6 +1225,44 @@ e_web_view_set_caret_mode (EWebView *web_view,
 	g_object_notify (G_OBJECT (web_view), "caret-mode");
 }
 
+gboolean
+e_web_view_get_disable_printing (EWebView *web_view)
+{
+	g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+
+	return web_view->priv->disable_printing;
+}
+
+void
+e_web_view_set_disable_printing (EWebView *web_view,
+                                 gboolean disable_printing)
+{
+	g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+	web_view->priv->disable_printing = disable_printing;
+
+	g_object_notify (G_OBJECT (web_view), "disable-printing");
+}
+
+gboolean
+e_web_view_get_disable_save_to_disk (EWebView *web_view)
+{
+	g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+
+	return web_view->priv->disable_save_to_disk;
+}
+
+void
+e_web_view_set_disable_save_to_disk (EWebView *web_view,
+                                     gboolean disable_save_to_disk)
+{
+	g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+	web_view->priv->disable_save_to_disk = disable_save_to_disk;
+
+	g_object_notify (G_OBJECT (web_view), "disable-save-to-disk");
+}
+
 const gchar *
 e_web_view_get_selected_uri (EWebView *web_view)
 {
@@ -981,6 +1284,87 @@ e_web_view_set_selected_uri (EWebView *web_view,
 }
 
 GtkAction *
+e_web_view_get_open_proxy (EWebView *web_view)
+{
+	g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+
+	return web_view->priv->open_proxy;
+}
+
+void
+e_web_view_set_open_proxy (EWebView *web_view,
+                           GtkAction *open_proxy)
+{
+	g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+	if (open_proxy != NULL) {
+		g_return_if_fail (GTK_IS_ACTION (open_proxy));
+		g_object_ref (open_proxy);
+	}
+
+	if (web_view->priv->open_proxy != NULL)
+		g_object_unref (web_view->priv->open_proxy);
+
+	web_view->priv->open_proxy = open_proxy;
+
+	g_object_notify (G_OBJECT (web_view), "open-proxy");
+}
+
+GtkAction *
+e_web_view_get_print_proxy (EWebView *web_view)
+{
+	g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+
+	return web_view->priv->print_proxy;
+}
+
+void
+e_web_view_set_print_proxy (EWebView *web_view,
+                            GtkAction *print_proxy)
+{
+	g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+	if (print_proxy != NULL) {
+		g_return_if_fail (GTK_IS_ACTION (print_proxy));
+		g_object_ref (print_proxy);
+	}
+
+	if (web_view->priv->print_proxy != NULL)
+		g_object_unref (web_view->priv->print_proxy);
+
+	web_view->priv->print_proxy = print_proxy;
+
+	g_object_notify (G_OBJECT (web_view), "print-proxy");
+}
+
+GtkAction *
+e_web_view_get_save_as_proxy (EWebView *web_view)
+{
+	g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+
+	return web_view->priv->save_as_proxy;
+}
+
+void
+e_web_view_set_save_as_proxy (EWebView *web_view,
+                              GtkAction *save_as_proxy)
+{
+	g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+	if (save_as_proxy != NULL) {
+		g_return_if_fail (GTK_IS_ACTION (save_as_proxy));
+		g_object_ref (save_as_proxy);
+	}
+
+	if (web_view->priv->save_as_proxy != NULL)
+		g_object_unref (web_view->priv->save_as_proxy);
+
+	web_view->priv->save_as_proxy = save_as_proxy;
+
+	g_object_notify (G_OBJECT (web_view), "save-as-proxy");
+}
+
+GtkAction *
 e_web_view_get_action (EWebView *web_view,
                        const gchar *action_name)
 {
@@ -1026,6 +1410,22 @@ e_web_view_extract_uri (EWebView *web_view,
 	return class->extract_uri (web_view, event, frame);
 }
 
+void
+e_web_view_clipboard_copy (EWebView *web_view)
+{
+	g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+	gtk_html_command (GTK_HTML (web_view), "copy");
+}
+
+gboolean
+e_web_view_is_selection_active (EWebView *web_view)
+{
+	g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+
+	return gtk_html_command (GTK_HTML (web_view), "is-selection-active");
+}
+
 gboolean
 e_web_view_scroll_forward (EWebView *web_view)
 {
@@ -1042,6 +1442,22 @@ e_web_view_scroll_backward (EWebView *web_view)
 	return gtk_html_command (GTK_HTML (web_view), "scroll-backward");
 }
 
+void
+e_web_view_select_all (EWebView *web_view)
+{
+	g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+	gtk_html_command (GTK_HTML (web_view), "select-all");
+}
+
+void
+e_web_view_unselect_all (EWebView *web_view)
+{
+	g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+	gtk_html_command (GTK_HTML (web_view), "unselect-all");
+}
+
 GtkUIManager *
 e_web_view_get_ui_manager (EWebView *web_view)
 {
diff --git a/widgets/misc/e-web-view.h b/widgets/misc/e-web-view.h
index 3bce2b4..37c289a 100644
--- a/widgets/misc/e-web-view.h
+++ b/widgets/misc/e-web-view.h
@@ -91,9 +91,26 @@ void		e_web_view_set_animate		(EWebView *web_view,
 gboolean	e_web_view_get_caret_mode	(EWebView *web_view);
 void		e_web_view_set_caret_mode	(EWebView *web_view,
 						 gboolean caret_mode);
+gboolean	e_web_view_get_disable_printing	(EWebView *web_view);
+void		e_web_view_set_disable_printing	(EWebView *web_view,
+						 gboolean disable_printing);
+gboolean	e_web_view_get_disable_save_to_disk
+						(EWebView *web_view);
+void		e_web_view_set_disable_save_to_disk
+						(EWebView *web_view,
+						 gboolean disable_save_to_disk);
 const gchar *	e_web_view_get_selected_uri	(EWebView *web_view);
 void		e_web_view_set_selected_uri	(EWebView *web_view,
 						 const gchar *selected_uri);
+GtkAction *	e_web_view_get_open_proxy	(EWebView *web_view);
+void		e_web_view_set_open_proxy	(EWebView *web_view,
+						 GtkAction *open_proxy);
+GtkAction *	e_web_view_get_print_proxy	(EWebView *web_view);
+void		e_web_view_set_print_proxy	(EWebView *web_view,
+						 GtkAction *print_proxy);
+GtkAction *	e_web_view_get_save_as_proxy	(EWebView *web_view);
+void		e_web_view_set_save_as_proxy	(EWebView *web_view,
+						 GtkAction *save_as_proxy);
 GtkAction *	e_web_view_get_action		(EWebView *web_view,
 						 const gchar *action_name);
 GtkActionGroup *e_web_view_get_action_group	(EWebView *web_view,
@@ -101,8 +118,12 @@ GtkActionGroup *e_web_view_get_action_group	(EWebView *web_view,
 gchar *		e_web_view_extract_uri		(EWebView *web_view,
 						 GdkEventButton *event,
 						 GtkHTML *frame);
+void		e_web_view_clipboard_copy	(EWebView *web_view);
+gboolean	e_web_view_is_selection_active	(EWebView *web_view);
 gboolean	e_web_view_scroll_forward	(EWebView *web_view);
 gboolean	e_web_view_scroll_backward	(EWebView *web_view);
+void		e_web_view_select_all		(EWebView *web_view);
+void		e_web_view_unselect_all		(EWebView *web_view);
 GtkUIManager *	e_web_view_get_ui_manager	(EWebView *web_view);
 GtkWidget *	e_web_view_get_popup_menu	(EWebView *web_view);
 void		e_web_view_show_popup_menu	(EWebView *web_view,



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