diff --git a/src/main/java/dev/kske/undoredo/Change.java b/src/main/java/dev/kske/undoredo/Change.java new file mode 100644 index 0000000..6f88984 --- /dev/null +++ b/src/main/java/dev/kske/undoredo/Change.java @@ -0,0 +1,33 @@ +package dev.kske.undoredo; + +/** + * Base interface for changes to be registered in an undo manager. + * + * @author Maximilian Käfer + * @since 0.0.1 + */ +public interface Change { + + /** + * Performs the action implemented by this change. + * + * @since 0.0.1 + */ + void apply(); + + /** + * Inverts this change. + * + * @implSpec This method is not supposed to alter the state of this change, but rather to create + * a new complementary change. + * @return the inverted change + * @since 0.0.1 + */ + Change invert(); + + /** + * @return whether the application of this change would result in an identical state + * @since 0.0.1 + */ + boolean isIdentity(); +} diff --git a/src/main/java/dev/kske/undoredo/ChangeManager.java b/src/main/java/dev/kske/undoredo/ChangeManager.java new file mode 100644 index 0000000..8f2812e --- /dev/null +++ b/src/main/java/dev/kske/undoredo/ChangeManager.java @@ -0,0 +1,100 @@ +package dev.kske.undoredo; + +import java.util.*; + +/** + * @param the change types to store in this change manager + * @author Maximilian Käfer + * @since 0.0.1 + */ +public final class ChangeManager { + + private final List changes = new LinkedList<>(); + + private int index; + private int markedIndex; + + /** + * Adds a change to the changes list. + * + * @param change the change to add + * @since 0.0.1 + */ + public void addChange(C change) { + change.apply(); + changes.add(change); + } + + /** + * Undoes the change at the current index position. + * + * @return whether the operation could be executed due to one being currently available + * @since 0.1.0 + */ + public boolean undo() { + if (isUndoAvailable()) { + changes.get(index).invert().apply(); + --index; + return true; + } + return false; + } + + /** + * Applies the change that was undone before. + * + * @return whether the operation could be executed due to one being currently available + * @since 0.0.1 + */ + public boolean redo() { + if (isRedoAvailable()) { + changes.get(index + 1).apply(); + ++index; + return true; + } + return false; + } + + /** + * Marks the current index. + * + * @since 0.0.1 + */ + public void mark() { + markedIndex = index; + } + + /** + * @return whether the current index was marked + * @since 0.0.1 + */ + public boolean isAtMarkedIndex() { + return markedIndex == index; + } + + /** + * @return whether the undo operation is currently available + * @since 0.0.1 + */ + public boolean isUndoAvailable() { + return index > 0; + } + + /** + * @return whether the redo operation is currently available. + * @since 0.0.1 + */ + public boolean isRedoAvailable() { + return index < changes.size() - 1; + } + + /** + * Provides an unmodifiable view of the changes stored in this change manager. + * + * @return all stored changes + * @since 0.0.1 + */ + public List getChanges() { + return Collections.unmodifiableList(changes); + } +}