Commit bfa1117b authored by Tomas Popela's avatar Tomas Popela

Bug 748217 - undo of Ctrl-Backspace and Ctrl-Delete is broken for multi-character strings

Correct the current undo/redo implementation of delete operation to handle
the Ctrl+Backspace and Ctrl+Delete cases.
parent 6bd55cd7
......@@ -4114,7 +4114,8 @@ fix_structure_after_delete_before_quoted_content (EHTMLEditorView *view)
static void
save_history_for_delete_or_backspace (EHTMLEditorView *view,
gboolean delete_key)
gboolean delete_key,
gboolean control_key)
{
EHTMLEditorSelection *selection;
EHTMLEditorViewHistoryEvent *ev;
......@@ -4158,46 +4159,98 @@ save_history_for_delete_or_backspace (EHTMLEditorView *view,
block_selection_changed_callbacks (view);
range_clone = webkit_dom_range_clone_range (range, NULL);
if (delete_key) {
glong offset = webkit_dom_range_get_start_offset (range_clone, NULL);
webkit_dom_range_set_end (
range_clone,
webkit_dom_range_get_end_container (range_clone, NULL),
offset + 1,
NULL);
if (control_key) {
WebKitDOMRange *tmp_range;
/* Control + Delete/Backspace deletes previous/next word. */
webkit_dom_dom_selection_modify (
dom_selection, "move", delete_key ? "right" : "left", "word");
tmp_range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
if (delete_key)
webkit_dom_range_set_end (
range_clone,
webkit_dom_range_get_end_container (tmp_range, NULL),
webkit_dom_range_get_end_offset (tmp_range, NULL),
NULL);
else
webkit_dom_range_set_start (
range_clone,
webkit_dom_range_get_start_container (tmp_range, NULL),
webkit_dom_range_get_start_offset (tmp_range, NULL),
NULL);
g_object_unref (tmp_range);
} else {
webkit_dom_range_set_start (
range_clone,
webkit_dom_range_get_start_container (range_clone, NULL),
webkit_dom_range_get_start_offset (range_clone, NULL) - 1,
NULL);
if (delete_key) {
glong offset = webkit_dom_range_get_start_offset (range_clone, NULL);
webkit_dom_range_set_end (
range_clone,
webkit_dom_range_get_end_container (range_clone, NULL),
offset + 1,
NULL);
} else {
webkit_dom_range_set_start (
range_clone,
webkit_dom_range_get_start_container (range_clone, NULL),
webkit_dom_range_get_start_offset (range_clone, NULL) - 1,
NULL);
}
}
fragment = webkit_dom_range_clone_contents (range_clone, NULL);
g_object_unref (range_clone);
if (!webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment))) {
g_free (ev);
unblock_selection_changed_callbacks (view);
g_object_unref (range);
g_object_unref (range_clone);
g_object_unref (dom_selection);
return;
}
if (delete_key) {
e_html_editor_selection_get_selection_coordinates (
selection, &ev->after.start.x, &ev->after.start.y, &ev->after.end.x, &ev->after.end.y);
if (control_key) {
if (delete_key) {
ev->after.start.x = ev->before.start.x;
ev->after.start.y = ev->before.start.y;
ev->after.end.x = ev->before.end.x;
ev->after.end.y = ev->before.end.y;
webkit_dom_range_collapse (range_clone, TRUE, NULL);
webkit_dom_dom_selection_remove_all_ranges (dom_selection);
webkit_dom_dom_selection_add_range (dom_selection, range_clone);
} else {
WebKitDOMRange *tmp_range;
tmp_range = webkit_dom_range_clone_range (range_clone, NULL);
/* Prepare the selection to the right position after
* delete and save it. */
webkit_dom_range_collapse (range_clone, TRUE, NULL);
webkit_dom_dom_selection_remove_all_ranges (dom_selection);
webkit_dom_dom_selection_add_range (dom_selection, range_clone);
e_html_editor_selection_get_selection_coordinates (
selection, &ev->after.start.x, &ev->after.start.y, &ev->after.end.x, &ev->after.end.y);
/* Restore the selection where it was before the
* history event was saved. */
webkit_dom_range_collapse (tmp_range, FALSE, NULL);
webkit_dom_dom_selection_remove_all_ranges (dom_selection);
webkit_dom_dom_selection_add_range (dom_selection, tmp_range);
g_object_unref (tmp_range);
}
} else {
webkit_dom_dom_selection_modify (dom_selection, "move", "left", "character");
e_html_editor_selection_get_selection_coordinates (
selection, &ev->after.start.x, &ev->after.start.y, &ev->after.end.x, &ev->after.end.y);
webkit_dom_dom_selection_modify (dom_selection, "move", "right", "character");
}
if (delete_key) {
e_html_editor_selection_get_selection_coordinates (
selection, &ev->after.start.x, &ev->after.start.y, &ev->after.end.x, &ev->after.end.y);
} else {
webkit_dom_dom_selection_modify (dom_selection, "move", "left", "character");
e_html_editor_selection_get_selection_coordinates (
selection, &ev->after.start.x, &ev->after.start.y, &ev->after.end.x, &ev->after.end.y);
webkit_dom_dom_selection_modify (dom_selection, "move", "right", "character");
if (!delete_key) {
ev->after.end.x = ev->after.start.x;
ev->after.end.y = ev->after.start.y;
ev->after.end.x = ev->after.start.x;
ev->after.end.y = ev->after.start.y;
}
}
g_object_unref (range_clone);
if (delete_key) {
webkit_dom_node_insert_before (
WEBKIT_DOM_NODE (fragment),
......@@ -4716,7 +4769,8 @@ html_editor_view_key_press_event (GtkWidget *widget,
}
e_html_editor_selection_restore (view->priv->selection);
}
save_history_for_delete_or_backspace (view, event->keyval == GDK_KEY_Delete);
save_history_for_delete_or_backspace (
view, event->keyval == GDK_KEY_Delete, ((event)->state & GDK_CONTROL_MASK));
if (event->keyval == GDK_KEY_BackSpace && !view->priv->html_mode) {
if (delete_character_from_quoted_line_start (view))
return TRUE;
......@@ -11007,6 +11061,7 @@ static void
undo_delete (EHTMLEditorView *view,
EHTMLEditorViewHistoryEvent *event)
{
EHTMLEditorSelection *selection;
gboolean empty, single_block;
gchar *content;
WebKitDOMDocument *document;
......@@ -11016,6 +11071,8 @@ undo_delete (EHTMLEditorView *view,
WebKitDOMElement *element;
WebKitDOMNode *first_child, *fragment;
selection = e_html_editor_view_get_selection (view);
document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (view));
dom_window = webkit_dom_document_get_default_view (document);
dom_selection = webkit_dom_dom_window_get_selection (dom_window);
......@@ -11042,11 +11099,8 @@ undo_delete (EHTMLEditorView *view,
/* Redoing Return key press */
if (empty) {
EHTMLEditorSelection *selection;
WebKitDOMNode *node;
selection = e_html_editor_view_get_selection (view);
range = get_range_for_point (document, event->before.start);
webkit_dom_dom_selection_remove_all_ranges (dom_selection);
webkit_dom_dom_selection_add_range (dom_selection, range);
......@@ -11071,14 +11125,11 @@ undo_delete (EHTMLEditorView *view,
/* Multi block delete */
if (WEBKIT_DOM_IS_ELEMENT (first_child) && !single_block) {
EHTMLEditorSelection *selection;
WebKitDOMNode *node, *parent, *last_child;
WebKitDOMNode *parent_deleted_content;
WebKitDOMNode *parent_current_block;
WebKitDOMNode *insert_before;
selection = e_html_editor_view_get_selection (view);
range = get_range_for_point (document, event->before.start);
webkit_dom_dom_selection_remove_all_ranges (dom_selection);
webkit_dom_dom_selection_add_range (dom_selection, range);
......@@ -11188,7 +11239,7 @@ undo_delete (EHTMLEditorView *view,
* otherwise the selection was not callapsed so select the deleted
* content as it was before the delete occured. */
if (webkit_dom_document_fragment_query_selector (event->data.fragment, "span#-x-evo-selection-start-marker", NULL))
e_html_editor_selection_restore (e_html_editor_view_get_selection (view));
e_html_editor_selection_restore (selection);
else
restore_selection_to_history_event_state (view, event->before);
......@@ -11201,6 +11252,12 @@ 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)
......@@ -11216,7 +11273,9 @@ redo_delete (EHTMLEditorView *view,
restore_selection_to_history_event_state (view, event->before);
if (webkit_dom_document_fragment_query_selector (fragment, "span#-x-evo-selection-start-marker", NULL)) {
gboolean delete = FALSE;
gboolean delete = FALSE, control_key = FALSE;
glong length = 1;
gint ii;
WebKitDOMDOMWindow *dom_window;
WebKitDOMDOMSelection *dom_selection;
......@@ -11224,18 +11283,32 @@ redo_delete (EHTMLEditorView *view,
g_object_unref (dom_window);
dom_selection = webkit_dom_dom_window_get_selection (dom_window);
control_key = event_selection_was_collapsed (event);
if (control_key) {
gchar *text_content;
text_content = webkit_dom_node_get_text_content (WEBKIT_DOM_NODE (fragment));
length = g_utf8_strlen (text_content, -1);
control_key = control_key && length > 1;
g_free (text_content);
}
/* Check if the event was delete or backspace press. */
delete = WEBKIT_DOM_IS_ELEMENT (first_child);
delete = delete && element_has_id (WEBKIT_DOM_ELEMENT (first_child), "-x-evo-selection-start-marker");
if (delete)
webkit_dom_dom_selection_modify (dom_selection, "extend", "right", "character");
else
webkit_dom_dom_selection_modify (dom_selection, "extend", "left", "character");
g_object_unref (dom_selection);
}
for (ii = 0; ii < length; ii++) {
e_html_editor_view_exec_command (
view,
delete ? E_HTML_EDITOR_VIEW_COMMAND_FORWARD_DELETE :
E_HTML_EDITOR_VIEW_COMMAND_DELETE,
NULL);
}
e_html_editor_view_exec_command (view, E_HTML_EDITOR_VIEW_COMMAND_DELETE, NULL);
g_object_unref (dom_selection);
} else
e_html_editor_view_exec_command (view, E_HTML_EDITOR_VIEW_COMMAND_DELETE, NULL);
e_html_editor_view_force_spell_check_for_current_paragraph (view);
}
......@@ -12356,12 +12429,6 @@ e_html_editor_view_redo (EHTMLEditorView *view)
view->priv->undo_redo_in_progress = FALSE;
}
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);
}
void
e_html_editor_view_undo (EHTMLEditorView *view)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment