Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Undo and Redo commands #20

Merged
merged 31 commits into from
Mar 29, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
6e155c6
Add Structure
pjanthony2001 Mar 4, 2024
bac1ea0
Add JavaDoc
pjanthony2001 Mar 4, 2024
73ea41a
Add JUnit Tests
pjanthony2001 Mar 4, 2024
7e3c55e
Update JUnit Tests
pjanthony2001 Mar 4, 2024
920333b
Merge branch 'master' into undo-redo
pjanthony2001 Mar 6, 2024
4079ce2
Merge branch 'master' into undo-redo
pjanthony2001 Mar 8, 2024
01f9380
Update CI
pjanthony2001 Mar 8, 2024
14fea66
Revert "Update CI"
pjanthony2001 Mar 8, 2024
5119fbb
Update Undo command
pjanthony2001 Mar 17, 2024
fe240b5
Merge branch 'master' into undo-redo
pjanthony2001 Mar 17, 2024
7c7d8e4
Add Undo functionality with deepcopy
pjanthony2001 Mar 17, 2024
79fa6ea
Add redo command
pjanthony2001 Mar 17, 2024
d5ae17b
Handle History Exception
pjanthony2001 Mar 21, 2024
7233b1f
Merge branch 'master' into undo-redo
pjanthony2001 Mar 24, 2024
f6c8422
Merge branch 'master' into undo-redo
pjanthony2001 Mar 24, 2024
e7d37cf
Update Tests for History and State
pjanthony2001 Mar 24, 2024
d613917
Update Tests for Model
pjanthony2001 Mar 25, 2024
9fdb5f9
Update Tests
pjanthony2001 Mar 25, 2024
08c1d21
Update Tests
pjanthony2001 Mar 25, 2024
5ec6f62
Fix Tests
pjanthony2001 Mar 25, 2024
e915d3d
Update Tests
pjanthony2001 Mar 26, 2024
413333e
Update Tests
pjanthony2001 Mar 26, 2024
a7765c7
Update Tests
pjanthony2001 Mar 26, 2024
54844b9
Rectify according to review
pjanthony2001 Mar 26, 2024
d926e1f
Fix Bugs
pjanthony2001 Mar 26, 2024
5e65815
Update JavaDocs
pjanthony2001 Mar 26, 2024
53e1cd1
Update Test
pjanthony2001 Mar 26, 2024
abb7fb6
Add OOP Abstraction
pjanthony2001 Mar 28, 2024
c2419fc
Update according to Peer Review
pjanthony2001 Mar 28, 2024
82b05d7
Update according to Peer Review
pjanthony2001 Mar 29, 2024
377b2ad
Merge branch 'master' into undo-redo
pjanthony2001 Mar 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/main/java/seedu/address/MainApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) {
ReadOnlyAddressBook initialData;
try {
addressBookOptional = storage.readAddressBook();
if (!addressBookOptional.isPresent()) {
if (addressBookOptional.isEmpty()) {
logger.info("Creating a new data file " + storage.getAddressBookFilePath()
+ " populated with a sample AddressBook.");
}
Expand All @@ -89,7 +89,6 @@ private Model initModelManager(Storage storage, ReadOnlyUserPrefs userPrefs) {
+ " Will be starting with an empty AddressBook.");
initialData = new AddressBook();
}

return new ModelManager(initialData, userPrefs);
}

Expand Down
36 changes: 36 additions & 0 deletions src/main/java/seedu/address/history/History.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package seedu.address.history;

import seedu.address.history.exceptions.HistoryException;

/**
* The `History` class manages the history of states in the ConnectCare application.
* It allows for rolling back and rolling forward to previous states.
*/
public interface History {
/**
* Rolls back to the previous state in the history.
*
*/
void rollBackState() throws HistoryException;

/**
* Rolls forward to the next state in the history.
*
* @throws Exception If there are no more future states to roll forward to.
*/
void rollForwardState() throws HistoryException;

/**
* Adds a new state to the history, removing subsequent states.
*
* @param state The state to add to the history.
*/
void addState(State state);

/**
* Gets the current state from the history.
*
* @return The current state.
*/
State getCurrState();
}
80 changes: 80 additions & 0 deletions src/main/java/seedu/address/history/HistoryManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package seedu.address.history;

import java.util.ArrayList;

import seedu.address.history.exceptions.HistoryException;


/**
* The `HistoryManager` class manages the history of commands used in the ConnectCare application.
* It facilitates the undoing and redoing commands and updating the command history.
*/
public class HistoryManager implements History {
private int currStateIdx;
private final ArrayList<State> states;

/**
* Constructs a new HistoryManager with a starting state.
*
* @param startState The initial state of the history.
*/
public HistoryManager(State startState) {
states = new ArrayList<>();
states.add(startState);
currStateIdx = 0;
}

/**
* Removes states after the current state, effectively truncating the history.
*/
private void truncate() {
assert (currStateIdx >= 0 && currStateIdx < states.size());
states.subList(currStateIdx + 1, states.size()).clear();
}

/**
* Rolls back to the previous state in the history.
*/
@Override
public void rollBackState() throws HistoryException {
if (currStateIdx == 0) {
throw new HistoryException("You can't rollback the state anymore!");
}
currStateIdx -= 1;
}

/**
* Rolls forward to the next state in the history.
*
* @throws Exception If there are no more future states to roll forward to.
*/
@Override
public void rollForwardState() throws HistoryException {
if (currStateIdx == states.size() - 1) {
throw new HistoryException("You can't roll forward the state anymore!");
}
currStateIdx += 1;
}

/**
* Adds a new state to the history, removing subsequent states.
*
* @param state The state to add to the history.
*/
@Override
public void addState(State state) {
truncate();
states.add(state);
currStateIdx += 1;
}

/**
* Gets the current state from the history.
*
* @return The current state.
*/
@Override
public State getCurrState() {
return states.get(currStateIdx);
}
}
86 changes: 86 additions & 0 deletions src/main/java/seedu/address/history/State.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package seedu.address.history;

import java.util.function.Predicate;

import javafx.collections.transformation.FilteredList;
import seedu.address.logic.commands.Command;
import seedu.address.model.ReadOnlyAddressBook;
import seedu.address.model.person.Person;



/**
* The `State` class represents a snapshot of the ConnectCare application's state at a specific point in time.
* It contains information about the executed command and the list of tasks at that time.
*/
public class State {
private final Command command;
private final ReadOnlyAddressBook addressBook;
private final Predicate<? super Person> filteredPersonsListPredicate;

/**
* Constructs a new State object with the given command and task list.
*
* @param command The command executed to reach this state.
* @param addressBook The list of tasks at this state.
* @param filteredPersonsListPredicate The predicate of the filtered list
*/
public State(Command command, ReadOnlyAddressBook addressBook,
Predicate<? super Person> filteredPersonsListPredicate) {
this.command = command;
this.addressBook = addressBook;
this.filteredPersonsListPredicate = filteredPersonsListPredicate;
}

/**
* Gets the list of tasks at this state.
*
* @return The list of tasks.
*/
public ReadOnlyAddressBook getAddressBook() {
return addressBook;
}

/**
* Gets the command executed to reach this state.
*
* @return The command.
*/
public Command getCommand() {
return command;
}

/**
* Gets the command executed to reach this state.
*
* @return The command.
*/
public Predicate<? super Person> getFilteredPersonsListPredicate() {
return filteredPersonsListPredicate;
}

@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}

// instanceof handles nulls
if (!(other instanceof State)) {
return false;
}

State otherState = (State) other;

FilteredList<Person> filteredListOther = new FilteredList<>(otherState.addressBook.getPersonList());
filteredListOther.setPredicate(otherState.filteredPersonsListPredicate);

FilteredList<Person> filteredList = new FilteredList<>(otherState.addressBook.getPersonList());
filteredList.setPredicate(filteredPersonsListPredicate);

return addressBook.equals(otherState.addressBook)
&& command.equals(otherState.command)
&& filteredList.equals(filteredListOther);

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package seedu.address.history.exceptions;

/**
* Represents an error which occurs during execution of an invalid history rollback/roll-forward
*/
public class HistoryException extends Exception {

public HistoryException(String message) {
super(message);
}

/**
* Constructs a new {@code HistoryException} with the specified detail {@code message} and {@code cause}.
*/
public HistoryException(String message, Throwable cause) {
super(message, cause);
}
}
12 changes: 11 additions & 1 deletion src/main/java/seedu/address/logic/LogicManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import javafx.collections.ObservableList;
import seedu.address.commons.core.GuiSettings;
import seedu.address.commons.core.LogsCenter;
import seedu.address.history.exceptions.HistoryException;
import seedu.address.logic.commands.Command;
import seedu.address.logic.commands.CommandResult;
import seedu.address.logic.commands.exceptions.CommandException;
Expand All @@ -26,7 +27,8 @@ public class LogicManager implements Logic {

public static final String FILE_OPS_PERMISSION_ERROR_FORMAT =
"Could not save data to file %s due to insufficient permissions to write to the file or the folder.";

public static final String HISTORY_SAVE_ERROR_FORMAT =
"Could not save state to history due to encoding errors. %s";
private final Logger logger = LogsCenter.getLogger(LogicManager.class);

private final Model model;
Expand Down Expand Up @@ -58,6 +60,14 @@ public CommandResult execute(String commandText) throws CommandException, ParseE
throw new CommandException(String.format(FILE_OPS_ERROR_FORMAT, ioe.getMessage()), ioe);
}

try {
model.updateState(command);
} catch (HistoryException e) {
model.restoreState(model.getCurrentState()); //Revert the command if there are issues updating state
throw new CommandException(String.format(HISTORY_SAVE_ERROR_FORMAT, e.getMessage()), e);
}


return commandResult;
}

