From d20c2e9bae727115e185f178de7195c18253e446 Mon Sep 17 00:00:00 2001 From: Jie Wei Date: Mon, 28 Mar 2022 05:22:47 +0800 Subject: [PATCH 1/3] Add redo command Add another test case for undo and redo --- .../address/logic/commands/ClearCommand.java | 3 +- .../address/logic/commands/RedoCommand.java | 24 ++++++ .../logic/parser/AddressBookParser.java | 4 + src/main/java/seedu/address/model/Model.java | 7 ++ .../seedu/address/model/ModelManager.java | 42 +++++----- .../address/storage/UndoRedoStorage.java | 80 +++++++++++++++++++ .../logic/commands/AddCommandTest.java | 10 +++ .../logic/commands/RedoCommandTest.java | 57 +++++++++++++ .../logic/commands/UndoCommandTest.java | 28 ++++++- 9 files changed, 234 insertions(+), 21 deletions(-) create mode 100644 src/main/java/seedu/address/logic/commands/RedoCommand.java create mode 100644 src/main/java/seedu/address/storage/UndoRedoStorage.java create mode 100644 src/test/java/seedu/address/logic/commands/RedoCommandTest.java diff --git a/src/main/java/seedu/address/logic/commands/ClearCommand.java b/src/main/java/seedu/address/logic/commands/ClearCommand.java index 9c86b1fa6e4..42fbd494be0 100644 --- a/src/main/java/seedu/address/logic/commands/ClearCommand.java +++ b/src/main/java/seedu/address/logic/commands/ClearCommand.java @@ -2,7 +2,6 @@ import static java.util.Objects.requireNonNull; -import seedu.address.model.AddressBook; import seedu.address.model.Model; /** @@ -17,7 +16,7 @@ public class ClearCommand extends Command { @Override public CommandResult execute(Model model) { requireNonNull(model); - model.setAddressBook(new AddressBook()); + model.resetAddressBook(); return new CommandResult(MESSAGE_SUCCESS); } } diff --git a/src/main/java/seedu/address/logic/commands/RedoCommand.java b/src/main/java/seedu/address/logic/commands/RedoCommand.java new file mode 100644 index 00000000000..a131948c917 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/RedoCommand.java @@ -0,0 +1,24 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; + +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; + +/** + * Lists all persons in the address book to the user. + */ +public class RedoCommand extends Command { + + public static final String COMMAND_WORD = "redo"; + + public static final String MESSAGE_SUCCESS = "Command redone"; + + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + model.redoCommand(); + return new CommandResult(MESSAGE_SUCCESS); + } +} diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java index 6b4c82495d5..a6e324d1799 100644 --- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java +++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java @@ -18,6 +18,7 @@ import seedu.address.logic.commands.HelpCommand; import seedu.address.logic.commands.ImportFromCsvCommand; import seedu.address.logic.commands.ListCommand; +import seedu.address.logic.commands.RedoCommand; import seedu.address.logic.commands.UndoCommand; import seedu.address.logic.parser.exceptions.ParseException; @@ -84,6 +85,9 @@ public Command parseCommand(String userInput) throws ParseException { case UndoCommand.COMMAND_WORD: return new UndoCommand(); + case RedoCommand.COMMAND_WORD: + return new RedoCommand(); + default: throw new ParseException(MESSAGE_UNKNOWN_COMMAND); } diff --git a/src/main/java/seedu/address/model/Model.java b/src/main/java/seedu/address/model/Model.java index 5a53abcac6b..e11bcf289a9 100644 --- a/src/main/java/seedu/address/model/Model.java +++ b/src/main/java/seedu/address/model/Model.java @@ -50,6 +50,11 @@ public interface Model { */ void setAddressBook(ReadOnlyAddressBook addressBook); + /** + * Replaces address book data with an empty {@code addressBook}. + */ + void resetAddressBook(); + /** Returns the AddressBook */ ReadOnlyAddressBook getAddressBook(); @@ -87,4 +92,6 @@ public interface Model { void updateFilteredPersonList(Predicate predicate); void undoCommand() throws CommandException; + + void redoCommand() throws CommandException; } diff --git a/src/main/java/seedu/address/model/ModelManager.java b/src/main/java/seedu/address/model/ModelManager.java index 971f4ae0ff2..8c437a7dc74 100644 --- a/src/main/java/seedu/address/model/ModelManager.java +++ b/src/main/java/seedu/address/model/ModelManager.java @@ -13,6 +13,7 @@ import seedu.address.commons.core.LogsCenter; import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.person.Person; +import seedu.address.storage.UndoRedoStorage; /** * Represents the in-memory model of the address book data. @@ -20,14 +21,11 @@ public class ModelManager implements Model { private static final Logger logger = LogsCenter.getLogger(ModelManager.class); - private static final String UNABLE_TO_UNDO = "Command cannot be undone"; - private final AddressBook addressBook; private final UserPrefs userPrefs; private final FilteredList filteredPersons; - private AddressBook backup; - private boolean undoable = false; + private UndoRedoStorage undoRedoStorage = new UndoRedoStorage(); /** * Initializes a ModelManager with the given addressBook and userPrefs. @@ -40,6 +38,7 @@ public ModelManager(ReadOnlyAddressBook addressBook, ReadOnlyUserPrefs userPrefs this.addressBook = new AddressBook(addressBook); this.userPrefs = new UserPrefs(userPrefs); filteredPersons = new FilteredList<>(this.addressBook.getPersonList()); + undoRedoStorage.addToUndo(copyAddressBook()); } public ModelManager() { @@ -85,10 +84,16 @@ public void setAddressBookFilePath(Path addressBookFilePath) { @Override public void setAddressBook(ReadOnlyAddressBook addressBook) { - backup = copyAddressBook(); this.addressBook.resetData(addressBook); } + @Override + public void resetAddressBook() { + this.addressBook.resetData(new AddressBook()); + undoRedoStorage.resetRedoStack(); + undoRedoStorage.addToUndo(copyAddressBook()); + } + @Override public ReadOnlyAddressBook getAddressBook() { return addressBook; @@ -102,36 +107,37 @@ public boolean hasPerson(Person person) { @Override public void deletePerson(Person target) { - undoable = true; - backup = copyAddressBook(); addressBook.removePerson(target); + undoRedoStorage.resetRedoStack(); + undoRedoStorage.addToUndo(copyAddressBook()); } @Override public void addPerson(Person person) { - undoable = true; - backup = copyAddressBook(); addressBook.addPerson(person); + undoRedoStorage.resetRedoStack(); + undoRedoStorage.addToUndo(copyAddressBook()); updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); } @Override public void setPerson(Person target, Person editedPerson) { - undoable = true; - backup = copyAddressBook(); requireAllNonNull(target, editedPerson); addressBook.setPerson(target, editedPerson); + undoRedoStorage.resetRedoStack(); + undoRedoStorage.addToUndo(copyAddressBook()); } @Override public void undoCommand() throws CommandException { - if (undoable) { - setAddressBook(backup); - backup = copyAddressBook(); - undoable = false; - } else { - throw new CommandException(UNABLE_TO_UNDO); - } + AddressBook newAddressBook = undoRedoStorage.undo(); + setAddressBook(newAddressBook); + } + + @Override + public void redoCommand() throws CommandException { + AddressBook newAddressBook = undoRedoStorage.redo(); + setAddressBook(newAddressBook); } /** diff --git a/src/main/java/seedu/address/storage/UndoRedoStorage.java b/src/main/java/seedu/address/storage/UndoRedoStorage.java new file mode 100644 index 00000000000..478b0aa4ddc --- /dev/null +++ b/src/main/java/seedu/address/storage/UndoRedoStorage.java @@ -0,0 +1,80 @@ +package seedu.address.storage; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.AddressBook; + +public class UndoRedoStorage { + + private static int undoRedoLimit = 5; + + private List undoList; + private Stack redoStack; + + /** + * Constructs a {@code UndoRedoStorage}. + */ + public UndoRedoStorage() { + undoList = new ArrayList<>(); + redoStack = new Stack<>(); + } + + + private void resize() { + while (undoList.size() > undoRedoLimit) { + undoList.remove(0); + } + + while (redoStack.size() > undoRedoLimit) { + redoStack.remove(0); + } + } + + public void resetRedoStack() { + redoStack = new Stack<>(); + } + + /** + * Adds an address book to a list for storage. + */ + public void addToUndo(AddressBook addressBook) { + undoList.add(addressBook); + resize(); + } + + /** + * Undoes the previous command and returns the old {@code AddressBook}. + */ + public AddressBook undo() throws CommandException { + if (undoList.isEmpty() || undoList.size() == 1) { + throw new CommandException("No previous command to undo"); + } + + AddressBook currAddressBook = undoList.get(undoList.size() - 1); + redoStack.add(currAddressBook); + AddressBook prevAddressBook = undoList.get(undoList.size() - 2); + undoList.remove(undoList.size() - 1); + resize(); + + return prevAddressBook; + } + + /** + * Redoes the previous command and returns the old {@code AddressBook}. + */ + public AddressBook redo() throws CommandException { + if (redoStack.isEmpty()) { + throw new CommandException("No previous command to redo"); + } + + AddressBook addressBook = redoStack.pop(); + undoList.add(addressBook); + resize(); + + return addressBook; + } + +} diff --git a/src/test/java/seedu/address/logic/commands/AddCommandTest.java b/src/test/java/seedu/address/logic/commands/AddCommandTest.java index b55959e6f75..ddae60cc1b1 100644 --- a/src/test/java/seedu/address/logic/commands/AddCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/AddCommandTest.java @@ -118,6 +118,11 @@ public void setAddressBook(ReadOnlyAddressBook newData) { throw new AssertionError("This method should not be called."); } + @Override + public void resetAddressBook() { + throw new AssertionError("This method should not be called."); + } + @Override public ReadOnlyAddressBook getAddressBook() { throw new AssertionError("This method should not be called."); @@ -152,6 +157,11 @@ public void updateFilteredPersonList(Predicate predicate) { public void undoCommand() { throw new AssertionError("This method should not be called."); } + + @Override + public void redoCommand() { + throw new AssertionError("This method should not be called."); + } } /** diff --git a/src/test/java/seedu/address/logic/commands/RedoCommandTest.java b/src/test/java/seedu/address/logic/commands/RedoCommandTest.java new file mode 100644 index 00000000000..373f1fb3181 --- /dev/null +++ b/src/test/java/seedu/address/logic/commands/RedoCommandTest.java @@ -0,0 +1,57 @@ +package seedu.address.logic.commands; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure; +import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON; +import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; + +import org.junit.jupiter.api.Test; + +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.ModelManager; +import seedu.address.model.UserPrefs; +import seedu.address.model.person.Person; + +/** + * Contains integration tests (interaction with the Model) and unit tests for + * {@code UndoCommand}. + */ +public class RedoCommandTest { + + private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs()); + + @Test + public void execute_undoCommand_throwsCommandException() { + RedoCommand redoCommand = new RedoCommand(); + + assertCommandFailure(redoCommand, model, "No previous command to redo"); + } + + @Test + public void execute_undoCommand_success() { + try { + Person personToDelete = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased()); + DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_PERSON); + UndoCommand undoCommand = new UndoCommand(); + RedoCommand redoCommand = new RedoCommand(); + + String expectedMessage = String.format(RedoCommand.MESSAGE_SUCCESS); + CommandResult expectedCommandResult = new CommandResult(expectedMessage); + + Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs()); + expectedModel.deletePerson(personToDelete); + expectedModel.undoCommand(); + expectedModel.redoCommand(); + + deleteCommand.execute(model); + undoCommand.execute(model); + CommandResult result = redoCommand.execute(model); + assertEquals(expectedCommandResult, result); + assertEquals(expectedModel, model); + } catch (CommandException ce) { + throw new AssertionError("Execution of undo should not fail.", ce); + } + } +} + diff --git a/src/test/java/seedu/address/logic/commands/UndoCommandTest.java b/src/test/java/seedu/address/logic/commands/UndoCommandTest.java index 7ad9ce72b4b..5a7c1df0abd 100644 --- a/src/test/java/seedu/address/logic/commands/UndoCommandTest.java +++ b/src/test/java/seedu/address/logic/commands/UndoCommandTest.java @@ -1,13 +1,17 @@ package seedu.address.logic.commands; +import static org.junit.jupiter.api.Assertions.assertEquals; import static seedu.address.logic.commands.CommandTestUtil.assertCommandFailure; +import static seedu.address.testutil.TypicalIndexes.INDEX_FIRST_PERSON; import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook; import org.junit.jupiter.api.Test; +import seedu.address.logic.commands.exceptions.CommandException; import seedu.address.model.Model; import seedu.address.model.ModelManager; import seedu.address.model.UserPrefs; +import seedu.address.model.person.Person; /** * Contains integration tests (interaction with the Model) and unit tests for @@ -21,7 +25,29 @@ public class UndoCommandTest { public void execute_undoCommand_throwsCommandException() { UndoCommand undoCommand = new UndoCommand(); - assertCommandFailure(undoCommand, model, "Command cannot be undone"); + assertCommandFailure(undoCommand, model, "No previous command to undo"); } + @Test + public void execute_undoCommand_success() { + try { + Person personToDelete = model.getFilteredPersonList().get(INDEX_FIRST_PERSON.getZeroBased()); + DeleteCommand deleteCommand = new DeleteCommand(INDEX_FIRST_PERSON); + UndoCommand undoCommand = new UndoCommand(); + + String expectedMessage = String.format(UndoCommand.MESSAGE_SUCCESS); + CommandResult expectedCommandResult = new CommandResult(expectedMessage); + + Model expectedModel = new ModelManager(model.getAddressBook(), new UserPrefs()); + expectedModel.deletePerson(personToDelete); + expectedModel.undoCommand(); + + deleteCommand.execute(model); + CommandResult result = undoCommand.execute(model); + assertEquals(expectedCommandResult, result); + assertEquals(expectedModel, model); + } catch (CommandException ce) { + throw new AssertionError("Execution of undo should not fail.", ce); + } + } } From cd00af0f383ab181f2931914cc38fa30231f4852 Mon Sep 17 00:00:00 2001 From: MontyPython28 Date: Mon, 28 Mar 2022 12:44:11 +0800 Subject: [PATCH 2/3] Make EditTagCommand and DeleteTagCommand --- .../address/logic/commands/AddTagCommand.java | 2 +- .../logic/commands/DeleteTagCommand.java | 82 ++++++++++++++++ .../logic/commands/EditTagCommand.java | 93 +++++++++++++++++++ 3 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 src/main/java/seedu/address/logic/commands/DeleteTagCommand.java create mode 100644 src/main/java/seedu/address/logic/commands/EditTagCommand.java diff --git a/src/main/java/seedu/address/logic/commands/AddTagCommand.java b/src/main/java/seedu/address/logic/commands/AddTagCommand.java index 965cbffe4f8..46208de8067 100644 --- a/src/main/java/seedu/address/logic/commands/AddTagCommand.java +++ b/src/main/java/seedu/address/logic/commands/AddTagCommand.java @@ -28,7 +28,7 @@ public class AddTagCommand extends Command { + "Example: " + COMMAND_WORD + "1 " + "owesMoney :p2"; - public static final String MESSAGE_SUCCESS = "Edited Person: %1$s"; + public static final String MESSAGE_SUCCESS = "Added tag to Person: %1$s"; public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book"; private final Index index; diff --git a/src/main/java/seedu/address/logic/commands/DeleteTagCommand.java b/src/main/java/seedu/address/logic/commands/DeleteTagCommand.java new file mode 100644 index 00000000000..b2dfa39faeb --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/DeleteTagCommand.java @@ -0,0 +1,82 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS; + +import java.util.ArrayList; +import java.util.List; + +import seedu.address.commons.core.Messages; +import seedu.address.commons.core.index.Index; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.person.Person; +import seedu.address.model.tag.Tag; + +/** + * Adds a person to the address book. + */ +public class DeleteTagCommand extends Command { + + public static final String COMMAND_WORD = "addTag"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Delete a tag " + + "(identified by the tag's index number) " + + "of the person identified " + + "by the index number used in the displayed person list. " + + "Only one tag can be deleted at a time. " + + "Parameters: PERSON_INDEX (must be a positive integer) " + + "TAG_INDEX (must be a positive integer)\n" + + "Example: " + COMMAND_WORD + "3 " + "2"; + + public static final String MESSAGE_SUCCESS = "Deleted tag in Person: %1$s"; + public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book"; + + private final Index index; + private final int tagNumber; + + /** + * Creates an AddTagCommand to add the specified {@code Tag} + * + * @param index of the person in the filtered person list to edit + * @param tagNumber of the tag to be deleted + */ + public DeleteTagCommand(Index index, int tagNumber) { + requireNonNull(index); + this.index = index; + this.tagNumber = tagNumber; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + List lastShownList = model.getFilteredPersonList(); + + if (index.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + } + + Person personToEdit = lastShownList.get(index.getZeroBased()); + Person tagAddedPerson = deleteTagFromPerson(personToEdit, tagNumber); + + model.setPerson(personToEdit, tagAddedPerson); + model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); + return new CommandResult(String.format(MESSAGE_SUCCESS, tagAddedPerson)); + } + + private Person deleteTagFromPerson(Person personToEdit, int tagNumber) { + Person newPerson = Person.copyPerson(personToEdit); + ArrayList tagList = newPerson.getTags(); + tagList.remove(tagNumber-1); + + newPerson.setTags(tagList); + return newPerson; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof DeleteTagCommand // instanceof handles nulls + && tagNumber == ((DeleteTagCommand) other).tagNumber); + } +} diff --git a/src/main/java/seedu/address/logic/commands/EditTagCommand.java b/src/main/java/seedu/address/logic/commands/EditTagCommand.java new file mode 100644 index 00000000000..79601b806b9 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/EditTagCommand.java @@ -0,0 +1,93 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.model.Model.PREDICATE_SHOW_ALL_PERSONS; + +import java.util.ArrayList; +import java.util.List; + +import seedu.address.commons.core.Messages; +import seedu.address.commons.core.index.Index; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; +import seedu.address.model.person.Person; +import seedu.address.model.tag.Tag; + +/** + * Adds a person to the address book. + */ +public class EditTagCommand extends Command { + + public static final String COMMAND_WORD = "editTag"; + + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edit a tag " + + "(identified by the tag's index number) " + + "of the person identified " + + "by the index number used in the displayed person list. " + + "Only one tag can edited at a time. " + + "Parameters: PERSON_INDEX (must be a positive integer) " + + "TAG_INDEX (must be a positive integer) " + + "TAG\n" + + "Example: " + COMMAND_WORD + "1 " + "2 " + + "owesMoney :p2"; + + public static final String MESSAGE_SUCCESS = "Edited tag in Person: %1$s"; + public static final String MESSAGE_DUPLICATE_PERSON = "This person already exists in the address book"; + + private final Index index; + private final int tagNumber; + private final Tag toAdd; + + /** + * Creates an EditTagCommand to replace the tag in the index with the specified {@code Tag} + * + * @param index of the person in the filtered person list to edit + * @param tagNumber of the person's tag list to edit + * @param tag to be added to the person identified + */ + public EditTagCommand(Index index, int tagNumber, Tag tag) { + requireNonNull(index); + requireNonNull(tag); + this.index = index; + this.tagNumber = tagNumber; + toAdd = tag; + } + + @Override + public CommandResult execute(Model model) throws CommandException { + requireNonNull(model); + List lastShownList = model.getFilteredPersonList(); + + if (index.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + } + + Person personToEdit = lastShownList.get(index.getZeroBased()); + Person tagAddedPerson = editTagOfPerson(personToEdit, tagNumber, toAdd); + + model.setPerson(personToEdit, tagAddedPerson); + model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); + return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); + } + + private Person editTagOfPerson(Person personToEdit, int tagNumber, Tag tag) { + Person newPerson = Person.copyPerson(personToEdit); + ArrayList tagList = newPerson.getTags(); + tagList.set(tagNumber-1, tag); // add exception later + + newPerson.setTags(tagList); + return newPerson; + } + + public Tag getToAdd() { + return toAdd; + } + + @Override + public boolean equals(Object other) { + return other == this // short circuit if same object + || (other instanceof EditTagCommand // instanceof handles nulls + && tagNumber == ((EditTagCommand) other).tagNumber + && toAdd.equals(((EditTagCommand) other).toAdd)); + } +} From 2bb720bdcf4161a9fdf099a0b71483bd72cf1f55 Mon Sep 17 00:00:00 2001 From: MontyPython28 Date: Mon, 28 Mar 2022 13:13:55 +0800 Subject: [PATCH 3/3] Integrate EditTagCommand and DeleteTagCommand into Parser completely --- .../logic/commands/DeleteTagCommand.java | 8 ++-- .../logic/commands/EditTagCommand.java | 6 +-- .../logic/parser/AddressBookParser.java | 8 ++++ .../logic/parser/DeleteTagCommandParser.java | 39 ++++++++++++++++++ .../logic/parser/EditTagCommandParser.java | 41 +++++++++++++++++++ .../address/logic/parser/ParserUtil.java | 16 ++++++++ 6 files changed, 111 insertions(+), 7 deletions(-) create mode 100644 src/main/java/seedu/address/logic/parser/DeleteTagCommandParser.java create mode 100644 src/main/java/seedu/address/logic/parser/EditTagCommandParser.java diff --git a/src/main/java/seedu/address/logic/commands/DeleteTagCommand.java b/src/main/java/seedu/address/logic/commands/DeleteTagCommand.java index b2dfa39faeb..5c289b721e0 100644 --- a/src/main/java/seedu/address/logic/commands/DeleteTagCommand.java +++ b/src/main/java/seedu/address/logic/commands/DeleteTagCommand.java @@ -18,7 +18,7 @@ */ public class DeleteTagCommand extends Command { - public static final String COMMAND_WORD = "addTag"; + public static final String COMMAND_WORD = "deleteTag"; public static final String MESSAGE_USAGE = COMMAND_WORD + ": Delete a tag " + "(identified by the tag's index number) " @@ -61,13 +61,13 @@ public CommandResult execute(Model model) throws CommandException { model.setPerson(personToEdit, tagAddedPerson); model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); - return new CommandResult(String.format(MESSAGE_SUCCESS, tagAddedPerson)); + return new CommandResult(String.format(MESSAGE_SUCCESS, tagAddedPerson.getName())); } private Person deleteTagFromPerson(Person personToEdit, int tagNumber) { Person newPerson = Person.copyPerson(personToEdit); ArrayList tagList = newPerson.getTags(); - tagList.remove(tagNumber-1); + tagList.remove(tagNumber - 1); newPerson.setTags(tagList); return newPerson; @@ -77,6 +77,6 @@ private Person deleteTagFromPerson(Person personToEdit, int tagNumber) { public boolean equals(Object other) { return other == this // short circuit if same object || (other instanceof DeleteTagCommand // instanceof handles nulls - && tagNumber == ((DeleteTagCommand) other).tagNumber); + && tagNumber == ((DeleteTagCommand) other).tagNumber); } } diff --git a/src/main/java/seedu/address/logic/commands/EditTagCommand.java b/src/main/java/seedu/address/logic/commands/EditTagCommand.java index 79601b806b9..43b94ab3517 100644 --- a/src/main/java/seedu/address/logic/commands/EditTagCommand.java +++ b/src/main/java/seedu/address/logic/commands/EditTagCommand.java @@ -67,13 +67,13 @@ public CommandResult execute(Model model) throws CommandException { model.setPerson(personToEdit, tagAddedPerson); model.updateFilteredPersonList(PREDICATE_SHOW_ALL_PERSONS); - return new CommandResult(String.format(MESSAGE_SUCCESS, toAdd)); + return new CommandResult(String.format(MESSAGE_SUCCESS, tagAddedPerson.getName())); } private Person editTagOfPerson(Person personToEdit, int tagNumber, Tag tag) { Person newPerson = Person.copyPerson(personToEdit); ArrayList tagList = newPerson.getTags(); - tagList.set(tagNumber-1, tag); // add exception later + tagList.set(tagNumber - 1, tag); // add exception later newPerson.setTags(tagList); return newPerson; @@ -87,7 +87,7 @@ public Tag getToAdd() { public boolean equals(Object other) { return other == this // short circuit if same object || (other instanceof EditTagCommand // instanceof handles nulls - && tagNumber == ((EditTagCommand) other).tagNumber + && tagNumber == ((EditTagCommand) other).tagNumber && toAdd.equals(((EditTagCommand) other).toAdd)); } } diff --git a/src/main/java/seedu/address/logic/parser/AddressBookParser.java b/src/main/java/seedu/address/logic/parser/AddressBookParser.java index c96665e3a20..a9ce7b0d2d4 100644 --- a/src/main/java/seedu/address/logic/parser/AddressBookParser.java +++ b/src/main/java/seedu/address/logic/parser/AddressBookParser.java @@ -12,7 +12,9 @@ import seedu.address.logic.commands.ClearCommand; import seedu.address.logic.commands.Command; import seedu.address.logic.commands.DeleteCommand; +import seedu.address.logic.commands.DeleteTagCommand; import seedu.address.logic.commands.EditCommand; +import seedu.address.logic.commands.EditTagCommand; import seedu.address.logic.commands.ExitCommand; import seedu.address.logic.commands.ExportToCsvCommand; import seedu.address.logic.commands.FindCommand; @@ -58,9 +60,15 @@ public Command parseCommand(String userInput) throws ParseException { case EditCommand.COMMAND_WORD: return new EditCommandParser().parse(arguments); + case EditTagCommand.COMMAND_WORD: + return new EditTagCommandParser().parse(arguments); + case DeleteCommand.COMMAND_WORD: return new DeleteCommandParser().parse(arguments); + case DeleteTagCommand.COMMAND_WORD: + return new DeleteTagCommandParser().parse(arguments); + case ClearCommand.COMMAND_WORD: return new ClearCommand(); diff --git a/src/main/java/seedu/address/logic/parser/DeleteTagCommandParser.java b/src/main/java/seedu/address/logic/parser/DeleteTagCommandParser.java new file mode 100644 index 00000000000..f75597d8edf --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/DeleteTagCommandParser.java @@ -0,0 +1,39 @@ +package seedu.address.logic.parser; + +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; + +import javafx.util.Pair; +import seedu.address.commons.core.index.Index; +import seedu.address.logic.commands.DeleteTagCommand; +import seedu.address.logic.commands.EditCommand; +import seedu.address.logic.parser.exceptions.ParseException; + +/** + * Parses input arguments and creates a new AddCommand object + */ +public class DeleteTagCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the DeleteCommand + * and returns an AddCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public DeleteTagCommand parse(String args) throws ParseException { + ArgumentMultimap argMultimap = + ArgumentTokenizer.tokenize(args); + Pair userInputs; + Pair trimOutNumber; + + try { + userInputs = ParserUtil.parseOutIndex(argMultimap.getPreamble()); + trimOutNumber = ParserUtil.parseOutNumber(userInputs.getValue()); + } catch (ParseException pe) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE), pe); + } + + Index index = userInputs.getKey(); + Integer tagNumber = trimOutNumber.getKey(); + return new DeleteTagCommand(index, tagNumber); + } + +} diff --git a/src/main/java/seedu/address/logic/parser/EditTagCommandParser.java b/src/main/java/seedu/address/logic/parser/EditTagCommandParser.java new file mode 100644 index 00000000000..32d4d9228f7 --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/EditTagCommandParser.java @@ -0,0 +1,41 @@ +package seedu.address.logic.parser; + +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; + +import javafx.util.Pair; +import seedu.address.commons.core.index.Index; +import seedu.address.logic.commands.EditCommand; +import seedu.address.logic.commands.EditTagCommand; +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.tag.Tag; + +/** + * Parses input arguments and creates a new AddCommand object + */ +public class EditTagCommandParser implements Parser { + + /** + * Parses the given {@code String} of arguments in the context of the EditCommand + * and returns an EditCommand object for execution. + * @throws ParseException if the user input does not conform the expected format + */ + public EditTagCommand parse(String args) throws ParseException { + ArgumentMultimap argMultimap = + ArgumentTokenizer.tokenize(args); + Pair userInputs; + Pair trimOutNumber; + + try { + userInputs = ParserUtil.parseOutIndex(argMultimap.getPreamble()); + trimOutNumber = ParserUtil.parseOutNumber(userInputs.getValue()); + } catch (ParseException pe) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE), pe); + } + + Index index = userInputs.getKey(); + Integer tagNumber = trimOutNumber.getKey(); + Tag tag = ParserUtil.parseTag(trimOutNumber.getValue()); + return new EditTagCommand(index, tagNumber, tag); + } + +} diff --git a/src/main/java/seedu/address/logic/parser/ParserUtil.java b/src/main/java/seedu/address/logic/parser/ParserUtil.java index 1db0d57c1e3..7bd1c4c5fcc 100644 --- a/src/main/java/seedu/address/logic/parser/ParserUtil.java +++ b/src/main/java/seedu/address/logic/parser/ParserUtil.java @@ -53,6 +53,22 @@ public static Pair parseOutIndex(String indexAndWords) throws Par return new Pair<>(index, splitIndexAndRemainingString[1]); } + /** + * Parses {@code numberAndWords} into an {@code Pair} and returns it. Leading and trailing + * whitespaces will be trimmed. Must contain a number at the beginning and then words. + * + * @throws ParseException if the specified index is invalid (not non-zero unsigned integer). + */ + public static Pair parseOutNumber(String numberAndWords) throws ParseException { + String trimmedInput = numberAndWords.trim(); + // splitIndexAndRemainingString[0] contains number, splitIndexAndRemainingString[2] contains remaining string + String[] splitIndexAndRemainingString = trimmedInput.split(" ", 2); + + // Edit this to handle NumberFormatException + Integer number = Integer.valueOf(splitIndexAndRemainingString[0].trim()); + return new Pair<>(number, splitIndexAndRemainingString.length > 1 ? splitIndexAndRemainingString[1] : ""); + } + /** * Parses a {@code String name} into a {@code Name}. * Leading and trailing whitespaces will be trimmed.