[evolution] I#289 - 'Search web' context menu option for selection in EWebView



commit a0f102812e1e6998ff4ddccd3d9fa6e6be379e7b
Author: Milan Crha <mcrha redhat com>
Date:   Wed Jan 30 14:45:05 2019 +0100

    I#289 - 'Search web' context menu option for selection in EWebView
    
    Closes https://gitlab.gnome.org/GNOME/evolution/issues/289

 data/org.gnome.evolution.shell.gschema.xml.in |   5 +
 data/ui/evolution-mail-reader.ui              |   1 +
 src/e-util/e-web-view.c                       | 175 ++++++++++++++++++++++++++
 src/e-util/e-web-view.h                       |  13 ++
 src/e-util/widgets.error.xml                  |   5 +
 src/mail/e-mail-browser.c                     |   6 +-
 src/mail/e-mail-reader.c                      |  31 +++++
 src/web-extensions/e-dom-utils.c              |  49 ++------
 8 files changed, 246 insertions(+), 39 deletions(-)
---
diff --git a/data/org.gnome.evolution.shell.gschema.xml.in b/data/org.gnome.evolution.shell.gschema.xml.in
index ebfd602c8b..e982c9f7eb 100644
--- a/data/org.gnome.evolution.shell.gschema.xml.in
+++ b/data/org.gnome.evolution.shell.gschema.xml.in
@@ -125,6 +125,11 @@
       <_summary>The last extension being used when backing up Evolution data.</_summary>
       <_description>It can be either “.gz” or “.xz” and it influences what extension will be preselected in 
the file chooser.</_description>
     </key>
+    <key name="search-web-uri-prefix" type="s">
+      <default>'https://duckduckgo.com/?q='</default>
+      <_summary>Prefix of the URI to use to search the web with selected text.</_summary>
+      <_description>The prefix of a URL to be used for searches on the web. The actual text selection is 
escaped and appended to this string. The URI should start with https://.</_description>
+    </key>
     <child name="window" schema="org.gnome.evolution.window"/>
   </schema>
 </schemalist>
diff --git a/data/ui/evolution-mail-reader.ui b/data/ui/evolution-mail-reader.ui
index eff05c2971..ea90e50bb7 100644
--- a/data/ui/evolution-mail-reader.ui
+++ b/data/ui/evolution-mail-reader.ui
@@ -178,6 +178,7 @@
   </popup>
   <popup name='mail-preview-popup'>
     <menuitem action='popup-copy-clipboard'/>
+    <menuitem action='mail-popup-search-web'/>
     <separator/>
     <menuitem action='mail-popup-reply-sender'/>
     <menuitem action='mail-popup-reply-all'/>
diff --git a/src/e-util/e-web-view.c b/src/e-util/e-web-view.c
index a25dc472ec..df5721300a 100644
--- a/src/e-util/e-web-view.c
+++ b/src/e-util/e-web-view.c
@@ -144,6 +144,7 @@ static const gchar *ui =
 "<ui>"
 "  <popup name='context'>"
 "    <menuitem action='copy-clipboard'/>"
+"    <menuitem action='search-web'/>"
 "    <separator/>"
 "    <placeholder name='custom-actions-1'>"
 "      <menuitem action='open'/>"
@@ -207,6 +208,63 @@ action_copy_clipboard_cb (GtkAction *action,
        e_web_view_copy_clipboard (web_view);
 }
 
