diff --git a/richtextfx/src/integrationTest/java/org/fxmisc/richtext/api/UndoManagerTests.java b/richtextfx/src/integrationTest/java/org/fxmisc/richtext/api/UndoManagerTests.java index 00072eb17..8302b57e7 100644 --- a/richtextfx/src/integrationTest/java/org/fxmisc/richtext/api/UndoManagerTests.java +++ b/richtextfx/src/integrationTest/java/org/fxmisc/richtext/api/UndoManagerTests.java @@ -44,19 +44,38 @@ public void incoming_change_is_not_merged_after_period_of_user_inactivity() { } @Test // After undo, text insertion point jumps to the start of the text area #780 + // After undo, text insertion point jumps to the end of the text area #912 public void undo_leaves_correct_insertion_point() { - long periodOfUserInactivity = UndoUtils.DEFAULT_PREVENT_MERGE_DELAY.toMillis() + 300L; - - write("abc def "); - sleep(periodOfUserInactivity); - - write("xyz"); - interact(area::undo); - write('g'); + write("abc mno"); + interact(() -> { + area.insertText(3," def"); + area.appendText(" xyz"); + }); - sleep(periodOfUserInactivity); - assertTrue(area.getText().endsWith("g")); + assertEquals("abc def mno xyz",area.getText()); + + interact(area::undo); // removes " xyz" + assertEquals("abc def mno",area.getText()); + // ^ + assertEquals( area.getCaretPosition(), area.getSelection().getStart() ); + assertEquals( 11, area.getSelection().getStart() ); + + interact(area::undo); // removes " def" + assertEquals("abc mno",area.getText()); + // ^ + assertEquals( area.getCaretPosition(), area.getSelection().getStart() ); + assertEquals( 3, area.getSelection().getStart() ); + + interact(area::redo); // restore " def" + assertEquals("abc def mno",area.getText()); + // ^ + assertEquals( area.getCaretPosition(), area.getSelection().getStart() ); + assertEquals( 7, area.getSelection().getStart() ); + + interact(area::undo); // removes " def" + interact(() -> area.insertText(area.getCaretPosition()," ?")); + assertEquals("abc ? mno",area.getText()); } @Test diff --git a/richtextfx/src/main/java/org/fxmisc/richtext/util/UndoUtils.java b/richtextfx/src/main/java/org/fxmisc/richtext/util/UndoUtils.java index acf9c87ac..7a8e9bdce 100644 --- a/richtextfx/src/main/java/org/fxmisc/richtext/util/UndoUtils.java +++ b/richtextfx/src/main/java/org/fxmisc/richtext/util/UndoUtils.java @@ -214,7 +214,10 @@ public static UndoManager> plainTextUndoManag * by {@code area.replaceText(change.getPosition(), change.getRemovalEnd(), change.getInserted()}. */ public static Consumer applyPlainTextChange(GenericStyledArea area) { - return change -> area.replaceText(change.getPosition(), change.getRemovalEnd(), change.getInserted()); + return change -> { + area.replaceText(change.getPosition(), change.getRemovalEnd(), change.getInserted()); + moveToChange( area, change ); + }; } /** @@ -223,7 +226,10 @@ public static Consumer applyPlainTextChange(Generi */ public static Consumer> applyRichTextChange( GenericStyledArea area) { - return change -> area.replace(change.getPosition(), change.getRemovalEnd(), change.getInserted()); + return change -> { + area.replace(change.getPosition(), change.getRemovalEnd(), change.getInserted()); + moveToChange( area, change ); + }; } /** @@ -238,6 +244,7 @@ public static Consumer> applyMultiPlainTextCh builder.replaceTextAbsolutely(c.getPosition(), c.getRemovalEnd(), c.getInserted()); } builder.commit(); + moveToChange( area, changeList.get( changeList.size()-1 ) ); }; } @@ -253,7 +260,19 @@ public static Consumer>> applyMulti builder.replaceAbsolutely(c.getPosition(), c.getRemovalEnd(), c.getInserted()); } builder.commit(); + moveToChange( area, changeList.get( changeList.size()-1 ) ); }; } + /* + * Address #912 "After undo/redo, new text is inserted at the end". + * Without breaking PositionTests. (org.fxmisc.richtext.api.caret) + */ + private static void moveToChange( GenericStyledArea area, TextChange chg ) { + int pos = chg.getPosition(), len = chg.getNetLength(); + if ( len > 0 ) { + pos = Math.min( pos + Math.abs(len), area.getLength() ); + } + area.moveTo( pos ); + } }