[evolution/wip/tpopela/composer-dnd: 5/6] Fix the replace dialog functionality



commit 90ffd759eca2f1d3541a2d667a07ea23f6eb0fe2
Author: Tomas Popela <tpopela redhat com>
Date:   Wed Mar 15 13:08:02 2017 +0100

    Fix the replace dialog functionality
    
    There were many problems with it:
     * We have to use the sync call to the extension while replacing the
       content as otherwise the active selection could be lost (the
       WebKitFindController could jump to another occurrence) and the
       replace could fail.
     * We were sending messages to the extension even if the searched text
       was not found.
     * While performing the 'replace all' action wrong web extension
       function was called (to replace the whole editor content) - we have
       to call the e_content_editor_replace().
     * The history was not saved at all for the 'replace all' action.
     * Undoing the replace history event was wrong as it always expected,
       that the replaced string was a word.
    
    Add two new unit tests /replace/dialog and /replace-all/dialog.

 src/e-util/test-html-editor-units.c                |   44 ++++++++++++
 src/modules/webkit-editor/e-webkit-editor.c        |   71 +++++++++++++-------
 .../web-extension/e-editor-dom-functions.c         |   35 ++++++++--
 .../web-extension/e-editor-dom-functions.h         |    4 +
 .../web-extension/e-editor-undo-redo-manager.c     |    5 +-
 .../web-extension/e-editor-web-extension.c         |   16 +++++
 6 files changed, 144 insertions(+), 31 deletions(-)
---
diff --git a/src/e-util/test-html-editor-units.c b/src/e-util/test-html-editor-units.c
index 2778855..af9c900 100644
--- a/src/e-util/test-html-editor-units.c
+++ b/src/e-util/test-html-editor-units.c
@@ -2659,6 +2659,48 @@ test_delete_after_quoted (TestFixture *fixture)
                g_test_fail ();
 }
 
+static void
+test_replace_dialog (TestFixture *fixture)
+{
+       if (!test_utils_run_simple_test (fixture,
+               "mode:plain\n"
+               "type:text to replace\n"
+               "undo:save\n"   /* 1 */
+               "seq:h\n"
+               "action:show-replace\n"
+               "type:to\t2\n"
+               "type:\t\t\t\t\t\t\n" /* Jump to 'Replace' */
+               "seq:n\n" /* Press it */
+               "seq:^\n" /* Close the dialog */
+               "undo:undo\n"
+               "undo:test:1\n"
+               "undo:redo\n",
+               HTML_PREFIX "<div style=\"width: 71ch;\">text 2 replace</div>" HTML_SUFFIX,
+               "text 2 replace"))
+               g_test_fail ();
+}
+
+static void
+test_replace_dialog_all (TestFixture *fixture)
+{
+       if (!test_utils_run_simple_test (fixture,
+               "mode:plain\n"
+               "type:text to replace\n"
+               "undo:save\n"   /* 1 */
+               "seq:h\n"
+               "action:show-replace\n"
+               "type:e\t3\n"
+               "type:\t\t\t\t\t\t\t\n" /* Jump to 'Replace All' */
+               "seq:n\n" /* Press it */
+               "seq:^\n" /* Close the dialog */
+               "undo:undo\n"
+               "undo:test:1\n"
+               "undo:redo\n",
+               HTML_PREFIX "<div style=\"width: 71ch;\">t3xt to r3plac3</div>" HTML_SUFFIX,
+               "t3xt to r3plac3"))
+               g_test_fail ();
+}
+
 gint
 main (gint argc,
       gchar *argv[])
