diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 3cf54e010..bcd802eff 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -232,6 +232,7 @@ public class Editor extends JFrame implements RunnerListener { upper.add(header); textarea = new JEditTextArea(new PdeTextAreaDefaults()); + textarea.setName("editor"); textarea.setRightClickPopup(new TextAreaPopup()); textarea.setHorizontalOffset(6); @@ -1135,9 +1136,11 @@ public class Editor extends JFrame implements RunnerListener { protected JMenu buildEditMenu() { JMenu menu = new JMenu(_("Edit")); + menu.setName("menuEdit"); JMenuItem item; undoItem = newJMenuItem(_("Undo"), 'Z'); + undoItem.setName("menuEditUndo"); undoItem.addActionListener(undoAction = new UndoAction()); menu.add(undoItem); @@ -1146,6 +1149,7 @@ public class Editor extends JFrame implements RunnerListener { } else { redoItem = newJMenuItemShift(_("Redo"), 'Z'); } + redoItem.setName("menuEditRedo"); redoItem.addActionListener(redoAction = new RedoAction()); menu.add(redoItem); @@ -1345,7 +1349,10 @@ public class Editor extends JFrame implements RunnerListener { } if (undo.getLastUndoableEdit() != null && undo.getLastUndoableEdit() instanceof CaretAwareUndoableEdit) { CaretAwareUndoableEdit undoableEdit = (CaretAwareUndoableEdit) undo.getLastUndoableEdit(); - textarea.setCaretPosition(undoableEdit.getCaretPosition() - 1); + int nextCaretPosition = undoableEdit.getCaretPosition() - 1; + if (nextCaretPosition >= 0 && textarea.getDocumentLength() > nextCaretPosition) { + textarea.setCaretPosition(nextCaretPosition); + } } updateUndoState(); redoAction.updateRedoState(); diff --git a/app/test/processing/app/ReplacingTextGeneratesTwoUndoActionsTest.java b/app/test/processing/app/ReplacingTextGeneratesTwoUndoActionsTest.java new file mode 100644 index 000000000..b9a3ef22a --- /dev/null +++ b/app/test/processing/app/ReplacingTextGeneratesTwoUndoActionsTest.java @@ -0,0 +1,66 @@ +package processing.app; + +import org.fest.swing.core.ComponentMatcher; +import org.fest.swing.fixture.FrameFixture; +import org.fest.swing.fixture.JMenuItemFixture; +import org.junit.Before; +import org.junit.Test; +import processing.app.syntax.JEditTextArea; + +import javax.swing.*; +import java.awt.*; + +import static org.junit.Assert.assertEquals; + +public class ReplacingTextGeneratesTwoUndoActionsTest { + + private FrameFixture window; + private Base base; + + @Before + public void setUp() throws Exception { + Base.initPlatform(); + Preferences.init(null); + JPopupMenu.setDefaultLightWeightPopupEnabled(false); + Theme.init(); + Base.platform.setLookAndFeel(); + Base.untitledFolder = Base.createTempFolder("untitled"); + Base.untitledFolder.deleteOnExit(); + + base = new Base(new String[0]); + window = new FrameFixture(base.editors.get(0)); + } + + @Test + public void testName() throws Exception { + JMenuItemFixture menuEditUndo = window.menuItem("menuEditUndo"); + menuEditUndo.requireDisabled(); + JMenuItemFixture menuEditRedo = window.menuItem("menuEditRedo"); + menuEditRedo.requireDisabled(); + + JEditTextArea jEditTextArea = (JEditTextArea) window.robot.finder().find(new ComponentMatcher() { + @Override + public boolean matches(Component component) { + return component instanceof JEditTextArea && "editor".equals(component.getName()); + } + }); + + jEditTextArea.setText("fake text"); + + menuEditUndo.requireEnabled(); + menuEditUndo.click(); + + assertEquals("", jEditTextArea.getText()); + + menuEditRedo.requireEnabled(); + menuEditRedo.click(); + + assertEquals("fake text", jEditTextArea.getText()); + + menuEditUndo.requireEnabled(); + menuEditUndo.click(); + menuEditUndo.click(); + menuEditUndo.requireDisabled(); + menuEditRedo.requireEnabled(); + } +}