diff options
author | Matthew Barnes <mbarnes@redhat.com> | 2010-01-17 02:34:32 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@redhat.com> | 2010-01-18 01:11:08 +0800 |
commit | 3e7c7808cc65c22bc40a7d1d30ffa0044097a6ff (patch) | |
tree | d74cd0017e310c79b796eba3df7bfb8947a673d7 /widgets/misc/e-web-view.c | |
parent | 2cf0c27e2ece428dd2af1945f6fececbe9dbcc15 (diff) | |
download | gsoc2013-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.c | 243 |
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) { |