summaryrefslogtreecommitdiff
path: root/src/main/java/design/model
diff options
context:
space:
mode:
authorMichael Lizzio <142752852+Michael-Lizzio@users.noreply.github.com>2025-11-11 08:17:00 -0500
committerGitHub <noreply@github.com>2025-11-11 08:17:00 -0500
commitf438bcc00e442ec18f6a0bc8715398b981b1b189 (patch)
treedf3e18485e9a4781236f3b6c5dd8fd79ecc564e3 /src/main/java/design/model
parent868e0b1e55763f2de686332b0887398839e1fe73 (diff)
parentb58b98704f6b2d2b4a5938f5a8b87eda268ad88b (diff)
downloaddesignproject-design-6-f438bcc00e442ec18f6a0bc8715398b981b1b189.tar.gz
designproject-design-6-f438bcc00e442ec18f6a0bc8715398b981b1b189.tar.bz2
designproject-design-6-f438bcc00e442ec18f6a0bc8715398b981b1b189.zip
Merge pull request #15 from RIT-SWEN-262/lizzio-UndoRedoSubsystem
Lizzio undo redo subsystem
Diffstat (limited to 'src/main/java/design/model')
-rw-r--r--src/main/java/design/model/Golfer.java51
-rw-r--r--src/main/java/design/model/holeplay/HolePlayContext.java61
-rw-r--r--src/main/java/design/model/undo/Memento.java4
-rw-r--r--src/main/java/design/model/undo/Originator.java7
-rw-r--r--src/main/java/design/model/undo/UndoManager.java91
5 files changed, 212 insertions, 2 deletions
diff --git a/src/main/java/design/model/Golfer.java b/src/main/java/design/model/Golfer.java
index 48daae8..0f4c914 100644
--- a/src/main/java/design/model/Golfer.java
+++ b/src/main/java/design/model/Golfer.java
@@ -6,8 +6,11 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import java.util.ArrayList;
import java.util.List;
+import design.model.undo.Memento;
+import design.model.undo.Originator;
+
@JsonPropertyOrder({ "clubs", "nextClubId" })
-public class Golfer {
+public class Golfer implements Originator {
private String username;
private int passwordHash;
private String fullName;
@@ -112,4 +115,50 @@ public class Golfer {
public void removeClub(Club c) {
clubs.remove(c);
}
+
+ // Takes a snapshot of the golfer
+ private static class GolferMemento implements Memento {
+ private final String username;
+ private final int passwordHash;
+ private final String fullName;
+ private final List<Course> courses;
+ private final List<Round> rounds;
+ private final List<Club> clubs;
+ private final int nextClubId;
+
+ GolferMemento(Golfer g) {
+ this.username = g.username;
+ this.passwordHash = g.passwordHash;
+ this.fullName = g.fullName;
+ this.courses = new ArrayList<>(g.courses);
+ this.rounds = new ArrayList<>(g.rounds);
+ this.clubs = new ArrayList<>(g.clubs);
+ this.nextClubId = g.nextClubId;
+ }
+ }
+
+ @Override
+ public Memento createMemento() {
+ return new GolferMemento(this);
+ }
+
+ @Override
+ public void restore(Memento memento) {
+ GolferMemento gm = (GolferMemento) memento;
+
+ this.username = gm.username;
+ this.passwordHash = gm.passwordHash;
+ this.fullName = gm.fullName;
+
+ this.courses.clear();
+ this.courses.addAll(gm.courses);
+
+ this.rounds.clear();
+ this.rounds.addAll(gm.rounds);
+
+ this.clubs.clear();
+ this.clubs.addAll(gm.clubs);
+
+ this.nextClubId = gm.nextClubId;
+ }
}
diff --git a/src/main/java/design/model/holeplay/HolePlayContext.java b/src/main/java/design/model/holeplay/HolePlayContext.java
index 7a5d8ef..71fba32 100644
--- a/src/main/java/design/model/holeplay/HolePlayContext.java
+++ b/src/main/java/design/model/holeplay/HolePlayContext.java
@@ -6,7 +6,10 @@ import java.util.ArrayList;
import design.model.*;
import design.persistence.PersonalDatabase;
-public class HolePlayContext {
+import design.model.undo.Memento;
+import design.model.undo.Originator;
+
+public class HolePlayContext implements Originator {
private final Golfer golfer;
private final Round round;
private final PersonalDatabase pdb;
@@ -109,4 +112,60 @@ public class HolePlayContext {
void setStrokes(int s) {
this.strokes = s;
}
+
+ // Captures current State, current play (hole# + swings), and stroke counter
+ private static class HolePlayMemento implements Memento {
+ private final String stateName;
+ private final Play currentPlayCopy;
+ private final int strokesCopy;
+
+ HolePlayMemento(HolePlayContext ctx) {
+ this.stateName = ctx.state.name();
+
+ // Copy currentPlay if it exists
+ Play src = ctx.currentPlay;
+ if (src != null) {
+ var copySwings = new ArrayList<Swing>();
+ for (Swing s : src.getSwings()) {
+ copySwings.add(new Swing(s.getDistance(), s.getClubUsed()));
+ }
+ this.currentPlayCopy = new Play(src.getHoleNumber(), copySwings);
+ } else {
+ this.currentPlayCopy = null;
+ }
+
+ this.strokesCopy = ctx.strokes;
+ }
+ }
+
+ @Override
+ public Memento createMemento() {
+ return new HolePlayMemento(this);
+ }
+
+ @Override
+ public void restore(Memento m) {
+ HolePlayMemento hm = (HolePlayMemento) m;
+
+ // restore strokes
+ this.strokes = hm.strokesCopy;
+
+ // restore currentPlay
+ if (hm.currentPlayCopy == null) {
+ this.currentPlay = null;
+ } else {
+ var copySwings = new ArrayList<Swing>();
+ for (Swing s : hm.currentPlayCopy.getSwings()) {
+ copySwings.add(new Swing(s.getDistance(), s.getClubUsed()));
+ }
+ this.currentPlay = new Play(hm.currentPlayCopy.getHoleNumber(), copySwings);
+ }
+
+ // restore state based on name
+ switch (hm.stateName) {
+ case "SetupState" -> this.state = new SetupState();
+ case "PlayState" -> this.state = new PlayState();
+ case "HoleCompleteState" -> this.state = new HoleCompleteState();
+ }
+ }
} \ No newline at end of file
diff --git a/src/main/java/design/model/undo/Memento.java b/src/main/java/design/model/undo/Memento.java
new file mode 100644
index 0000000..162c3f3
--- /dev/null
+++ b/src/main/java/design/model/undo/Memento.java
@@ -0,0 +1,4 @@
+package design.model.undo;
+
+public interface Memento {
+}
diff --git a/src/main/java/design/model/undo/Originator.java b/src/main/java/design/model/undo/Originator.java
new file mode 100644
index 0000000..63eac38
--- /dev/null
+++ b/src/main/java/design/model/undo/Originator.java
@@ -0,0 +1,7 @@
+package design.model.undo;
+
+public interface Originator {
+ Memento createMemento();
+
+ void restore(Memento memento);
+} \ No newline at end of file
diff --git a/src/main/java/design/model/undo/UndoManager.java b/src/main/java/design/model/undo/UndoManager.java
new file mode 100644
index 0000000..5c6a4a0
--- /dev/null
+++ b/src/main/java/design/model/undo/UndoManager.java
@@ -0,0 +1,91 @@
+package design.model.undo;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.List;
+import java.util.stream.Collectors;
+
+// Singleton caretaker that handles undo and redo stacks.
+public final class UndoManager {
+
+ private static final UndoManager INSTANCE = new UndoManager();
+
+ public static UndoManager instance() {
+ return INSTANCE;
+ }
+
+ private UndoManager() {
+ }
+
+ // Stack entry
+ private static class Entry {
+ final Originator originator;
+ final Memento memento;
+ final String label;
+
+ Entry(Originator originator, Memento memento, String label) {
+ this.originator = originator;
+ this.memento = memento;
+ this.label = label;
+ }
+ }
+
+ private final Deque<Entry> undoStack = new ArrayDeque<>();
+ private final Deque<Entry> redoStack = new ArrayDeque<>();
+
+ // Capture state
+ public void capture(Originator originator, String label) {
+ undoStack.push(new Entry(originator, originator.createMemento(), label));
+ redoStack.clear();
+ }
+
+ // Undo / Redo ops
+ public boolean canUndo() {
+ return !undoStack.isEmpty();
+ }
+
+ public boolean canRedo() {
+ return !redoStack.isEmpty();
+ }
+
+ public String peekUndoLabel() {
+ return canUndo() ? undoStack.peek().label : null;
+ }
+
+ public String peekRedoLabel() {
+ return canRedo() ? redoStack.peek().label : null;
+ }
+
+ public List<String> getUndoHistoryLabels() {
+ return undoStack.stream()
+ .map(e -> e.label)
+ .collect(Collectors.toList());
+ }
+
+ public void undo() {
+ if (!canUndo()) {
+ System.out.println("Nothing to undo.");
+ return;
+ }
+
+ Entry entry = undoStack.pop();
+ redoStack.push(new Entry(entry.originator, entry.originator.createMemento(), entry.label));
+ entry.originator.restore(entry.memento);
+ }
+
+ public void redo() {
+ if (!canRedo()) {
+ System.out.println("Nothing to redo.");
+ return;
+ }
+
+ Entry entry = redoStack.pop();
+ undoStack.push(new Entry(entry.originator, entry.originator.createMemento(), entry.label));
+ entry.originator.restore(entry.memento);
+ }
+
+ public void purge() {
+ undoStack.clear();
+ redoStack.clear();
+ }
+}