diff --git a/.classpath b/.classpath new file mode 100644 index 000000000000..e1504452f97a --- /dev/null +++ b/.classpath @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 000000000000..f151561e3e92 --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + main + Project main created by Buildship. + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.buildship.core.gradleprojectbuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.buildship.core.gradleprojectnature + + diff --git a/src/main/java/seedu/address/logic/commands/EditCommand.java b/src/main/java/seedu/address/logic/commands/EditCommand.java new file mode 100644 index 000000000000..2dd9191708c5 --- /dev/null +++ b/src/main/java/seedu/address/logic/commands/EditCommand.java @@ -0,0 +1,359 @@ +package seedu.address.logic.commands; + +import static java.util.Objects.requireNonNull; +import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; +import static seedu.address.logic.parser.CliSyntax.PREFIX_DESCRIPTION; +import static seedu.address.logic.parser.CliSyntax.PREFIX_STARTDATE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_STARTTIME; +import static seedu.address.logic.parser.CliSyntax.PREFIX_ENDDATE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_ENDTIME; +import static seedu.address.model.Model.PREDICATE_SHOW_ALL_TASKS; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + + + +import seedu.address.commons.core.Messages; +import seedu.address.commons.core.index.Index; +import seedu.address.commons.util.CollectionUtil; +import seedu.address.logic.CommandHistory; +import seedu.address.logic.commands.exceptions.CommandException; +import seedu.address.model.Model; + +import seedu.address.model.tag.Tag; +import seedu.address.model.task.Description; +import seedu.address.model.task.EndDate; +import seedu.address.model.task.EndTime; +import seedu.address.model.task.Name; +import seedu.address.model.task.StartDate; +import seedu.address.model.task.StartTime; +import seedu.address.model.task.Task; + + + + /** + * Edits the details of an existing person in the address book. + */ + + public class EditCommand extends Command { + + + public static final String COMMAND_WORD = "edit"; + public static final String COMMAND_ALIAS = "e"; + public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the person identified " + + "by the index number used in the displayed person list. " + + "Existing values will be overwritten by the input values.\n" + + "Parameters: INDEX (must be a positive integer) " + + "[" + PREFIX_NAME + "NAME] " + + "[" + PREFIX_DESCRIPTION + "DECRIPTION] " + + "[" + PREFIX_STARTDATE + "STRATDATE] " + + "[" + PREFIX_STARTTIME + "STARTTIME] " + + "[" + PREFIX_ENDDATE + "ENDDATE] " + + "[" + PREFIX_ENDTIME + "ENDTIME]...\n" + + "Example: " + COMMAND_WORD + " 1 " + + PREFIX_NAME + "Study " + + PREFIX_DESCRIPTION + "Study for the whole day"; + + + public static final String MESSAGE_EDIT_TASK_SUCCESS = "Edited Task: %1$s"; + public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided."; + public static final String MESSAGE_DUPLICATE_TASK = "This task already exists in the address book."; + + private final Index index; + private final EditTaskDescriptor editTaskDescriptor; + + /** + * @param index of the Task in the filtered Task list to edit + * @param editPersonDescriptor details to edit the person with + */ + + public EditCommand(Index index, EditTaskDescriptor editTaskDescriptor) { + requireNonNull(index); + requireNonNull(editTaskDescriptor); + + this.index = index; + this.editTaskDescriptor = new EditTaskDescriptor(editTaskDescriptor); + } + + @Override + public CommandResult execute(Model model, CommandHistory history) throws CommandException { + requireNonNull(model); + List lastShownList = model.getFilteredTaskList(); + + if (index.getZeroBased() >= lastShownList.size()) { + throw new CommandException(Messages.MESSAGE_INVALID_PERSON_DISPLAYED_INDEX); + } + + + Task TaskToEdit = lastShownList.get(index.getZeroBased()); + Task editedTask = createEditedTask(TaskToEdit, editTaskDescriptor); + if (!TaskToEdit.isSameTask(editedTask) && model.hasTask(editedTask)) { + throw new CommandException(MESSAGE_DUPLICATE_TASK); + } + + model.setTask(TaskToEdit, editedTask); + model.updateFilteredTaskList(PREDICATE_SHOW_ALL_TASKS); + model.commitTaskBook(); + return new CommandResult(String.format(MESSAGE_EDIT_TASK_SUCCESS, editedTask)); + } + + + + /** + * Creates and returns a {@code Task} with the details of {@code personToEdit} + * edited with {@code editPersonDescriptor}. + */ + private static Task createEditedTask(Task personToEdit, EditTaskDescriptor editTaskDescriptor) { + + assert personToEdit != null; + + + Name updatedName = editTaskDescriptor.getName().orElse(personToEdit.getName()); + Description updatedDescription = editTaskDescriptor.getDescription().orElse(personToEdit.getDescription()); + StartDate updatedStartDate = editTaskDescriptor.getStartDate().orElse(personToEdit.getStartDate()); + StartTime updatedStartTime = editTaskDescriptor.getStartTime().orElse(personToEdit.getStartTime()); + EndDate updatedEndDate = editTaskDescriptor.getEndDate().orElse(personToEdit.getEndDate()); + EndTime updatedEndTime = editTaskDescriptor.getEndTime().orElse(personToEdit.getEndTime()); + Set updatedTags = editTaskDescriptor.getTags().orElse(personToEdit.getTags()); + + System.out.println(editTaskDescriptor.getName()); + return new Task(updatedName, updatedStartDate, updatedStartTime, updatedEndDate, updatedEndTime, updatedDescription, updatedTags); + } + + + + @Override + public boolean equals(Object other) { + // short circuit if same object + if (other == this) { + return true; + } + + + + // instanceof handles nulls + if (!(other instanceof EditCommand)) { + return false; + } + + + + // state check + EditCommand e = (EditCommand) other; + return index.equals(e.index) + && editTaskDescriptor.equals(e.editTaskDescriptor); + } + + + + /** + * Stores the details to edit the person with. Each non-empty field value will replace the + * corresponding field value of the person. + */ + public static class EditTaskDescriptor { + + + private Description description; + private EndDate endDate; + private EndTime endTime; + private Name name; + private StartDate startDate; + private StartTime startTime; + private Set tags = new HashSet<>(); + + + public EditTaskDescriptor() {} + + + public EditTaskDescriptor(Description description, EndDate endDate, EndTime endTime, + Name name, StartDate startDate, StartTime startTime, Set tags) { + super(); + this.description = description; + this.endDate = endDate; + this.endTime = endTime; + this.name = name; + this.startDate = startDate; + this.startTime = startTime; + this.tags = tags; + } + + + + + /** + * Copy constructor. + * A defensive copy of {@code tags} is used internally. + */ + public EditTaskDescriptor(EditTaskDescriptor toCopy) { + setName(toCopy.name); + setDescription(toCopy.description); + setEndDate(toCopy.endDate); + setEndTime(toCopy.endTime); + setStartDate(toCopy.startDate); + setStartTime(toCopy.startTime); + setTags(toCopy.tags); + } + + + /** + * Returns true if at least one field is edited. + */ + + public boolean isAnyFieldEdited() { + return CollectionUtil.isAnyNonNull(name, description, endDate, endTime, startDate, startTime); + } + + /** + * @return the description + */ + public Optional getDescription() { + return Optional.ofNullable(description); + } + + + + /** + * @param description the description to set + */ + public void setDescription(Description description) { + this.description = description; + } + + + + + /** + * @return the endDate + */ + public Optional getEndDate() { + return Optional.ofNullable(endDate); + } + + /** + * @param endDate the endDate to set + */ + public void setEndDate(EndDate endDate) { + this.endDate = endDate; + } + + + /** + * @return the endTime + */ + public Optional getEndTime() { + return Optional.ofNullable(endTime); + } + + + /** + * @param endTime the endTime to set + */ + public void setEndTime(EndTime endTime) { + this.endTime = endTime; + } + + + /** + * @return the name + */ + public Optional getName() { + return Optional.ofNullable(name); + } + + + /** + * @param name2 the name to set + */ + public void setName(Name name2) { + this.name = name2; + } + + + /** + * @return the startDate + */ + public Optional getStartDate() { + return Optional.ofNullable(startDate); + } + + + /** + * @param startDate the startDate to set + */ + public void setStartDate(StartDate startDate) { + this.startDate = startDate; + } + + + /** + * @return the startTime + */ + public Optional getStartTime() { + return Optional.ofNullable(startTime); + } + + + /** + * @param startTime the startTime to set + */ + public void setStartTime(StartTime startTime) { + this.startTime = startTime; + } + + /** + * @return the tags + */ + public Optional> getTags() { + return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty(); + } + + + + /** + * Sets {@code tags} to this object's {@code tags}. + * A defensive copy of {@code tags} is used internally. + */ + public void setTags(Set tags) { + this.tags = (tags != null) ? new HashSet<>(tags) : null; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "EditTaskDescriptor [description=" + description + ", endDate=" + endDate + + ", endTime=" + endTime + ", name=" + name + ", startDate=" + startDate + ", startTime=" + + startTime + "]"; + } + + + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((description == null) ? 0 : description.hashCode()); + result = prime * result + ((endDate == null) ? 0 : endDate.hashCode()); + result = prime * result + ((endTime == null) ? 0 : endTime.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((startDate == null) ? 0 : startDate.hashCode()); + result = prime * result + ((startTime == null) ? 0 : startTime.hashCode()); + return result; + + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + + } + +} \ No newline at end of file diff --git a/src/main/java/seedu/address/logic/parser/EditCommandParser.java b/src/main/java/seedu/address/logic/parser/EditCommandParser.java new file mode 100644 index 000000000000..2cdea249e37a --- /dev/null +++ b/src/main/java/seedu/address/logic/parser/EditCommandParser.java @@ -0,0 +1,91 @@ +package seedu.address.logic.parser; + +import static java.util.Objects.requireNonNull; +import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT; + +import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME; +import static seedu.address.logic.parser.CliSyntax.PREFIX_DESCRIPTION; +import static seedu.address.logic.parser.CliSyntax.PREFIX_STARTDATE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_STARTTIME; +import static seedu.address.logic.parser.CliSyntax.PREFIX_ENDDATE; +import static seedu.address.logic.parser.CliSyntax.PREFIX_ENDTIME; +import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG; + +import java.util.Collection; +import java.util.Collections; +import java.util.Optional; +import java.util.Set; + +import seedu.address.commons.core.index.Index; +import seedu.address.logic.commands.EditCommand; +import seedu.address.logic.commands.EditCommand.EditTaskDescriptor; +import seedu.address.logic.parser.exceptions.ParseException; +import seedu.address.model.tag.Tag; + +/** + * Parses input arguments and creates a new EditCommand object + */ +public class EditCommandParser 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 EditCommand parse(String args) throws ParseException { + requireNonNull(args); + ArgumentMultimap argMultimap = + ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_DESCRIPTION, PREFIX_STARTDATE, PREFIX_STARTTIME, PREFIX_ENDDATE, PREFIX_ENDTIME, PREFIX_TAG); + Index index; + + try { + index = ParserUtil.parseIndex(argMultimap.getPreamble()); + } catch (ParseException pe) { + throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, EditCommand.MESSAGE_USAGE), pe); + } + + EditTaskDescriptor editPersonDescriptor = new EditTaskDescriptor(); + if (argMultimap.getValue(PREFIX_NAME).isPresent()) { + editPersonDescriptor.setName(ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get())); + } + if (argMultimap.getValue(PREFIX_DESCRIPTION).isPresent()) { + editPersonDescriptor.setDescription(ParserUtil.parseDescription(argMultimap.getValue(PREFIX_DESCRIPTION).get())); + } + if (argMultimap.getValue(PREFIX_STARTDATE).isPresent()) { + editPersonDescriptor.setStartDate(ParserUtil.parseStartDate(argMultimap.getValue(PREFIX_STARTDATE).get())); + } + if (argMultimap.getValue(PREFIX_STARTTIME).isPresent()) { + editPersonDescriptor.setStartTime(ParserUtil.parseStartTime(argMultimap.getValue(PREFIX_STARTTIME).get())); + } + if (argMultimap.getValue(PREFIX_ENDDATE).isPresent()) { + editPersonDescriptor.setEndDate(ParserUtil.parseEndDate(argMultimap.getValue(PREFIX_STARTTIME).get())); + } + if (argMultimap.getValue(PREFIX_ENDTIME).isPresent()) { + editPersonDescriptor.setEndTime(ParserUtil.parseEndTime(argMultimap.getValue(PREFIX_STARTTIME).get())); + } + + parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editPersonDescriptor::setTags); + + if (!editPersonDescriptor.isAnyFieldEdited()) { + throw new ParseException(EditCommand.MESSAGE_NOT_EDITED); + } + + return new EditCommand(index, editPersonDescriptor); + } + + /** + * Parses {@code Collection tags} into a {@code Set} if {@code tags} is non-empty. + * If {@code tags} contain only one element which is an empty string, it will be parsed into a + * {@code Set} containing zero tags. + */ + private Optional> parseTagsForEdit(Collection tags) throws ParseException { + assert tags != null; + + if (tags.isEmpty()) { + return Optional.empty(); + } + Collection tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags; + return Optional.of(ParserUtil.parseTags(tagSet)); + } + +} \ No newline at end of file diff --git a/src/main/java/seedu/address/logic/parser/TaskBookParser.java b/src/main/java/seedu/address/logic/parser/TaskBookParser.java index a94a8f7ee881..5d978093e635 100644 --- a/src/main/java/seedu/address/logic/parser/TaskBookParser.java +++ b/src/main/java/seedu/address/logic/parser/TaskBookParser.java @@ -9,6 +9,7 @@ import seedu.address.logic.commands.AddCommand; import seedu.address.logic.commands.Command; import seedu.address.logic.commands.DeleteCommand; +import seedu.address.logic.commands.EditCommand; import seedu.address.logic.commands.ExitCommand; import seedu.address.logic.commands.FindCommand; import seedu.address.logic.commands.HelpCommand; @@ -57,11 +58,11 @@ public Command parseCommand(String userInput) throws ParseException { case DeleteCommand.COMMAND_WORD: case DeleteCommand.COMMAND_ALIAS: return new DeleteCommandParser().parse(arguments); - /* + case EditCommand.COMMAND_WORD: case EditCommand.COMMAND_ALIAS: return new EditCommandParser().parse(arguments); - + /* case SelectCommand.COMMAND_WORD: case SelectCommand.COMMAND_ALIAS: return new SelectCommandParser().parse(arguments);