[evolution/gnome-3-16] Composer - Undo/Redo on operations with selection could be wrong



commit 010d8d216d265e56548ce8663444923a850764f1
Author: Tomas Popela <tpopela redhat com>
Date:   Thu May 7 11:55:40 2015 +0200

    Composer - Undo/Redo on operations with selection could be wrong
    
    Previously, i.e. when we selected some text and pressed the Enter the
    selected text is removed and later the new line is inserted. In some of
    these situations the removal of the selected text was not saved at all that
    later led to inconsistent undo/redo operations. Also the HISTORY_AND event
    was introduced to add a possibility to distinguish the history events that
    are supposed to be processed as one.

 e-util/e-html-editor-selection.c |   81 ++++++++++++++++++++++-
 e-util/e-html-editor-view.c      |  136 ++++++++++++++++++++++++++++++++-----
 e-util/e-html-editor-view.h      |    1 +
 3 files changed, 198 insertions(+), 20 deletions(-)
---
diff --git a/e-util/e-html-editor-selection.c b/e-util/e-html-editor-selection.c
index d3893cc..6bd49be 100644
--- a/e-util/e-html-editor-selection.c
+++ b/e-util/e-html-editor-selection.c
@@ -5282,15 +5282,23 @@ e_html_editor_selection_insert_text (EHTMLEditorSelection *selection,
        g_return_if_fail (view != NULL);
 
        if (!e_html_editor_view_is_undo_redo_in_progress (view)) {
+               gboolean collapsed;
+
                ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
                ev->type = HISTORY_PASTE;
 
+               collapsed = e_html_editor_selection_is_collapsed (selection);
                e_html_editor_selection_get_selection_coordinates (
                        selection,
                        &ev->before.start.x,
                        &ev->before.start.y,
                        &ev->before.end.x,
                        &ev->before.end.y);
+
+               if (!collapsed) {
+                       ev->before.end.x = ev->before.start.x;
+                       ev->before.end.y = ev->before.start.y;
+               }
                ev->data.string.from = NULL;
                ev->data.string.to = g_strdup (plain_text);
        }
@@ -5333,21 +5341,61 @@ e_html_editor_selection_insert_html (EHTMLEditorSelection *selection,
        g_return_if_fail (view != NULL);
 
        if (!e_html_editor_view_is_undo_redo_in_progress (view)) {
+               gboolean collapsed;
+
                ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
                ev->type = HISTORY_INSERT_HTML;
 
+               collapsed = e_html_editor_selection_is_collapsed (selection);
                e_html_editor_selection_get_selection_coordinates (
                        selection,
                        &ev->before.start.x,
                        &ev->before.start.y,
                        &ev->before.end.x,
                        &ev->before.end.y);
+               if (!collapsed) {
+                       ev->before.end.x = ev->before.start.x;
+                       ev->before.end.y = ev->before.start.y;
+               }
                ev->data.string.from = NULL;
                ev->data.string.to = g_strdup (html_text);
        }
 
        command = E_HTML_EDITOR_VIEW_COMMAND_INSERT_HTML;
        if (e_html_editor_view_get_html_mode (view)) {
+               if (!e_html_editor_selection_is_collapsed (selection)) {
+                       EHTMLEditorViewHistoryEvent *ev;
+                       WebKitDOMDocumentFragment *fragment;
+                       WebKitDOMRange *range;
+
+                       ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
+                       ev->type = HISTORY_DELETE;
+
+                       range = html_editor_selection_get_current_range (selection);
+                       fragment = webkit_dom_range_clone_contents (range, NULL);
+                       g_object_unref (range);
+                       ev->data.fragment = fragment;
+
+                       e_html_editor_selection_get_selection_coordinates (
+                               selection,
+                               &ev->before.start.x,
+                               &ev->before.start.y,
+                               &ev->before.end.x,
+                               &ev->before.end.y);
+
+                       ev->after.start.x = ev->before.start.x;
+                       ev->after.start.y = ev->before.start.y;
+                       ev->after.end.x = ev->before.start.x;
+                       ev->after.end.y = ev->before.start.y;
+
+                       e_html_editor_view_insert_new_history_event (view, ev);
+
+                       ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
+                       ev->type = HISTORY_AND;
+
+                       e_html_editor_view_insert_new_history_event (view, ev);
+               }
+
                e_html_editor_view_exec_command (view, command, html_text);
                if (strstr (html_text, "id=\"-x-evo-selection-start-marker\""))
                        e_html_editor_selection_restore (selection);
@@ -5495,9 +5543,40 @@ insert_base64_image (EHTMLEditorSelection *selection,
 
        e_html_editor_view_set_changed (view, TRUE);
 
-       if (!e_html_editor_selection_is_collapsed (selection))
+       if (!e_html_editor_selection_is_collapsed (selection)) {
+               EHTMLEditorViewHistoryEvent *ev;
+               WebKitDOMDocumentFragment *fragment;
+               WebKitDOMRange *range;
+
+               ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
+               ev->type = HISTORY_DELETE;
+
+               range = html_editor_selection_get_current_range (selection);
+               fragment = webkit_dom_range_clone_contents (range, NULL);
+               g_object_unref (range);
+               ev->data.fragment = fragment;
+
+               e_html_editor_selection_get_selection_coordinates (
+                       selection,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+
+               ev->after.start.x = ev->before.start.x;
+               ev->after.start.y = ev->before.start.y;
+               ev->after.end.x = ev->before.start.x;
+               ev->after.end.y = ev->before.start.y;
+
+               e_html_editor_view_insert_new_history_event (view, ev);
+
+               ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
+               ev->type = HISTORY_AND;
+
+               e_html_editor_view_insert_new_history_event (view, ev);
                e_html_editor_view_exec_command (
                        view, E_HTML_EDITOR_VIEW_COMMAND_DELETE, NULL);
+       }
 
        e_html_editor_selection_save (selection);
        selection_start_marker = webkit_dom_document_query_selector (
diff --git a/e-util/e-html-editor-view.c b/e-util/e-html-editor-view.c
index 33c724a..31b8479 100644
--- a/e-util/e-html-editor-view.c
+++ b/e-util/e-html-editor-view.c
@@ -280,6 +280,9 @@ print_history_event (EHTMLEditorViewHistoryEvent *event)
                case HISTORY_START:
                        printf ("HISTORY START\n");
                        break;
+               case HISTORY_AND:
+                       printf ("HISTORY AND\n");
+                       break;
                default:
                        printf ("Unknown history type\n");
        }
@@ -1811,7 +1814,7 @@ insert_dash_history_event (EHTMLEditorView *view)
 
                                diff = event->after.start.x - item->after.start.x;
 
-                               /* We need to move the coordinater of the last
+                               /* We need to move the coordinate of the last
                                 * event by one character. */
                                last->after.start.x += diff;
                                last->after.end.x += diff;
@@ -1827,6 +1830,42 @@ insert_dash_history_event (EHTMLEditorView *view)
 }
 
 static void
+insert_delete_event (EHTMLEditorView *view,
+                     WebKitDOMRange *range)
+{
+       EHTMLEditorViewHistoryEvent *ev;
+       WebKitDOMDocumentFragment *fragment;
+
+       if (view->priv->undo_redo_in_progress)
+               return;
+
+       ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
+       ev->type = HISTORY_DELETE;
+
+       fragment = webkit_dom_range_clone_contents (range, NULL);
+       ev->data.fragment = fragment;
+
+       e_html_editor_selection_get_selection_coordinates (
+               view->priv->selection,
+               &ev->before.start.x,
+               &ev->before.start.y,
+               &ev->before.end.x,
+               &ev->before.end.y);
+
+       ev->after.start.x = ev->before.start.x;
+       ev->after.start.y = ev->before.start.y;
+       ev->after.end.x = ev->before.start.x;
+       ev->after.end.y = ev->before.start.y;
+
+       e_html_editor_view_insert_new_history_event (view, ev);
+
+       ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
+       ev->type = HISTORY_AND;
+
+       e_html_editor_view_insert_new_history_event (view, ev);
+}
+
+static void
 emoticon_insert_span (EHTMLEditorView *view,
                       EEmoticon *emoticon,
                       WebKitDOMElement *span)
@@ -1866,6 +1905,15 @@ emoticon_insert_span (EHTMLEditorView *view,
                        }
                }
        } else {
+               WebKitDOMRange *tmp_range;
+
+               tmp_range = html_editor_view_get_dom_range (view);
+               insert_delete_event (view, tmp_range);
+               g_object_unref (tmp_range);
+
+               e_html_editor_view_exec_command (
+                       view, E_HTML_EDITOR_VIEW_COMMAND_DELETE, NULL);
+
                if (!view->priv->smiley_written) {
                        if (!e_html_editor_view_is_undo_redo_in_progress (view)) {
                                ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
@@ -1880,9 +1928,6 @@ emoticon_insert_span (EHTMLEditorView *view,
                        }
                }
 
-               e_html_editor_view_exec_command (
-                       view, E_HTML_EDITOR_VIEW_COMMAND_DELETE, NULL);
-
                e_html_editor_selection_save (selection);
 
                selection_start_marker = webkit_dom_document_get_element_by_id (
@@ -2494,15 +2539,16 @@ body_keypress_event_cb (WebKitDOMElement *element,
                return;
        }
 
-       if (!webkit_dom_range_get_collapsed (range, NULL)) {
+       if (!webkit_dom_range_get_collapsed (range, NULL))
+               insert_delete_event (view, range);
+
+       if (view->priv->return_key_pressed) {
                EHTMLEditorViewHistoryEvent *ev;
-               WebKitDOMDocumentFragment *fragment;
 
+               /* Insert new hiisvent for Return to have the right coordinates.
+                * The fragment will be added later. */
                ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
-               ev->type = HISTORY_DELETE;
-
-               fragment = webkit_dom_range_clone_contents (range, NULL);
-               ev->data.fragment = fragment;
+               ev->type = HISTORY_INPUT;
 
                e_html_editor_selection_get_selection_coordinates (
                        view->priv->selection,
@@ -2595,8 +2641,16 @@ save_history_for_input (EHTMLEditorView *view)
                return;
        }
 
-       ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
-       ev->type = HISTORY_INPUT;
+       if (view->priv->return_key_pressed) {
+               ev = view->priv->history->data;
+               if (ev->type != HISTORY_INPUT) {
+                       g_object_unref (dom_selection);
+                       return;
+               }
+       } else {
+               ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
+               ev->type = HISTORY_INPUT;
+       }
 
        block_selection_changed_callbacks (view);
 
@@ -2700,7 +2754,8 @@ save_history_for_input (EHTMLEditorView *view)
        unblock_selection_changed_callbacks (view);
 
        ev->data.fragment = fragment;
-       e_html_editor_view_insert_new_history_event (view, ev);
+       if (!view->priv->return_key_pressed)
+               e_html_editor_view_insert_new_history_event (view, ev);
 }
 
 static gboolean
@@ -3262,15 +3317,22 @@ clipboard_text_received_for_paste_as_text (GtkClipboard *clipboard,
        selection = e_html_editor_view_get_selection (view);
 
        if (!e_html_editor_view_is_undo_redo_in_progress (view)) {
+               gboolean collapsed;
+
                ev = g_new0 (EHTMLEditorViewHistoryEvent, 1);
                ev->type = HISTORY_PASTE_AS_TEXT;
 
+               collapsed = e_html_editor_selection_is_collapsed (selection);
                e_html_editor_selection_get_selection_coordinates (
                        selection,
                        &ev->before.start.x,
                        &ev->before.start.y,
                        &ev->before.end.x,
                        &ev->before.end.y);
+               if (!collapsed) {
+                       ev->before.end.x = ev->before.start.x;
+                       ev->before.end.y = ev->before.start.y;
+               }
                ev->data.string.from = NULL;
                ev->data.string.to = g_strdup (text);
        }
@@ -6911,6 +6973,13 @@ html_editor_view_insert_converted_html_into_selection (EHTMLEditorView *view,
        g_free (inner_html);
 
        has_selection = !e_html_editor_selection_is_collapsed (selection);
+       if (has_selection) {
+               WebKitDOMRange *range;
+
+               range = html_editor_view_get_dom_range (view);
+               insert_delete_event (view, range);
+               g_object_unref (range);
+       }
 
        citation_level = get_citation_level (WEBKIT_DOM_NODE (selection_end_marker), FALSE);
        /* Pasting into the citation */
@@ -11092,6 +11161,12 @@ restore_selection_to_history_event_state (EHTMLEditorView *view,
        g_object_unref (dom_selection);
 }
 
+static gboolean
+event_selection_was_collapsed (EHTMLEditorViewHistoryEvent *ev)
+{
+       return (ev->before.start.x == ev->before.end.x) && (ev->before.start.y == ev->before.end.y);
+}
+
 static void
 undo_delete (EHTMLEditorView *view,
             EHTMLEditorViewHistoryEvent *event)
@@ -11287,12 +11362,6 @@ undo_delete (EHTMLEditorView *view,
        g_object_unref (dom_selection);
 }
 
-static gboolean
-event_selection_was_collapsed (EHTMLEditorViewHistoryEvent *ev)
-{
-       return (ev->before.start.x == ev->before.end.x) && (ev->before.start.y == ev->before.end.y);
-}
-
 static void
 redo_delete (EHTMLEditorView *view,
             EHTMLEditorViewHistoryEvent *event)
@@ -12403,6 +12472,13 @@ e_html_editor_view_redo (EHTMLEditorView *view)
                        break;
                case HISTORY_INPUT:
                        undo_delete (view, event);
+                       {
+                               WebKitDOMRange *range;
+
+                               range = html_editor_view_get_dom_range (view);
+                               html_editor_view_check_magic_smileys (view, range);
+                               g_object_unref (range);
+                       }
                        break;
                case HISTORY_REMOVE_LINK:
                        undo_redo_remove_link (view, event, FALSE);
@@ -12451,10 +12527,22 @@ e_html_editor_view_redo (EHTMLEditorView *view)
                case HISTORY_UNQUOTE:
                        undo_redo_unquote (view, event, FALSE);
                        break;
+               case HISTORY_AND:
+                       g_warning ("Unhandled HISTORY_AND event!");
+                       break;
                default:
                        return;
        }
 
+       if (history->prev->prev) {
+               event = history->prev->prev->data;
+               if (event->type == HISTORY_AND) {
+                       view->priv->history = history->prev->prev;
+                       e_html_editor_view_redo (view);
+                       return;
+               }
+       }
+
        view->priv->history = view->priv->history->prev;
 
        d (print_history (view));
@@ -12554,10 +12642,20 @@ e_html_editor_view_undo (EHTMLEditorView *view)
                case HISTORY_UNQUOTE:
                        undo_redo_unquote (view, event, TRUE);
                        break;
+               case HISTORY_AND:
+                       g_warning ("Unhandled HISTORY_AND event!");
+                       break;
                default:
                        return;
        }
 
+       event = history->next->data;
+       if (event->type == HISTORY_AND) {
+               view->priv->history = history->next->next;
+               e_html_editor_view_undo (view);
+               return;
+       }
+
        if (history->next)
                view->priv->history = view->priv->history->next;
 
diff --git a/e-util/e-html-editor-view.h b/e-util/e-html-editor-view.h
index 83d86f6..bd61513 100644
--- a/e-util/e-html-editor-view.h
+++ b/e-util/e-html-editor-view.h
@@ -85,6 +85,7 @@ struct _EHTMLEditorViewClass {
 
 enum EHTMLEditorViewHistoryEventType {
        HISTORY_ALIGNMENT,
+       HISTORY_AND,
        HISTORY_BLOCK_FORMAT,
        HISTORY_BLOCKQUOTE,
        HISTORY_BOLD,


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