[evolution] I#1923 - Composer: Add "Copy/Open Link" into the context menu
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution] I#1923 - Composer: Add "Copy/Open Link" into the context menu
- Date: Mon, 13 Jun 2022 12:12:02 +0000 (UTC)
commit 1ee1bbe2a496524f96bb91da46cb0bbf792cbad7
Author: Milan Crha <mcrha redhat com>
Date: Mon Jun 13 14:10:32 2022 +0200
I#1923 - Composer: Add "Copy/Open Link" into the context menu
Closes https://gitlab.gnome.org/GNOME/evolution/-/issues/1923
data/webkit/e-editor.js | 11 ++++--
po/POTFILES.in | 1 +
src/e-util/e-content-editor.c | 15 ++++++++
src/e-util/e-content-editor.h | 5 ++-
src/e-util/e-html-editor-actions.c | 49 +++++++++++++++++++++++-
src/e-util/e-html-editor-actions.h | 4 ++
src/e-util/e-html-editor-manager.ui | 2 +
src/e-util/e-html-editor-private.h | 2 +
src/e-util/e-html-editor.c | 26 ++++++++++---
src/e-util/e-html-editor.h | 3 +-
src/modules/webkit-editor/e-webkit-editor.c | 59 ++++++++++++++++++++++++++---
11 files changed, 159 insertions(+), 18 deletions(-)
---
diff --git a/data/webkit/e-editor.js b/data/webkit/e-editor.js
index 80f950865b..48b3c7565c 100644
--- a/data/webkit/e-editor.js
+++ b/data/webkit/e-editor.js
@@ -6434,12 +6434,16 @@ EvoEditor.onContextMenu = function(event)
EvoEditor.contextMenuNode = node;
- var nodeFlags = EvoEditor.E_CONTENT_EDITOR_NODE_UNKNOWN, res;
+ var nodeFlags = EvoEditor.E_CONTENT_EDITOR_NODE_UNKNOWN, res, anchorHref = "";
while (node && node.tagName != "BODY") {
- if (node.tagName == "A")
+ if (node.tagName == "A") {
nodeFlags |= EvoEditor.E_CONTENT_EDITOR_NODE_IS_ANCHOR;
- else if (node.tagName == "HR")
+ if (EvoEditor.mode == EvoEditor.MODE_PLAIN_TEXT)
+ anchorHref = node.innerText;
+ else
+ anchorHref = node.href;
+ } else if (node.tagName == "HR")
nodeFlags |= EvoEditor.E_CONTENT_EDITOR_NODE_IS_H_RULE;
else if (node.tagName == "IMG")
nodeFlags |= EvoEditor.E_CONTENT_EDITOR_NODE_IS_IMAGE;
@@ -6461,6 +6465,7 @@ EvoEditor.onContextMenu = function(event)
res["nodeFlags"] = nodeFlags;
res["caretWord"] = EvoEditor.GetCaretWord();
+ res["anchorHref"] = anchorHref;
window.webkit.messageHandlers.contextMenuRequested.postMessage(res);
}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index c3b5e1b29a..eed67030f2 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -494,6 +494,7 @@ src/modules/text-highlight/languages.c
src/modules/vcard-inline/e-mail-formatter-vcard.c
src/modules/vcard-inline/e-mail-parser-vcard.c
src/modules/vcard-inline/e-mail-part-vcard.c
+src/modules/webkit-editor/e-webkit-editor.c
src/modules/webkit-inspector/evolution-webkit-inspector.c
src/plugins/attachment-reminder/attachment-reminder.c
src/plugins/attachment-reminder/org-gnome-attachment-reminder.error.xml
diff --git a/src/e-util/e-content-editor.c b/src/e-util/e-content-editor.c
index f8b1722639..8d2aeca84e 100644
--- a/src/e-util/e-content-editor.c
+++ b/src/e-util/e-content-editor.c
@@ -3855,6 +3855,21 @@ e_content_editor_spell_check_prev_word (EContentEditor *editor,
return iface->spell_check_prev_word (editor, word);
}
+const gchar *
+e_content_editor_get_hover_uri (EContentEditor *editor)
+{
+ EContentEditorInterface *iface;
+
+ g_return_val_if_fail (E_IS_CONTENT_EDITOR (editor), NULL);
+
+ iface = E_CONTENT_EDITOR_GET_IFACE (editor);
+ g_return_val_if_fail (iface != NULL, NULL);
+ if (!iface->get_hover_uri)
+ return NULL;
+
+ return iface->get_hover_uri (editor);
+}
+
void
e_content_editor_emit_load_finished (EContentEditor *editor)
{
diff --git a/src/e-util/e-content-editor.h b/src/e-util/e-content-editor.h
index 8f376e6b2b..0ae7ea1665 100644
--- a/src/e-util/e-content-editor.h
+++ b/src/e-util/e-content-editor.h
@@ -430,9 +430,10 @@ struct _EContentEditorInterface {
EContentEditorMode mode);
void (*grab_focus) (EContentEditor *editor);
gboolean (*is_focus) (EContentEditor *editor);
+ const gchar * (*get_hover_uri) (EContentEditor *editor);
/* padding for future expansion */
- gpointer reserved[17];
+ gpointer reserved[16];
};
/* Properties */
@@ -991,6 +992,8 @@ void e_content_editor_spell_check_replace_all
void e_content_editor_delete_h_rule (EContentEditor *editor);
void e_content_editor_delete_image (EContentEditor *editor);
+const gchar * e_content_editor_get_hover_uri (EContentEditor *editor);
+
/* Signal helpers */
void e_content_editor_emit_load_finished
diff --git a/src/e-util/e-html-editor-actions.c b/src/e-util/e-html-editor-actions.c
index aa6f664597..f56e560e32 100644
--- a/src/e-util/e-html-editor-actions.c
+++ b/src/e-util/e-html-editor-actions.c
@@ -140,9 +140,42 @@ insert_text_file_ready_cb (GFile *file,
* Action Callbacks
*****************************************************************************/
+static void
+action_copy_link_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ GtkClipboard *clipboard;
+
+ if (!editor->priv->context_hover_uri)
+ return;
+
+ clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
+ gtk_clipboard_set_text (clipboard, editor->priv->context_hover_uri, -1);
+ gtk_clipboard_store (clipboard);
+
+ clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+ gtk_clipboard_set_text (clipboard, editor->priv->context_hover_uri, -1);
+ gtk_clipboard_store (clipboard);
+}
+
+static void
+action_open_link_cb (GtkAction *action,
+ EHTMLEditor *editor)
+{
+ gpointer parent;
+
+ if (!editor->priv->context_hover_uri)
+ return;
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (editor));
+ parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
+
+ e_show_uri (parent, editor->priv->context_hover_uri);
+}
+
static void
action_context_delete_cell_contents_cb (GtkAction *action,
- EHTMLEditor *editor)
+ EHTMLEditor *editor)
{
EContentEditor *cnt_editor;
@@ -1667,6 +1700,20 @@ static GtkRadioActionEntry html_size_entries[] = {
static GtkActionEntry context_entries[] = {
+ { "context-copy-link",
+ "edit-copy",
+ N_("Copy _Link Location"),
+ NULL,
+ N_("Copy the link to the clipboard"),
+ G_CALLBACK (action_copy_link_cb) },
+
+ { "context-open-link",
+ "emblem-web",
+ N_("_Open Link in Browser"),
+ NULL,
+ N_("Open the link in a web browser"),
+ G_CALLBACK (action_open_link_cb) },
+
{ "context-delete-cell",
NULL,
N_("Cell Contents"),
diff --git a/src/e-util/e-html-editor-actions.h b/src/e-util/e-html-editor-actions.h
index f66eb584aa..0adde4c3d9 100644
--- a/src/e-util/e-html-editor-actions.h
+++ b/src/e-util/e-html-editor-actions.h
@@ -29,6 +29,8 @@
#define E_HTML_EDITOR_ACTION_BOLD(editor) \
E_HTML_EDITOR_ACTION ((editor), "bold")
+#define E_HTML_EDITOR_ACTION_CONTEXT_COPY_LINK(editor) \
+ E_HTML_EDITOR_ACTION ((editor), "context-copy-link")
#define E_HTML_EDITOR_ACTION_CONTEXT_DELETE_CELL(editor) \
E_HTML_EDITOR_ACTION ((editor), "context-delete-cell")
#define E_HTML_EDITOR_ACTION_CONTEXT_DELETE_COLUMN(editor) \
@@ -51,6 +53,8 @@
E_HTML_EDITOR_ACTION ((editor), "context-insert-row-above")
#define E_HTML_EDITOR_ACTION_CONTEXT_INSERT_ROW_BELOW(editor) \
E_HTML_EDITOR_ACTION ((editor), "context-insert-row-below")
+#define E_HTML_EDITOR_ACTION_CONTEXT_OPEN_LINK(editor) \
+ E_HTML_EDITOR_ACTION ((editor), "context-open-link")
#define E_HTML_EDITOR_ACTION_CONTEXT_PROPERTIES_CELL(editor) \
E_HTML_EDITOR_ACTION ((editor), "context-properties-cell")
#define E_HTML_EDITOR_ACTION_CONTEXT_PROPERTIES_IMAGE(editor) \
diff --git a/src/e-util/e-html-editor-manager.ui b/src/e-util/e-html-editor-manager.ui
index 885108bde2..4592ea63a8 100644
--- a/src/e-util/e-html-editor-manager.ui
+++ b/src/e-util/e-html-editor-manager.ui
@@ -158,6 +158,8 @@
<menuitem action='paste-quote'/>
<menuitem action='paste-as-text'/>
<separator/>
+ <menuitem action='context-copy-link'/>
+ <menuitem action='context-open-link'/>
<menuitem action='context-insert-link'/>
<menuitem action='context-remove-link'/>
<separator/>
diff --git a/src/e-util/e-html-editor-private.h b/src/e-util/e-html-editor-private.h
index 909a603011..aeb6208b46 100644
--- a/src/e-util/e-html-editor-private.h
+++ b/src/e-util/e-html-editor-private.h
@@ -111,6 +111,8 @@ struct _EHTMLEditorPrivate {
gint editor_layout_row;
gboolean paste_plain_prefer_pre;
+
+ gchar *context_hover_uri;
};
void e_html_editor_actions_init (EHTMLEditor *editor);
diff --git a/src/e-util/e-html-editor.c b/src/e-util/e-html-editor.c
index 6e26ef4166..23f8b18ef2 100644
--- a/src/e-util/e-html-editor.c
+++ b/src/e-util/e-html-editor.c
@@ -457,7 +457,8 @@ action_set_visible_and_sensitive (GtkAction *action,
static void
html_editor_update_actions (EHTMLEditor *editor,
EContentEditorNodeFlags flags,
- const gchar *caret_word)
+ const gchar *caret_word,
+ const gchar *hover_uri)
{
EContentEditor *cnt_editor;
ESpellChecker *spell_checker;
@@ -472,17 +473,23 @@ html_editor_update_actions (EHTMLEditor *editor,
cnt_editor = e_html_editor_get_content_editor (editor);
if (camel_debug ("webkit:editor"))
- printf ("%s: flags:%d(%x)\n", G_STRFUNC, flags, flags);
+ printf ("%s: flags:%d(%x) caret-word:'%s' hover_uri:'%s'\n", G_STRFUNC, flags, flags,
caret_word, hover_uri);
+
+ g_clear_pointer (&editor->priv->context_hover_uri, g_free);
+ editor->priv->context_hover_uri = hover_uri && *hover_uri ? g_strdup (hover_uri) : NULL;
visible = (flags & E_CONTENT_EDITOR_NODE_IS_IMAGE);
action_set_visible_and_sensitive (ACTION (CONTEXT_PROPERTIES_IMAGE), visible);
action_set_visible_and_sensitive (ACTION (CONTEXT_DELETE_IMAGE), visible);
visible = (flags & E_CONTENT_EDITOR_NODE_IS_ANCHOR);
- if (visible)
- action_set_visible_and_sensitive (ACTION (CONTEXT_INSERT_LINK), visible);
+ action_set_visible_and_sensitive (ACTION (CONTEXT_INSERT_LINK), !visible);
action_set_visible_and_sensitive (ACTION (CONTEXT_PROPERTIES_LINK), visible);
+ visible = hover_uri && *hover_uri;
+ action_set_visible_and_sensitive (ACTION (CONTEXT_COPY_LINK), visible);
+ action_set_visible_and_sensitive (ACTION (CONTEXT_OPEN_LINK), visible);
+
visible = (flags & E_CONTENT_EDITOR_NODE_IS_H_RULE);
action_set_visible_and_sensitive (ACTION (CONTEXT_PROPERTIES_RULE), visible);
action_set_visible_and_sensitive (ACTION (CONTEXT_DELETE_HRULE), visible);
@@ -619,6 +626,7 @@ typedef struct _ContextMenuData {
GWeakRef *editor_weakref; /* EHTMLEditor * */
EContentEditorNodeFlags flags;
gchar *caret_word;
+ gchar *hover_uri;
GdkEvent *event;
} ContextMenuData;
@@ -631,6 +639,7 @@ context_menu_data_free (gpointer ptr)
g_clear_pointer (&cmd->event, gdk_event_free);
e_weak_ref_free (cmd->editor_weakref);
g_free (cmd->caret_word);
+ g_free (cmd->hover_uri);
g_slice_free (ContextMenuData, cmd);
}
}
@@ -659,7 +668,7 @@ html_editor_show_context_menu_idle_cb (gpointer user_data)
menu = e_html_editor_get_managed_widget (editor, "/context-menu");
- g_signal_emit (editor, signals[UPDATE_ACTIONS], 0, cmd->flags, cmd->caret_word);
+ g_signal_emit (editor, signals[UPDATE_ACTIONS], 0, cmd->flags, cmd->caret_word,
cmd->hover_uri);
if (!gtk_menu_get_attach_widget (GTK_MENU (menu))) {
gtk_menu_attach_to_widget (GTK_MENU (menu), GTK_WIDGET (editor), NULL);
@@ -692,6 +701,7 @@ html_editor_context_menu_requested_cb (EContentEditor *cnt_editor,
cmd->editor_weakref = e_weak_ref_new (editor);
cmd->flags = flags;
cmd->caret_word = g_strdup (caret_word);
+ cmd->hover_uri = g_strdup (e_content_editor_get_hover_uri (cnt_editor));
cmd->event = gdk_event_copy (event);
g_idle_add_full (G_PRIORITY_LOW, html_editor_show_context_menu_idle_cb,
@@ -1074,6 +1084,9 @@ html_editor_dispose (GObject *object)
g_clear_object (&priv->mode_change_content_cancellable);
+ g_clear_pointer (&priv->filename, g_free);
+ g_clear_pointer (&priv->context_hover_uri, g_free);
+
/* Do not unbind/disconnect signal handlers here, just free/unset them */
g_slist_free_full (priv->content_editor_bindings, g_object_unref);
priv->content_editor_bindings = NULL;
@@ -1171,8 +1184,9 @@ e_html_editor_class_init (EHTMLEditorClass *class)
G_STRUCT_OFFSET (EHTMLEditorClass, update_actions),
NULL, NULL,
NULL,
- G_TYPE_NONE, 2,
+ G_TYPE_NONE, 3,
G_TYPE_UINT,
+ G_TYPE_STRING,
G_TYPE_STRING);
signals[SPELL_LANGUAGES_CHANGED] = g_signal_new (
diff --git a/src/e-util/e-html-editor.h b/src/e-util/e-html-editor.h
index b30250bdf3..1e65949b52 100644
--- a/src/e-util/e-html-editor.h
+++ b/src/e-util/e-html-editor.h
@@ -69,7 +69,8 @@ struct _EHTMLEditorClass {
void (*update_actions) (EHTMLEditor *editor,
EContentEditorNodeFlags flags,
- const gchar *caret_word);
+ const gchar *caret_word,
+ const gchar *hover_uri);
void (*spell_languages_changed)
(EHTMLEditor *editor);
diff --git a/src/modules/webkit-editor/e-webkit-editor.c b/src/modules/webkit-editor/e-webkit-editor.c
index 8b0b30717f..48db63df07 100644
--- a/src/modules/webkit-editor/e-webkit-editor.c
+++ b/src/modules/webkit-editor/e-webkit-editor.c
@@ -16,6 +16,8 @@
#include "evolution-config.h"
+#include <glib/gi18n-lib.h>
+
#include "e-webkit-editor.h"
#include "e-util/e-util.h"
@@ -734,9 +736,11 @@ context_menu_requested_cb (WebKitUserContentManager *manager,
g_return_if_fail (jsc_value_is_object (jsc_params));
g_clear_pointer (&wk_editor->priv->context_menu_caret_word, g_free);
+ g_clear_pointer (&wk_editor->priv->last_hover_uri, g_free);
wk_editor->priv->context_menu_node_flags = e_web_view_jsc_get_object_property_int32 (jsc_params,
"nodeFlags", 0);
wk_editor->priv->context_menu_caret_word = e_web_view_jsc_get_object_property_string (jsc_params,
"caretWord", NULL);
+ wk_editor->priv->last_hover_uri = e_web_view_jsc_get_object_property_string (jsc_params,
"anchorHref", NULL);
}
static gboolean
@@ -4432,8 +4436,7 @@ webkit_editor_finalize (GObject *object)
g_clear_pointer (&priv->body_link_color, gdk_rgba_free);
g_clear_pointer (&priv->body_vlink_color, gdk_rgba_free);
- g_free (priv->last_hover_uri);
- priv->last_hover_uri = NULL;
+ g_clear_pointer (&priv->last_hover_uri, g_free);
g_clear_object (&priv->spell_checker);
g_clear_object (&priv->cancellable);
@@ -5178,11 +5181,14 @@ webkit_editor_mouse_target_changed_cb (EWebKitEditor *wk_editor,
{
g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
- g_free (wk_editor->priv->last_hover_uri);
- wk_editor->priv->last_hover_uri = NULL;
+ g_clear_pointer (&wk_editor->priv->last_hover_uri, g_free);
- if (webkit_hit_test_result_context_is_link (hit_test_result))
- wk_editor->priv->last_hover_uri = g_strdup (webkit_hit_test_result_get_link_uri
(hit_test_result));
+ if (webkit_hit_test_result_context_is_link (hit_test_result)) {
+ if (wk_editor->priv->mode == E_CONTENT_EDITOR_MODE_HTML)
+ wk_editor->priv->last_hover_uri = g_strdup (webkit_hit_test_result_get_link_uri
(hit_test_result));
+ else
+ wk_editor->priv->last_hover_uri = g_strdup (webkit_hit_test_result_get_link_label
(hit_test_result));
+ }
}
static gboolean
@@ -5457,6 +5463,40 @@ e_webkit_editor_cid_resolver_ref_part (ECidResolver *resolver,
return e_content_editor_emit_ref_mime_part (E_CONTENT_EDITOR (resolver), cid_uri);
}
+static const gchar *
+webkit_editor_get_hover_uri (EContentEditor *editor)
+{
+ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (editor);
+
+ return wk_editor->priv->last_hover_uri;
+}
+
+static gboolean
+webkit_editor_query_tooltip_cb (GtkWidget *widget,
+ gint xx,
+ gint yy,
+ gboolean keyboard_mode,
+ GtkTooltip *tooltip,
+ gpointer user_data)
+{
+ EWebKitEditor *wk_editor;
+ gchar *str;
+
+ g_return_val_if_fail (E_IS_WEBKIT_EDITOR (widget), FALSE);
+
+ wk_editor = E_WEBKIT_EDITOR (widget);
+
+ if (!wk_editor->priv->last_hover_uri || !*wk_editor->priv->last_hover_uri)
+ return FALSE;
+
+ /* Translators: The "%s" is replaced with a link, constructing a text like: "Ctrl-click to open a
link “http://www.example.com”" */
+ str = g_strdup_printf (_("Ctrl-click to open a link “%s”"), wk_editor->priv->last_hover_uri);
+ gtk_tooltip_set_text (tooltip, str);
+ g_free (str);
+
+ return TRUE;
+}
+
static gboolean
webkit_editor_button_press_event (GtkWidget *widget,
GdkEventButton *event)
@@ -5799,6 +5839,12 @@ e_webkit_editor_init (EWebKitEditor *wk_editor)
wk_editor, "state-flags-changed",
G_CALLBACK (webkit_editor_style_updated_cb), NULL);
+ gtk_widget_set_has_tooltip (GTK_WIDGET (wk_editor), TRUE);
+
+ g_signal_connect (
+ wk_editor, "query-tooltip",
+ G_CALLBACK (webkit_editor_query_tooltip_cb), NULL);
+
g_settings = e_util_ref_settings ("org.gnome.desktop.interface");
g_signal_connect (
g_settings, "changed::font-name",
@@ -5965,6 +6011,7 @@ e_webkit_editor_content_editor_init (EContentEditorInterface *iface)
iface->spell_check_prev_word = webkit_editor_spell_check_prev_word;
iface->delete_h_rule = webkit_editor_delete_h_rule;
iface->delete_image = webkit_editor_delete_image;
+ iface->get_hover_uri = webkit_editor_get_hover_uri;
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]