aboutsummaryrefslogtreecommitdiffstats
path: root/widgets/misc/e-web-view.c
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@redhat.com>2010-01-17 02:34:32 +0800
committerMatthew Barnes <mbarnes@redhat.com>2010-01-18 01:11:08 +0800
commit3e7c7808cc65c22bc40a7d1d30ffa0044097a6ff (patch)
treed74cd0017e310c79b796eba3df7bfb8947a673d7 /widgets/misc/e-web-view.c
parent2cf0c27e2ece428dd2af1945f6fececbe9dbcc15 (diff)
downloadgsoc2013-evolution-3e7c7808cc65c22bc40a7d1d30ffa0044097a6ff.tar.gz
gsoc2013-evolution-3e7c7808cc65c22bc40a7d1d30ffa0044097a6ff.tar.zst
gsoc2013-evolution-3e7c7808cc65c22bc40a7d1d30ffa0044097a6ff.zip
Improve clipboard behavior.
Add "copy-target-list" and "paste-target-list" to the ESelectable interface. These are underutilized for the moment, but will eventually be used to help integrate drag-and-drop support into ESelectable. Add cut and paste support to EWebView, along with a new "editable" property and new clipboard signals "copy-clipboard", "cut-clipboard" and "paste-clipboard". In EFocusTracker, listen for "owner-changed" signals from the default clipboard as another trigger to update actions, particularly the Paste action. (Unfortunately this doesn't work for EWebView since GtkHtml implements its own clipboard.) In EMsgComposer, convert GtkhtmlEditor's clipboard methods to empty stubs, since EFocusTracker will now trigger EWebView's clipboard actions. Also, intercept EWebView::paste-clipboard signals and improve the interaction between the HTML editor and the attachment bar based on use cases in bug #603715.
Diffstat (limited to 'widgets/misc/e-web-view.c')
-rw-r--r--widgets/misc/e-web-view.c243
1 files changed, 231 insertions, 12 deletions
diff --git a/widgets/misc/e-web-view.c b/widgets/misc/e-web-view.c
index 31516bf04d..a5f98a4edc 100644
--- a/widgets/misc/e-web-view.c
+++ b/widgets/misc/e-web-view.c
@@ -50,6 +50,9 @@ struct _EWebViewPrivate {
GtkAction *print_proxy;
GtkAction *save_as_proxy;
+ GtkTargetList *copy_target_list;
+ GtkTargetList *paste_target_list;
+
/* Lockdown Options */
guint disable_printing : 1;
guint disable_save_to_disk : 1;
@@ -68,15 +71,21 @@ enum {
PROP_0,
PROP_ANIMATE,
PROP_CARET_MODE,
+ PROP_COPY_TARGET_LIST,
PROP_DISABLE_PRINTING,
PROP_DISABLE_SAVE_TO_DISK,
+ PROP_EDITABLE,
PROP_OPEN_PROXY,
+ PROP_PASTE_TARGET_LIST,
PROP_PRINT_PROXY,
PROP_SAVE_AS_PROXY,
PROP_SELECTED_URI
};
enum {
+ COPY_CLIPBOARD,
+ CUT_CLIPBOARD,
+ PASTE_CLIPBOARD,
POPUP_EVENT,
STATUS_MESSAGE,
STOP_LOADING,
@@ -488,6 +497,12 @@ web_view_set_property (GObject *object,
g_value_get_boolean (value));
return;
+ case PROP_EDITABLE:
+ e_web_view_set_editable (
+ E_WEB_VIEW (object),
+ g_value_get_boolean (value));
+ return;
+
case PROP_OPEN_PROXY:
e_web_view_set_open_proxy (
E_WEB_VIEW (object),
@@ -535,6 +550,12 @@ web_view_get_property (GObject *object,
E_WEB_VIEW (object)));
return;
+ case PROP_COPY_TARGET_LIST:
+ g_value_set_boxed (
+ value, e_web_view_get_copy_target_list (
+ E_WEB_VIEW (object)));
+ return;
+
case PROP_DISABLE_PRINTING:
g_value_set_boolean (
value, e_web_view_get_disable_printing (
@@ -547,12 +568,24 @@ web_view_get_property (GObject *object,
E_WEB_VIEW (object)));
return;
+ case PROP_EDITABLE:
+ g_value_set_boolean (
+ value, e_web_view_get_editable (
+ 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_PASTE_TARGET_LIST:
+ g_value_set_boxed (
+ value, e_web_view_get_paste_target_list (
+ E_WEB_VIEW (object)));
+ return;
+
case PROP_PRINT_PROXY:
g_value_set_object (
value, e_web_view_get_print_proxy (
@@ -602,6 +635,16 @@ web_view_dispose (GObject *object)
priv->save_as_proxy = NULL;
}
+ if (priv->copy_target_list != NULL) {
+ gtk_target_list_unref (priv->copy_target_list);
+ priv->copy_target_list = NULL;
+ }
+
+ if (priv->paste_target_list != NULL) {
+ gtk_target_list_unref (priv->paste_target_list);
+ priv->paste_target_list = NULL;
+ }
+
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@@ -765,6 +808,26 @@ web_view_extract_uri (EWebView *web_view,
return uri;
}
+static void
+web_view_copy_clipboard (EWebView *web_view)
+{
+ gtk_html_command (GTK_HTML (web_view), "copy");
+}
+
+static void
+web_view_cut_clipboard (EWebView *web_view)
+{
+ if (e_web_view_get_editable (web_view))
+ gtk_html_command (GTK_HTML (web_view), "cut");
+}
+
+static void
+web_view_paste_clipboard (EWebView *web_view)
+{
+ if (e_web_view_get_editable (web_view))
+ gtk_html_command (GTK_HTML (web_view), "paste");
+}
+
static gboolean
web_view_popup_event (EWebView *web_view,
GdkEventButton *event,
@@ -865,39 +928,76 @@ web_view_selectable_update_actions (ESelectable *selectable,
{
EWebView *web_view;
GtkAction *action;
- const gchar *tooltip;
+ /*GtkTargetList *target_list;*/
+ gboolean can_paste = FALSE;
+ gboolean editable;
+ gboolean have_selection;
gboolean sensitive;
+ const gchar *tooltip;
+ /*gint ii;*/
web_view = E_WEB_VIEW (selectable);
+ editable = e_web_view_get_editable (web_view);
+ have_selection = e_web_view_is_selection_active (web_view);
- /* Copy Clipboard */
-
- action = e_web_view_get_action (web_view, "copy-clipboard");
- sensitive = gtk_action_get_sensitive (action);
- tooltip = gtk_action_get_tooltip (action);
+ /* XXX GtkHtml implements its own clipboard instead of using
+ * GDK_SELECTION_CLIPBOARD, so we don't get notifications
+ * when the clipboard contents change. The logic below
+ * is what we would do if GtkHtml worked properly.
+ * Instead, we need to keep the Paste action sensitive so
+ * its accelerator overrides GtkHtml's key binding. */
+#if 0
+ target_list = e_selectable_get_paste_target_list (selectable);
+ for (ii = 0; ii < n_clipboard_targets && !can_paste; ii++)
+ can_paste = gtk_target_list_find (
+ target_list, clipboard_targets[ii], NULL);
+#endif
+ can_paste = TRUE;
+
+ action = e_focus_tracker_get_cut_clipboard_action (focus_tracker);
+ sensitive = editable && have_selection;
+ tooltip = _("Cut the selection");
+ gtk_action_set_sensitive (action, sensitive);
+ gtk_action_set_tooltip (action, tooltip);
action = e_focus_tracker_get_copy_clipboard_action (focus_tracker);
+ sensitive = have_selection;
+ tooltip = _("Copy the selection");
gtk_action_set_sensitive (action, sensitive);
gtk_action_set_tooltip (action, tooltip);
- /* Select All */
-
- action = e_web_view_get_action (web_view, "select-all");
- sensitive = gtk_action_get_sensitive (action);
- tooltip = gtk_action_get_tooltip (action);
+ action = e_focus_tracker_get_paste_clipboard_action (focus_tracker);
+ sensitive = editable && can_paste;
+ tooltip = _("Paste the clipboard");
+ gtk_action_set_sensitive (action, sensitive);
+ gtk_action_set_tooltip (action, tooltip);
action = e_focus_tracker_get_select_all_action (focus_tracker);
+ sensitive = TRUE;
+ tooltip = _("Select all text and images");
gtk_action_set_sensitive (action, sensitive);
gtk_action_set_tooltip (action, tooltip);
}
static void
+web_view_selectable_cut_clipboard (ESelectable *selectable)
+{
+ e_web_view_cut_clipboard (E_WEB_VIEW (selectable));
+}
+
+static void
web_view_selectable_copy_clipboard (ESelectable *selectable)
{
e_web_view_copy_clipboard (E_WEB_VIEW (selectable));
}
static void
+web_view_selectable_paste_clipboard (ESelectable *selectable)
+{
+ e_web_view_paste_clipboard (E_WEB_VIEW (selectable));
+}
+
+static void
web_view_selectable_select_all (ESelectable *selectable)
{
e_web_view_select_all (E_WEB_VIEW (selectable));
@@ -930,6 +1030,9 @@ web_view_class_init (EWebViewClass *class)
html_class->iframe_created = web_view_iframe_created;
class->extract_uri = web_view_extract_uri;
+ class->copy_clipboard = web_view_copy_clipboard;
+ class->cut_clipboard = web_view_cut_clipboard;
+ class->paste_clipboard = web_view_paste_clipboard;
class->popup_event = web_view_popup_event;
class->stop_loading = web_view_stop_loading;
class->update_actions = web_view_update_actions;
@@ -954,6 +1057,12 @@ web_view_class_init (EWebViewClass *class)
FALSE,
G_PARAM_READWRITE));
+ /* Inherited from ESelectableInterface */
+ g_object_class_override_property (
+ object_class,
+ PROP_COPY_TARGET_LIST,
+ "copy-target-list");
+
g_object_class_install_property (
object_class,
PROP_DISABLE_PRINTING,
@@ -976,6 +1085,16 @@ web_view_class_init (EWebViewClass *class)
g_object_class_install_property (
object_class,
+ PROP_EDITABLE,
+ g_param_spec_boolean (
+ "editable",
+ "Editable",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
PROP_OPEN_PROXY,
g_param_spec_object (
"open-proxy",
@@ -984,6 +1103,12 @@ web_view_class_init (EWebViewClass *class)
GTK_TYPE_ACTION,
G_PARAM_READWRITE));
+ /* Inherited from ESelectableInterface */
+ g_object_class_override_property (
+ object_class,
+ PROP_PASTE_TARGET_LIST,
+ "paste-target-list");
+
g_object_class_install_property (
object_class,
PROP_PRINT_PROXY,
@@ -1014,6 +1139,33 @@ web_view_class_init (EWebViewClass *class)
NULL,
G_PARAM_READWRITE));
+ signals[COPY_CLIPBOARD] = g_signal_new (
+ "copy-clipboard",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EWebViewClass, copy_clipboard),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[CUT_CLIPBOARD] = g_signal_new (
+ "cut-clipboard",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EWebViewClass, cut_clipboard),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[PASTE_CLIPBOARD] = g_signal_new (
+ "paste-clipboard",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EWebViewClass, paste_clipboard),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
signals[POPUP_EVENT] = g_signal_new (
"popup-event",
G_TYPE_FROM_CLASS (class),
@@ -1058,7 +1210,9 @@ static void
web_view_selectable_init (ESelectableInterface *interface)
{
interface->update_actions = web_view_selectable_update_actions;
+ interface->cut_clipboard = web_view_selectable_cut_clipboard;
interface->copy_clipboard = web_view_selectable_copy_clipboard;
+ interface->paste_clipboard = web_view_selectable_paste_clipboard;
interface->select_all = web_view_selectable_select_all;
}
@@ -1067,6 +1221,7 @@ web_view_init (EWebView *web_view)
{
GtkUIManager *ui_manager;
GtkActionGroup *action_group;
+ GtkTargetList *target_list;
EPopupAction *popup_action;
const gchar *domain = GETTEXT_PACKAGE;
const gchar *id;
@@ -1081,6 +1236,12 @@ web_view_init (EWebView *web_view)
ui_manager, "connect-proxy",
G_CALLBACK (web_view_connect_proxy_cb), web_view);
+ target_list = gtk_target_list_new (NULL, 0);
+ web_view->priv->copy_target_list = target_list;
+
+ target_list = gtk_target_list_new (NULL, 0);
+ web_view->priv->paste_target_list = target_list;
+
action_group = gtk_action_group_new ("uri");
gtk_action_group_set_translation_domain (action_group, domain);
gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
@@ -1287,6 +1448,14 @@ e_web_view_set_caret_mode (EWebView *web_view,
g_object_notify (G_OBJECT (web_view), "caret-mode");
}
+GtkTargetList *
+e_web_view_get_copy_target_list (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+ return web_view->priv->copy_target_list;
+}
+
gboolean
e_web_view_get_disable_printing (EWebView *web_view)
{
@@ -1325,6 +1494,32 @@ e_web_view_set_disable_save_to_disk (EWebView *web_view,
g_object_notify (G_OBJECT (web_view), "disable-save-to-disk");
}
+gboolean
+e_web_view_get_editable (EWebView *web_view)
+{
+ /* XXX This is just here to maintain symmetry
+ * with e_web_view_set_editable(). */
+
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+
+ return gtk_html_get_editable (GTK_HTML (web_view));
+}
+
+void
+e_web_view_set_editable (EWebView *web_view,
+ gboolean editable)
+{
+ /* XXX GtkHTML does not utilize GObject properties as well
+ * as it could. This just wraps gtk_html_set_editable()
+ * so we can get a "notify::editable" signal. */
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ gtk_html_set_editable (GTK_HTML (web_view), editable);
+
+ g_object_notify (G_OBJECT (web_view), "editable");
+}
+
const gchar *
e_web_view_get_selected_uri (EWebView *web_view)
{
@@ -1372,6 +1567,14 @@ e_web_view_set_open_proxy (EWebView *web_view,
g_object_notify (G_OBJECT (web_view), "open-proxy");
}
+GtkTargetList *
+e_web_view_get_paste_target_list (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+ return web_view->priv->paste_target_list;
+}
+
GtkAction *
e_web_view_get_print_proxy (EWebView *web_view)
{
@@ -1477,7 +1680,15 @@ e_web_view_copy_clipboard (EWebView *web_view)
{
g_return_if_fail (E_IS_WEB_VIEW (web_view));
- gtk_html_command (GTK_HTML (web_view), "copy");
+ g_signal_emit (web_view, signals[COPY_CLIPBOARD], 0);
+}
+
+void
+e_web_view_cut_clipboard (EWebView *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ g_signal_emit (web_view, signals[CUT_CLIPBOARD], 0);
}
gboolean
@@ -1488,6 +1699,14 @@ e_web_view_is_selection_active (EWebView *web_view)
return gtk_html_command (GTK_HTML (web_view), "is-selection-active");
}
+void
+e_web_view_paste_clipboard (EWebView *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ g_signal_emit (web_view, signals[PASTE_CLIPBOARD], 0);
+}
+
gboolean
e_web_view_scroll_forward (EWebView *web_view)
{