+static void
+e_web_view_search_web_get_selection_cb (GObject *source,
+                                       GAsyncResult *result,
+                                       gpointer user_data)
+{
+       gchar *text;
+       GError *local_error = NULL;
+
+       g_return_if_fail (E_IS_WEB_VIEW (source));
+
+       text = e_web_view_get_selection_content_text_finish (E_WEB_VIEW (source), result, &local_error);
+
+       if (local_error &&
+           !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+               e_alert_submit (E_ALERT_SINK (source), "widgets:get-selected-text-failed", 
local_error->message, NULL);
+       } else if (!local_error) {
+               GSettings *settings;
+               gchar *uri_prefix;
+               gchar *escaped;
+               gchar *uri;
+
+               g_strstrip (text);
+
+               settings = e_util_ref_settings ("org.gnome.evolution.shell");
+               uri_prefix = g_settings_get_string (settings, "search-web-uri-prefix");
+               g_object_unref (settings);
+
+               escaped = camel_url_encode (text, "& ?#:;,/\\");
+
+               uri = g_strconcat (uri_prefix, escaped, NULL);
+               if (uri && g_ascii_strncasecmp (uri, "https://";, 8) == 0) {
+                       GtkWidget *toplevel;
+
+                       toplevel = gtk_widget_get_toplevel (GTK_WIDGET (source));
+
+                       e_show_uri (GTK_IS_WINDOW (toplevel) ? GTK_WINDOW (toplevel) : NULL, uri);
+               } else {
+                       g_printerr ("Incorrect URI provided, expects https:// prefix, but has got: '%s'\n", 
uri ? uri : "null");
+               }
+
+               g_free (uri_prefix);
+               g_free (escaped);
+               g_free (uri);
+       }
+
+       g_clear_error (&local_error);
+       g_free (text);
+}
+
+static void
+action_search_web_cb (GtkAction *action,
+                     EWebView *web_view)
+{
+       e_web_view_get_selection_content_text (web_view, web_view->priv->load_cancellable,
+               e_web_view_search_web_get_selection_cb, NULL);
+}
+
 static void
 action_http_open_cb (GtkAction *action,
                      EWebView *web_view)
@@ -410,6 +468,13 @@ static GtkActionEntry selection_entries[] = {
          "<Control>c",
          N_("Copy the selection"),
          G_CALLBACK (action_copy_clipboard_cb) },
