diff --git a/undofx-demos/src/main/java/org/fxmisc/undo/demo/CircleProperties.java b/undofx-demos/src/main/java/org/fxmisc/undo/demo/CircleProperties.java index cc92ab5..0a55bc3 100644 --- a/undofx-demos/src/main/java/org/fxmisc/undo/demo/CircleProperties.java +++ b/undofx-demos/src/main/java/org/fxmisc/undo/demo/CircleProperties.java @@ -173,7 +173,7 @@ public boolean equals(Object other) { private final Button redoBtn = new Button("Redo"); private final Button saveBtn = new Button("Save"); private final EventStream> changes; - private final UndoManager undoManager; + private final UndoManager> undoManager; { circle.fillProperty().bind(colorPicker.valueProperty()); diff --git a/undofx/src/main/java/org/fxmisc/undo/UndoManager.java b/undofx/src/main/java/org/fxmisc/undo/UndoManager.java index 2b560ee..ef4128b 100644 --- a/undofx/src/main/java/org/fxmisc/undo/UndoManager.java +++ b/undofx/src/main/java/org/fxmisc/undo/UndoManager.java @@ -4,7 +4,7 @@ import org.reactfx.value.Val; -public interface UndoManager { +public interface UndoManager { /** * Represents a position in UndoManager's history. @@ -48,6 +48,18 @@ interface UndoPosition { Val undoAvailableProperty(); boolean isUndoAvailable(); + /** + * Gives a peek at the change that will be undone by {@link #undo()}. + */ + Val nextToUndoProperty(); + default C getNextToUndo() { return nextToUndoProperty().getValue(); } + + /** + * Gives a peek at the change that will be redone by {@link #redo()}. + */ + Val nextToRedoProperty(); + default C getNextToRedo() { return nextToRedoProperty().getValue(); } + /** * Indicates whether there is a change that can be redone. */ diff --git a/undofx/src/main/java/org/fxmisc/undo/UndoManagerFactory.java b/undofx/src/main/java/org/fxmisc/undo/UndoManagerFactory.java index 4c01f96..ce0242a 100644 --- a/undofx/src/main/java/org/fxmisc/undo/UndoManagerFactory.java +++ b/undofx/src/main/java/org/fxmisc/undo/UndoManagerFactory.java @@ -26,7 +26,7 @@ public interface UndoManagerFactory { * describes an action to be performed. Calling {@code apply.accept(c)} * must cause {@code c} to be emitted from {@code changeStream}. */ - default UndoManager create( + default UndoManager create( EventStream changeStream, Function invert, Consumer apply) { @@ -46,7 +46,7 @@ default UndoManager create( * @param merge Used to merge two subsequent changes into one. * Returns an empty {@linkplain Optional} when the changes cannot or should not be merged. */ - default UndoManager create( + default UndoManager create( EventStream changeStream, Function invert, Consumer apply, @@ -72,7 +72,7 @@ default UndoManager create( * @param isIdentity returns true for changes whose application would have no effect, thereby equivalent * to an identity function ({@link Function#identity()}) on the underlying model. */ - UndoManager create( + UndoManager create( EventStream changeStream, Function invert, Consumer apply, @@ -84,7 +84,7 @@ UndoManager create( * * For description of parameters, see {@link #create(EventStream, Function, Consumer)}. */ - public static UndoManager unlimitedHistoryUndoManager( + public static UndoManager unlimitedHistoryUndoManager( EventStream changeStream, Function invert, Consumer apply) { @@ -96,7 +96,7 @@ public static UndoManager unlimitedHistoryUndoManager( * * For description of parameters, see {@link #create(EventStream, Function, Consumer, BiFunction)}. */ - public static UndoManager unlimitedHistoryUndoManager( + public static UndoManager unlimitedHistoryUndoManager( EventStream changeStream, Function invert, Consumer apply, @@ -108,7 +108,7 @@ public static UndoManager unlimitedHistoryUndoManager( * * For description of parameters, see {@link #create(EventStream, Function, Consumer, BiFunction, Predicate)}. */ - public static UndoManager unlimitedHistoryUndoManager( + public static UndoManager unlimitedHistoryUndoManager( EventStream changeStream, Function invert, Consumer apply, @@ -124,7 +124,7 @@ public static UndoManager unlimitedHistoryUndoManager( public static UndoManagerFactory unlimitedHistoryFactory() { return new UndoManagerFactory() { @Override - public UndoManager create( + public UndoManager create( EventStream changeStream, Function invert, Consumer apply, @@ -143,7 +143,7 @@ public UndoManager create( * * @param capacity maximum number of changes the returned UndoManager can store */ - public static UndoManager fixedSizeHistoryUndoManager( + public static UndoManager fixedSizeHistoryUndoManager( EventStream changeStream, Function invert, Consumer apply, @@ -159,7 +159,7 @@ public static UndoManager fixedSizeHistoryUndoManager( * * @param capacity maximum number of changes the returned UndoManager can store */ - public static UndoManager fixedSizeHistoryUndoManager( + public static UndoManager fixedSizeHistoryUndoManager( EventStream changeStream, Function invert, Consumer apply, @@ -176,7 +176,7 @@ public static UndoManager fixedSizeHistoryUndoManager( * * @param capacity maximum number of changes the returned UndoManager can store */ - public static UndoManager fixedSizeHistoryUndoManager( + public static UndoManager fixedSizeHistoryUndoManager( EventStream changeStream, Function invert, Consumer apply, @@ -194,7 +194,7 @@ public static UndoManager fixedSizeHistoryUndoManager( public static UndoManagerFactory fixedSizeHistoryFactory(int capacity) { return new UndoManagerFactory() { @Override - public UndoManager create( + public UndoManager create( EventStream changeStream, Function invert, Consumer apply, @@ -213,7 +213,7 @@ public UndoManager create( * {@link UndoManager#atMarkedPositionProperty()} to determine whether any change has occurred since the last * {@link UndoManager#mark()} (e.g. since the last save). */ - public static UndoManager zeroHistoryUndoManager(EventStream changeStream) { + public static UndoManager zeroHistoryUndoManager(EventStream changeStream) { ChangeQueue queue = new ZeroSizeChangeQueue<>(); return new UndoManagerImpl<>(queue, c -> c, c -> {}, (c1, c2) -> Optional.empty(), c -> false, changeStream); } @@ -226,7 +226,7 @@ public static UndoManager zeroHistoryUndoManager(EventStream changeStream public static UndoManagerFactory zeroHistoryFactory() { return new UndoManagerFactory() { @Override - public UndoManager create( + public UndoManager create( EventStream changeStream, Function invert, Consumer apply, diff --git a/undofx/src/main/java/org/fxmisc/undo/impl/UndoManagerImpl.java b/undofx/src/main/java/org/fxmisc/undo/impl/UndoManagerImpl.java index 796f87b..9d6f124 100644 --- a/undofx/src/main/java/org/fxmisc/undo/impl/UndoManagerImpl.java +++ b/undofx/src/main/java/org/fxmisc/undo/impl/UndoManagerImpl.java @@ -18,7 +18,7 @@ import org.reactfx.value.Val; import org.reactfx.value.ValBase; -public class UndoManagerImpl implements UndoManager { +public class UndoManagerImpl implements UndoManager { private class UndoPositionImpl implements UndoPosition { private final QueuePosition queuePos; @@ -118,6 +118,16 @@ public boolean redo() { } } + @Override + public Val nextToUndoProperty() { + return nextToUndo; + } + + @Override + public Val nextToRedoProperty() { + return nextToRedo; + } + @Override public boolean isUndoAvailable() { return nextToUndo.isPresent(); diff --git a/undofx/src/test/java/org/fxmisc/undo/impl/UndoManagerTest.java b/undofx/src/test/java/org/fxmisc/undo/impl/UndoManagerTest.java index a489ab0..217564e 100644 --- a/undofx/src/test/java/org/fxmisc/undo/impl/UndoManagerTest.java +++ b/undofx/src/test/java/org/fxmisc/undo/impl/UndoManagerTest.java @@ -20,7 +20,7 @@ public class UndoManagerTest { public void testUndoInvertsTheChange() { EventSource changes = new EventSource<>(); Var lastAction = Var.newSimpleVar(null); - UndoManager um = UndoManagerFactory.unlimitedHistoryUndoManager( + UndoManager um = UndoManagerFactory.unlimitedHistoryUndoManager( changes, i -> -i, i -> { lastAction.setValue(i); changes.push(i); }); changes.push(3); @@ -43,7 +43,7 @@ public void testUndoInvertsTheChange() { @Test public void testMark() { EventSource changes = new EventSource<>(); - UndoManager um = UndoManagerFactory.fixedSizeHistoryUndoManager( + UndoManager um = UndoManagerFactory.fixedSizeHistoryUndoManager( changes, c -> c, changes::push, 4); assertTrue(um.atMarkedPositionProperty().get()); @@ -68,7 +68,7 @@ public void testMark() { @Test public void testPositionValidAfterAddingAChange() { EventSource changes = new EventSource<>(); - UndoManager um = UndoManagerFactory.unlimitedHistoryUndoManager(changes, c -> c, changes::push); + UndoManager um = UndoManagerFactory.unlimitedHistoryUndoManager(changes, c -> c, changes::push); changes.push(1); UndoPosition pos = um.getCurrentPosition(); @@ -79,7 +79,7 @@ public void testPositionValidAfterAddingAChange() { @Test public void testPositionInvalidAfterMerge() { EventSource changes = new EventSource<>(); - UndoManager um = UndoManagerFactory.unlimitedHistoryUndoManager( + UndoManager um = UndoManagerFactory.unlimitedHistoryUndoManager( changes, c -> -c, changes::push, (c1, c2) -> Optional.of(c1 + c2)); changes.push(1); @@ -91,7 +91,7 @@ public void testPositionInvalidAfterMerge() { @Test public void testRedoUnavailableAfterAnnihilation() { EventSource changes = new EventSource<>(); - UndoManager um = UndoManagerFactory.unlimitedHistoryUndoManager( + UndoManager um = UndoManagerFactory.unlimitedHistoryUndoManager( changes, c -> -c, changes::push, (c1, c2) -> Optional.of(c1 + c2), c -> c == 0); changes.push(1); @@ -102,7 +102,7 @@ public void testRedoUnavailableAfterAnnihilation() { @Test public void zeroHistoryUndoManagerMark() { EventSource changes = new EventSource<>(); - UndoManager um = UndoManagerFactory.zeroHistoryUndoManager(changes); + UndoManager um = UndoManagerFactory.zeroHistoryUndoManager(changes); assertTrue(um.atMarkedPositionProperty().get()); changes.push(1); @@ -122,7 +122,7 @@ public void zeroHistoryUndoManagerMark() { @Test public void testAtMarkedPositionRevalidation() { EventSource changes = new EventSource<>(); - UndoManager um = UndoManagerFactory.zeroHistoryUndoManager(changes); + UndoManager um = UndoManagerFactory.zeroHistoryUndoManager(changes); um.atMarkedPositionProperty().get(); // atMarkedPositionProperty is now valid @@ -142,7 +142,7 @@ public void testAtMarkedPositionRevalidation() { @Test(expected = IllegalStateException.class) public void testFailFastWhenExpectedChangeNotReceived() { EventSource changes = new EventSource<>(); - UndoManager um = UndoManagerFactory.unlimitedHistoryUndoManager( + UndoManager um = UndoManagerFactory.unlimitedHistoryUndoManager( changes, i -> -i, i -> {}); changes.push(1); @@ -156,7 +156,7 @@ public void testFailFastWhenExpectedChangeNotReceived() { public void testPushedNonIdentityChangeIsStored() { SimpleIntegerProperty lastAppliedValue = new SimpleIntegerProperty(0); EventSource changes = new EventSource<>(); - UndoManager um = UndoManagerFactory.unlimitedHistoryUndoManager( + UndoManager um = UndoManagerFactory.unlimitedHistoryUndoManager( changes, i -> -i, // invert i -> { lastAppliedValue.set(i); changes.push(i); }, // apply change and re-emit value so expected change is received @@ -174,7 +174,7 @@ public void testPushedNonIdentityChangeIsStored() { public void testPushedIdentityChangeIsNotStored() { SimpleIntegerProperty lastAppliedValue = new SimpleIntegerProperty(0); EventSource changes = new EventSource<>(); - UndoManager um = UndoManagerFactory.unlimitedHistoryUndoManager( + UndoManager um = UndoManagerFactory.unlimitedHistoryUndoManager( changes, i -> -i, // invert i -> { lastAppliedValue.set(i); changes.push(i); }, // apply change and re-emit value so expected change is received @@ -195,7 +195,7 @@ public void testPushedIdentityChangeIsNotStored() { public void testMergeResultingInIdentityChangeAnnihilatesBothAndPreventsNextMerge() { SimpleIntegerProperty lastAppliedValue = new SimpleIntegerProperty(0); EventSource changes = new EventSource<>(); - UndoManager um = UndoManagerFactory.unlimitedHistoryUndoManager( + UndoManager um = UndoManagerFactory.unlimitedHistoryUndoManager( changes, i -> -i, // invert i -> { lastAppliedValue.set(i); changes.push(i); }, // apply change and re-emit value so expected change is received @@ -229,7 +229,7 @@ public void testMergeResultingInIdentityChangeAnnihilatesBothAndPreventsNextMerg public void testMergeResultingInNonIdentityChangeStoresMergeAndPreventsNextMerge() { SimpleIntegerProperty lastAppliedValue = new SimpleIntegerProperty(0); EventSource changes = new EventSource<>(); - UndoManager um = UndoManagerFactory.unlimitedHistoryUndoManager( + UndoManager um = UndoManagerFactory.unlimitedHistoryUndoManager( changes, i -> -i, // invert i -> { lastAppliedValue.set(i); changes.push(i); }, // apply change and re-emit value so expected change is received