diff --git a/app/src/processing/app/CaretAwareUndoableEdit.java b/app/src/processing/app/CaretAwareUndoableEdit.java new file mode 100644 index 000000000..ba8e67d85 --- /dev/null +++ b/app/src/processing/app/CaretAwareUndoableEdit.java @@ -0,0 +1,77 @@ +package processing.app; + +import processing.app.syntax.JEditTextArea; + +import javax.swing.undo.CannotRedoException; +import javax.swing.undo.CannotUndoException; +import javax.swing.undo.UndoableEdit; + +public class CaretAwareUndoableEdit implements UndoableEdit { + + private final UndoableEdit undoableEdit; + private final int caretPosition; + + public CaretAwareUndoableEdit(UndoableEdit undoableEdit, JEditTextArea textArea) { + this.undoableEdit = undoableEdit; + this.caretPosition = textArea.getCaretPosition(); + } + + @Override + public void undo() throws CannotUndoException { + undoableEdit.undo(); + } + + @Override + public boolean canUndo() { + return undoableEdit.canUndo(); + } + + @Override + public void redo() throws CannotRedoException { + undoableEdit.redo(); + } + + @Override + public boolean canRedo() { + return undoableEdit.canRedo(); + } + + @Override + public void die() { + undoableEdit.die(); + } + + @Override + public boolean addEdit(UndoableEdit undoableEdit) { + return this.undoableEdit.addEdit(undoableEdit); + } + + @Override + public boolean replaceEdit(UndoableEdit undoableEdit) { + return this.undoableEdit.replaceEdit(undoableEdit); + } + + @Override + public boolean isSignificant() { + return undoableEdit.isSignificant(); + } + + @Override + public String getPresentationName() { + return undoableEdit.getPresentationName(); + } + + @Override + public String getUndoPresentationName() { + return undoableEdit.getUndoPresentationName(); + } + + @Override + public String getRedoPresentationName() { + return undoableEdit.getRedoPresentationName(); + } + + public int getCaretPosition() { + return caretPosition; + } +} diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 1f55fa733..f99ced0b1 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -137,7 +137,7 @@ public class Editor extends JFrame implements RunnerListener { JMenuItem undoItem, redoItem; protected UndoAction undoAction; protected RedoAction redoAction; - UndoManager undo; + LastUndoableEditAwareUndoManager undo; // used internally, and only briefly CompoundEdit compoundEdit; @@ -1344,6 +1344,10 @@ public class Editor extends JFrame implements RunnerListener { //System.out.println("Unable to undo: " + ex); //ex.printStackTrace(); } + if (undo.getLastUndoableEdit() != null && undo.getLastUndoableEdit() instanceof CaretAwareUndoableEdit) { + CaretAwareUndoableEdit undoableEdit = (CaretAwareUndoableEdit) undo.getLastUndoableEdit(); + textarea.setCaretPosition(undoableEdit.getCaretPosition() - 1); + } updateUndoState(); redoAction.updateRedoState(); } @@ -1383,6 +1387,10 @@ public class Editor extends JFrame implements RunnerListener { //System.out.println("Unable to redo: " + ex); //ex.printStackTrace(); } + if (undo.getLastUndoableEdit() != null && undo.getLastUndoableEdit() instanceof CaretAwareUndoableEdit) { + CaretAwareUndoableEdit undoableEdit = (CaretAwareUndoableEdit) undo.getLastUndoableEdit(); + textarea.setCaretPosition(undoableEdit.getCaretPosition()); + } updateRedoState(); undoAction.updateUndoState(); } @@ -1664,7 +1672,7 @@ public class Editor extends JFrame implements RunnerListener { compoundEdit.addEdit(e.getEdit()); } else if (undo != null) { - undo.addEdit(e.getEdit()); + undo.addEdit(new CaretAwareUndoableEdit(e.getEdit(), textarea)); undoAction.updateUndoState(); redoAction.updateRedoState(); } diff --git a/app/src/processing/app/LastUndoableEditAwareUndoManager.java b/app/src/processing/app/LastUndoableEditAwareUndoManager.java new file mode 100644 index 000000000..336cfe15f --- /dev/null +++ b/app/src/processing/app/LastUndoableEditAwareUndoManager.java @@ -0,0 +1,31 @@ +package processing.app; + +import javax.swing.undo.CannotRedoException; +import javax.swing.undo.CannotUndoException; +import javax.swing.undo.UndoManager; +import javax.swing.undo.UndoableEdit; + +public class LastUndoableEditAwareUndoManager extends UndoManager { + + private UndoableEdit lastUndoableEdit; + + public LastUndoableEditAwareUndoManager() { + this.lastUndoableEdit = null; + } + + @Override + public synchronized void undo() throws CannotUndoException { + lastUndoableEdit = super.editToBeUndone(); + super.undo(); + } + + @Override + public synchronized void redo() throws CannotRedoException { + lastUndoableEdit = super.editToBeRedone(); + super.redo(); + } + + public UndoableEdit getLastUndoableEdit() { + return lastUndoableEdit; + } +} diff --git a/app/src/processing/app/SketchCode.java b/app/src/processing/app/SketchCode.java index 6498cf4ba..37e63ed71 100644 --- a/app/src/processing/app/SketchCode.java +++ b/app/src/processing/app/SketchCode.java @@ -27,7 +27,7 @@ package processing.app; import java.io.*; import javax.swing.text.Document; -import javax.swing.undo.*; + import static processing.app.I18n._; @@ -55,7 +55,7 @@ public class SketchCode { * Editor.undo will be set to this object when this code is the tab * that's currently the front. */ - private UndoManager undo = new UndoManager(); + private LastUndoableEditAwareUndoManager undo = new LastUndoableEditAwareUndoManager(); // saved positions from last time this tab was used private int selectionStart; @@ -221,7 +221,7 @@ public class SketchCode { } - public UndoManager getUndo() { + public LastUndoableEditAwareUndoManager getUndo() { return undo; }