+
+       { "search-web",
+         NULL,
+         N_("Search _Web…"),
+         NULL,
+         N_("Search the Web with the selected text"),
+         G_CALLBACK (action_search_web_cb) }
 };
 
 static GtkActionEntry standard_entries[] = {
@@ -3501,6 +3566,116 @@ e_web_view_get_selection_content_html_sync (EWebView *web_view,
        return NULL;
 }
 
+static void
+get_selection_content_text_cb (GObject *source_object,
+                              GAsyncResult *result,
+                              gpointer user_data)
+{
+       GDBusProxy *web_extension;
+       GTask *task = user_data;
+       GVariant *result_variant;
+       gchar *text_content = NULL;
+       GError *error = NULL;
+
+       g_return_if_fail (G_IS_DBUS_PROXY (source_object));
+       g_return_if_fail (G_IS_TASK (task));
+
+       web_extension = G_DBUS_PROXY (source_object);
+
+       result_variant = g_dbus_proxy_call_finish (web_extension, result, &error);
+       if (result_variant)
+               g_variant_get (result_variant, "(s)", &text_content);
+       g_variant_unref (result_variant);
+
+       g_task_return_pointer (task, text_content, g_free);
+       g_object_unref (task);
+
+       if (error)
+               g_dbus_error_strip_remote_error (error);
+
+       e_util_claim_dbus_proxy_call_error (web_extension, "GetSelectionContentText", error);
+       g_clear_error (&error);
+}
+
+void
+e_web_view_get_selection_content_text (EWebView *web_view,
+                                      GCancellable *cancellable,
+                                      GAsyncReadyCallback callback,
+                                      gpointer user_data)
+{
+       GDBusProxy *web_extension;
+       GTask *task;
+
+       g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+       task = g_task_new (web_view, cancellable, callback, user_data);
+
+       web_extension = e_web_view_get_web_extension_proxy (web_view);
+       if (web_extension) {
+               g_dbus_proxy_call (
+                       web_extension,
+                       "GetSelectionContentText",
+                       g_variant_new (
+                               "(t)",
+                               webkit_web_view_get_page_id (
+                                       WEBKIT_WEB_VIEW (web_view))),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       cancellable,
+                       get_selection_content_text_cb,
+                       g_object_ref (task));
+       } else
+               g_task_return_pointer (task, NULL, NULL);
+}
+
+gchar *
+e_web_view_get_selection_content_text_finish (EWebView *web_view,
+                                             GAsyncResult *result,
+                                             GError **error)
+{
+       g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+       g_return_val_if_fail (g_task_is_valid (result, web_view), FALSE);
+
+       return g_task_propagate_pointer (G_TASK (result), error);
+}
+
+gchar *
+e_web_view_get_selection_content_text_sync (EWebView *web_view,
+                                           GCancellable *cancellable,
+                                           GError **error)
+{
+       GDBusProxy *web_extension;
+
+       g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+       web_extension = e_web_view_get_web_extension_proxy (web_view);
+       if (web_extension) {
+               GVariant *result;
+
+               result = e_util_invoke_g_dbus_proxy_call_sync_wrapper_full (
+                               web_extension,
+                               "GetSelectionContentText",
+                               g_variant_new (
+                                       "(t)",
+                                       webkit_web_view_get_page_id (
+                                               WEBKIT_WEB_VIEW (web_view))),
+                               G_DBUS_CALL_FLAGS_NONE,
+                               -1,
+                               cancellable,
+                               error);
+
+               if (result) {
+                       gchar *text_content = NULL;
+
+                       g_variant_get (result, "(s)", &text_content);
+                       g_variant_unref (result);
+                       return text_content;
+               }
+       }
+
+       return NULL;
+}
+
 const gchar *
 e_web_view_get_citation_color_for_level (gint level)
 {
diff --git a/src/e-util/e-web-view.h b/src/e-util/e-web-view.h
index fb1692ab53..474140dfb6 100644
--- a/src/e-util/e-web-view.h
+++ b/src/e-util/e-web-view.h
@@ -238,6 +238,19 @@ gchar *            e_web_view_get_selection_content_html_sync
                                                (EWebView *web_view,
                                                 GCancellable *cancellable,
                                                 GError **error);
+void           e_web_view_get_selection_content_text
+                                               (EWebView *web_view,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+gchar *                e_web_view_get_selection_content_text_finish
+                                               (EWebView *web_view,
+                                                GAsyncResult *result,
+                                                GError **error);
+gchar *                e_web_view_get_selection_content_text_sync
+                                               (EWebView *web_view,
+                                                GCancellable *cancellable,
+                                                GError **error);
 void           e_web_view_update_fonts         (EWebView *web_view);
 void           e_web_view_cursor_image_copy    (EWebView *web_view);
 void           e_web_view_cursor_image_save    (EWebView *web_view);
diff --git a/src/e-util/widgets.error.xml b/src/e-util/widgets.error.xml
index 74fbd9f9a1..7e6b7c89d7 100644
--- a/src/e-util/widgets.error.xml
+++ b/src/e-util/widgets.error.xml
@@ -34,5 +34,10 @@
     <secondary xml:space="preserve">{0}</secondary>
   </error>
 
+  <error id="get-selected-text-failed" type="error">
+    <_primary>Could not get selected text.</_primary>
+    <secondary xml:space="preserve">{0}</secondary>
+  </error>
+
 </error-list>
 
diff --git a/src/mail/e-mail-browser.c b/src/mail/e-mail-browser.c
index e476759f38..4dca830bdb 100644
--- a/src/mail/e-mail-browser.c
+++ b/src/mail/e-mail-browser.c
@@ -189,7 +189,11 @@ static EPopupActionEntry mail_browser_popup_entries[] = {
 
        { "popup-copy-clipboard",
          NULL,
-         "copy-clipboard" }
+         "copy-clipboard" },
+
+       { "popup-search-web",
+         NULL,
+         "search-web" }
 };
 
 static void
diff --git a/src/mail/e-mail-reader.c b/src/mail/e-mail-reader.c
index 363090127c..6992d2c306 100644
--- a/src/mail/e-mail-reader.c
+++ b/src/mail/e-mail-reader.c
@@ -2263,6 +2263,19 @@ action_mail_zoom_out_cb (GtkAction *action,
        e_web_view_zoom_out (E_WEB_VIEW (display));
 }
 
+static void
+action_mail_search_web_cb (GtkAction *action,
+                          EMailReader *reader)
+{
+       EMailDisplay *display;
+       GtkAction *wv_action;
+
+       display = e_mail_reader_get_mail_display (reader);
+       wv_action = e_web_view_get_action (E_WEB_VIEW (display), "search-web");
+
+       gtk_action_activate (wv_action);
+}
+
 static void
 action_search_folder_recipient_cb (GtkAction *action,
                                    EMailReader *reader)
@@ -2769,6 +2782,13 @@ static GtkActionEntry mail_reader_entries[] = {
          N_("Save selected messages as an mbox file"),
          G_CALLBACK (action_mail_save_as_cb) },
 
+       { "mail-search-web",
+         NULL,
+         N_("Search _Web…"),
+         NULL,
+         N_("Search the Web with the selected text"),
+         G_CALLBACK (action_mail_search_web_cb) },
+
        { "mail-show-source",
          NULL,
          N_("_Message Source"),
@@ -3030,6 +3050,10 @@ static EPopupActionEntry mail_reader_popup_entries[] = {
          NULL,
          "mail-save-as" },
 
+       { "mail-popup-search-web",
+         NULL,
+         "mail-search-web" },
+
        { "mail-popup-undelete",
          NULL,
          "mail-undelete" }
@@ -4263,6 +4287,7 @@ mail_reader_update_actions (EMailReader *reader,
        GtkAction *action;
        const gchar *action_name;
        gboolean sensitive;
+       EMailDisplay *mail_display;
 
        /* Be descriptive. */
        gboolean any_messages_selected;
@@ -4331,6 +4356,8 @@ mail_reader_update_actions (EMailReader *reader,
        any_messages_selected =
                (single_message_selected || multiple_messages_selected);
 
+       mail_display = e_mail_reader_get_mail_display (reader);
+
        if (any_messages_selected) {
                MessageList *message_list;
                gint row = -1, count = -1;
@@ -4703,6 +4730,10 @@ mail_reader_update_actions (EMailReader *reader,
        action = e_mail_reader_get_action (reader, action_name);
        gtk_action_set_sensitive (action, sensitive);
 
+       action = e_mail_reader_get_action (reader, "mail-search-web");
+       gtk_action_set_sensitive (action, single_message_selected &&
+               mail_display && e_web_view_is_selection_active (E_WEB_VIEW (mail_display)));
+
        mail_reader_update_labels_menu (reader);
 }
 
diff --git a/src/web-extensions/e-dom-utils.c b/src/web-extensions/e-dom-utils.c
index 30e94b025a..24e15dcb64 100644
--- a/src/web-extensions/e-dom-utils.c
+++ b/src/web-extensions/e-dom-utils.c
@@ -278,18 +278,14 @@ dom_selection_get_content_text (WebKitDOMDOMSelection *dom_selection)
        return text;
 }
 
-static gchar *
-get_frame_selection_content_text (WebKitDOMElement *iframe)
+gchar *
+e_dom_utils_get_selection_content_text (WebKitDOMDocument *content_document)
 {
-       WebKitDOMDocument *content_document;
        WebKitDOMDOMWindow *dom_window = NULL;
        WebKitDOMDOMSelection *dom_selection = NULL;
        WebKitDOMHTMLCollection *frames = NULL;
        gulong ii, length;
 
-       content_document = webkit_dom_html_iframe_element_get_content_document (
-               WEBKIT_DOM_HTML_IFRAME_ELEMENT (iframe));
-
        if (!content_document)
                return NULL;
 
@@ -298,8 +294,11 @@ get_frame_selection_content_text (WebKitDOMElement *iframe)
        g_clear_object (&dom_window);
        if (dom_selection && (webkit_dom_dom_selection_get_range_count (dom_selection) > 0)) {
                gchar *text = dom_selection_get_content_text (dom_selection);
-               g_clear_object (&dom_selection);
-               return text;
+               if (text && *text) {
+                       g_clear_object (&dom_selection);
+                       return text;
+               }
+               g_free (text);
        }
        g_clear_object (&dom_selection);
 
@@ -311,41 +310,15 @@ get_frame_selection_content_text (WebKitDOMElement *iframe)
 
                node = webkit_dom_html_collection_item (frames, ii);
 
-               text = get_frame_selection_content_text (
-                       WEBKIT_DOM_ELEMENT (node));
+               text = e_dom_utils_get_selection_content_text (
+                       webkit_dom_html_iframe_element_get_content_document (WEBKIT_DOM_HTML_IFRAME_ELEMENT 
(node)));
 
-               if (text != NULL) {
+               if (text && *text) {
                        g_clear_object (&frames);
                        return text;
                }
-       }
-
-       g_clear_object (&frames);
-       return NULL;
-}
-
-gchar *
-e_dom_utils_get_selection_content_text (WebKitDOMDocument *document)
-{
-       WebKitDOMHTMLCollection *frames = NULL;
-       gulong ii, length;
-
-       frames = webkit_dom_document_get_elements_by_tag_name_as_html_collection (document, "iframe");
-       length = webkit_dom_html_collection_get_length (frames);
-
-       for (ii = 0; ii < length; ii++) {
-               gchar *text;
-               WebKitDOMNode *node;
-
-               node = webkit_dom_html_collection_item (frames, ii);
-
-               text = get_frame_selection_content_text (
-                       WEBKIT_DOM_ELEMENT (node));
 
-               if (text != NULL) {
-                       g_clear_object (&frames);
-                       return text;
-               }
+               g_free (text);
        }
 
        g_clear_object (&frames);


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