Expand Down
6 changes: 6 additions & 0 deletions src/main/java/seedu/address/logic/commands/AddCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ public class AddCommand extends Command {
*/
public AddCommand(Person person) {
requireNonNull(person);

super.setReversible(true);
toAdd = person;
}

Expand Down Expand Up @@ -87,4 +89,8 @@ public String toString() {
.add("toAdd", toAdd)
.toString();
}
@Override
public String getCommandString() {
return COMMAND_WORD;
}
}
9 changes: 7 additions & 2 deletions src/main/java/seedu/address/logic/commands/ClearCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,17 @@ public class ClearCommand extends Command {

public static final String COMMAND_WORD = "clear";
public static final String MESSAGE_SUCCESS = "Address book has been cleared!";


public ClearCommand() {
super.setReversible(true);
}
@Override
public CommandResult execute(Model model) {
requireNonNull(model);
model.setAddressBook(new AddressBook());
return new CommandResult(MESSAGE_SUCCESS);
}
@Override
public String getCommandString() {
return COMMAND_WORD;
}
}
9 changes: 8 additions & 1 deletion src/main/java/seedu/address/logic/commands/Command.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* Represents a command with hidden internal logic and the ability to be executed.
*/
public abstract class Command {
private boolean isReversible;

/**
* Executes the command and returns the result message.
Expand All @@ -16,5 +17,11 @@ public abstract class Command {
* @throws CommandException If an error occurs during command execution.
*/
public abstract CommandResult execute(Model model) throws CommandException;

public abstract String getCommandString();
public boolean isReversible() {
return isReversible;
}
public void setReversible(boolean setValue) {
isReversible = setValue;
}
}
8 changes: 8 additions & 0 deletions src/main/java/seedu/address/logic/commands/DeleteCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ public class DeleteCommand extends Command {

private final Index targetIndex;

/**
* @param targetIndex Index to be deleted
*/
public DeleteCommand(Index targetIndex) {
super.setReversible(true);
this.targetIndex = targetIndex;
}

Expand Down Expand Up @@ -66,4 +70,8 @@ public String toString() {
.add("targetIndex", targetIndex)
.toString();
}
@Override
public String getCommandString() {
return COMMAND_WORD;
}
}
9 changes: 7 additions & 2 deletions src/main/java/seedu/address/logic/commands/ExitCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,15 @@ public class ExitCommand extends Command {
public static final String COMMAND_WORD = "exit";

public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT = "Exiting Address Book as requested ...";

public ExitCommand() {
super.setReversible(false);
}
@Override
public CommandResult execute(Model model) {
return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT, false, true);
}

@Override
public String getCommandString() {
return COMMAND_WORD;
}
}
Loading
Loading