@@ -2826,6 +2868,8 @@ main (gint argc,
        test_utils_add_test ("/undo/link-paste/plain", test_undo_link_paste_plain);
        test_utils_add_test ("/delete/quoted", test_delete_quoted);
        test_utils_add_test ("/delete/after-quoted", test_delete_after_quoted);
+       test_utils_add_test ("/replace/dialog", test_replace_dialog);
+       test_utils_add_test ("/replace-all/dialog", test_replace_dialog_all);
 
        test_add_html_editor_bug_tests ();
 
diff --git a/src/modules/webkit-editor/e-webkit-editor.c b/src/modules/webkit-editor/e-webkit-editor.c
index 053fc88..91dd309 100644
--- a/src/modules/webkit-editor/e-webkit-editor.c
+++ b/src/modules/webkit-editor/e-webkit-editor.c
@@ -131,6 +131,7 @@ struct _EWebKitEditorPrivate {
        gchar *replace_with;
        gulong found_text_handler_id;
        gulong failed_to_find_text_handler_id;
+       gboolean current_text_not_found;
 
        gboolean performing_drag;
        gulong drag_data_received_handler_id;
@@ -2474,7 +2475,7 @@ webkit_editor_replace_caret_word (EContentEditor *editor,
                return;
        }
 
-       e_util_invoke_g_dbus_proxy_call_with_error_check (
+       e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
                wk_editor->priv->web_extension,
                "DOMReplaceCaretWord",
                g_variant_new ("(ts)", current_page_id (wk_editor), replacement),
@@ -2527,10 +2528,31 @@ find_flags_to_webkit_find_options (guint32 flags /* EContentEditorFindFlags */)
 }
 
 static void
+webkit_editor_replace (EContentEditor *editor,
+                       const gchar *replacement)
+{
+       EWebKitEditor *wk_editor;
+
+       wk_editor = E_WEBKIT_EDITOR (editor);
+       if (!wk_editor->priv->web_extension) {
+               g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+               return;
+       }
+
+       e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
+               wk_editor->priv->web_extension,
+               "DOMSelectionReplace",
+               g_variant_new ("(ts)", current_page_id (wk_editor), replacement),
+               wk_editor->priv->cancellable);
+}
+
+static void
 webkit_find_controller_found_text_cb (WebKitFindController *find_controller,
                                       guint match_count,
                                       EWebKitEditor *wk_editor)
 {
+       wk_editor->priv->current_text_not_found = FALSE;
+
        if (wk_editor->priv->performing_replace_all) {
                if (!wk_editor->priv->replaced_count)
                        wk_editor->priv->replaced_count = match_count;
@@ -2538,10 +2560,7 @@ webkit_find_controller_found_text_cb (WebKitFindController *find_controller,
                /* Repeatedly search for 'word', then replace selection by
                 * 'replacement'. Repeat until there's at least one occurrence of
                 * 'word' in the document */
-               e_content_editor_insert_content (
-                       E_CONTENT_EDITOR (wk_editor),
-                       wk_editor->priv->replace_with,
-                       E_CONTENT_EDITOR_INSERT_TEXT_PLAIN);
+               webkit_editor_replace (E_CONTENT_EDITOR (wk_editor), wk_editor->priv->replace_with);
 
                webkit_find_controller_search_next (find_controller);
        } else {
@@ -2553,9 +2572,26 @@ static void
 webkit_find_controller_failed_to_find_text_cb (WebKitFindController *find_controller,
                                                EWebKitEditor *wk_editor)
 {
+       wk_editor->priv->current_text_not_found = TRUE;
+
        if (wk_editor->priv->performing_replace_all) {
                guint replaced_count = wk_editor->priv->replaced_count;
 
+               if (replaced_count > 0) {
+                       if (!wk_editor->priv->web_extension) {
+                               g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+                       } else {
+                               e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
+                                       wk_editor->priv->web_extension,
+                                       "DOMInsertReplaceAllHistoryEvent",
+                                       g_variant_new ("(tss)",
+                                               current_page_id (wk_editor),
+                                               webkit_find_controller_get_search_text (find_controller),
+                                               wk_editor->priv->replace_with),
+                                       NULL);
+                       }
+               }
+
                webkit_editor_finish_search (wk_editor);
                e_content_editor_emit_replace_all_done (E_CONTENT_EDITOR (wk_editor), replaced_count);
        } else {
@@ -2581,6 +2617,7 @@ webkit_editor_prepare_find_controller (EWebKitEditor *wk_editor)
 
        wk_editor->priv->performing_replace_all = FALSE;
        wk_editor->priv->replaced_count = 0;
+       wk_editor->priv->current_text_not_found = FALSE;
        g_free (wk_editor->priv->replace_with);
        wk_editor->priv->replace_with = NULL;
 }
@@ -2619,25 +2656,6 @@ webkit_editor_find (EContentEditor *editor,
 }
 
 static void
-webkit_editor_replace (EContentEditor *editor,
-                       const gchar *replacement)
-{
-       EWebKitEditor *wk_editor;
-
-       wk_editor = E_WEBKIT_EDITOR (editor);
-       if (!wk_editor->priv->web_extension) {
-               g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
-               return;
-       }
-
-       e_util_invoke_g_dbus_proxy_call_with_error_check (
-               wk_editor->priv->web_extension,
-               "DOMSelectionReplace",
-               g_variant_new ("(ts)", current_page_id (wk_editor), replacement),
-               wk_editor->priv->cancellable);
-}
-
-static void
 webkit_editor_replace_all (EContentEditor *editor,
                            guint32 flags,
                            const gchar *find_text,
@@ -2653,6 +2671,11 @@ webkit_editor_replace_all (EContentEditor *editor,
        wk_editor = E_WEBKIT_EDITOR (editor);
        wk_options = find_flags_to_webkit_find_options (flags);
 
+       wk_options |= WEBKIT_FIND_OPTIONS_WRAP_AROUND;
+
+       if (wk_editor->priv->current_text_not_found)
+               return;
+
        if (!wk_editor->priv->find_controller)
                webkit_editor_prepare_find_controller (wk_editor);
 
diff --git a/src/modules/webkit-editor/web-extension/e-editor-dom-functions.c 
b/src/modules/webkit-editor/web-extension/e-editor-dom-functions.c
index bd8481c..4ec1a8d 100644
--- a/src/modules/webkit-editor/web-extension/e-editor-dom-functions.c
+++ b/src/modules/webkit-editor/web-extension/e-editor-dom-functions.c
@@ -17341,6 +17341,28 @@ e_editor_dom_selection_set_alignment (EEditorPage *editor_page,
        e_editor_page_emit_content_changed (editor_page);
 }
 
+void
+e_editor_dom_insert_replace_all_history_event (EEditorPage *editor_page,
+                                               const gchar *search_text,
+                                               const gchar *replacement)
+{
+       EEditorUndoRedoManager *manager;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               EEditorHistoryEvent *ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_REPLACE_ALL;
+
+               ev->data.string.from = g_strdup (search_text);
+               ev->data.string.to = g_strdup (replacement);
+
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+}
+
 /*
  * e_html_editor_selection_replace:
  * @selection: an #EEditorSelection
@@ -17354,14 +17376,17 @@ e_editor_dom_selection_replace (EEditorPage *editor_page,
 {
        EEditorHistoryEvent *ev = NULL;
        EEditorUndoRedoManager *manager;
+       WebKitDOMRange *range = NULL;
 
        g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
 
        manager = e_editor_page_get_undo_redo_manager (editor_page);
 
-       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
-               WebKitDOMRange *range = NULL;
+       if (!(range = e_editor_dom_get_current_range (editor_page)) ||
+            e_editor_dom_selection_is_collapsed (editor_page))
+               return;
 
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
                ev = g_new0 (EEditorHistoryEvent, 1);
                ev->type = HISTORY_REPLACE;
 
@@ -17371,14 +17396,12 @@ e_editor_dom_selection_replace (EEditorPage *editor_page,
                        &ev->before.end.x,
                        &ev->before.end.y);
 
-               range = e_editor_dom_get_current_range (editor_page);
-
                ev->data.string.from = webkit_dom_range_get_text (range);
                ev->data.string.to = g_strdup (replacement);
-
-               g_clear_object (&range);
        }
 
+       g_clear_object (&range);
+
        e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_INSERT_TEXT, replacement);
 
        if (ev) {
diff --git a/src/modules/webkit-editor/web-extension/e-editor-dom-functions.h 
b/src/modules/webkit-editor/web-extension/e-editor-dom-functions.h
index 226cde1..04cb85f 100644
--- a/src/modules/webkit-editor/web-extension/e-editor-dom-functions.h
+++ b/src/modules/webkit-editor/web-extension/e-editor-dom-functions.h
@@ -349,6 +349,10 @@ EContentEditorAlignment
 void           e_editor_dom_selection_set_alignment
                                                (EEditorPage *editor_page,
                                                 EContentEditorAlignment alignment);
+void           e_editor_dom_insert_replace_all_history_event
+                                               (EEditorPage *editor_page,
+                                                const gchar *search_text,
+                                                const gchar *replacement);
 void           e_editor_dom_selection_replace  (EEditorPage *editor_page,
                                                 const gchar *replacement);
 void           e_editor_dom_replace_caret_word (EEditorPage *editor_page,
diff --git a/src/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c 
b/src/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c
index 541ff49..2f4831a 100644
--- a/src/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c
+++ b/src/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c
@@ -1625,6 +1625,7 @@ undo_redo_replace (EEditorPage *editor_page,
        e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : 
event->before);
 
        if (undo) {
+               gint ii = 0;
                WebKitDOMDOMWindow *dom_window = NULL;
                WebKitDOMDOMSelection *dom_selection = NULL;
 
@@ -1632,7 +1633,9 @@ undo_redo_replace (EEditorPage *editor_page,
                dom_selection = webkit_dom_dom_window_get_selection (dom_window);
                g_clear_object (&dom_window);
 
-               webkit_dom_dom_selection_modify (dom_selection, "extend", "left", "word");
+               for (ii = g_utf8_strlen (event->data.string.to, -1); ii--;)
+                       webkit_dom_dom_selection_modify (dom_selection, "extend", "left", "character");
+
                g_clear_object (&dom_selection);
        }
 
diff --git a/src/modules/webkit-editor/web-extension/e-editor-web-extension.c 
b/src/modules/webkit-editor/web-extension/e-editor-web-extension.c
index 8f27eee..d9477db 100644
--- a/src/modules/webkit-editor/web-extension/e-editor-web-extension.c
+++ b/src/modules/webkit-editor/web-extension/e-editor-web-extension.c
@@ -501,6 +501,11 @@ static const gchar *introspection_xml =
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='s' name='uri' direction='in'/>"
 "    </method>"
+"    <method name='DOMInsertReplaceAllHistoryEvent'>"
+"      <arg type='t' name='page_id' direction='in'/>"
+"      <arg type='s' name='search_text' direction='in'/>"
+"      <arg type='s' name='replacement' direction='in'/>"
+"    </method>"
 "    <method name='DOMSelectionReplace'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='s' name='replacement' direction='in'/>"
@@ -1918,6 +1923,17 @@ handle_method_call (GDBusConnection *connection,
                e_editor_dom_insert_image (editor_page, uri);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
+       } else if (g_strcmp0 (method_name, "DOMInsertReplaceAllHistoryEvent") == 0) {
+               const gchar *replacement, *search_text;
+
+               g_variant_get (parameters, "(t&s&s)", &page_id, &search_text, &replacement);
+
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
+                       goto error;
+
+               e_editor_dom_insert_replace_all_history_event (editor_page, search_text, replacement);
+               g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMSelectionReplace") == 0) {
                const gchar *replacement;
 


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