Skip to content

Commit

Permalink
Merge pull request nus-cs2103-AY2021S1#81 from iqbxl/branch-Lesson-edit
Browse files Browse the repository at this point in the history
Add Lesson edit feature
  • Loading branch information
Licheng-Wu authored Oct 21, 2020
2 parents f6463c6 + 4d0696f commit 6ff930f
Show file tree
Hide file tree
Showing 15 changed files with 508 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
public class ClearCommand extends Command {

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


@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ public class LessonAddCommand extends Command {
+ "[" + PREFIX_TAG + "TAG]...\n"
+ "Example: " + COMMAND_WORD + " "
+ PREFIX_NAME + "CS2103T "
+ PREFIX_TAG + "Monday "
+ PREFIX_TAG + "1000 "
+ PREFIX_TAG + "webcasted "
+ PREFIX_TAG + "consult "
+ PREFIX_TAG + "2hours";

public static final String MESSAGE_SUCCESS = "New lesson added: %1$s";
Expand Down
181 changes: 181 additions & 0 deletions src/main/java/seedu/address/logic/commands/LessonEditCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
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_TAG;
import static seedu.address.model.Model.PREDICATE_SHOW_ALL_LESSONS;

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.commands.exceptions.CommandException;
import seedu.address.model.Model;
import seedu.address.model.person.Lesson;
import seedu.address.model.person.Name;
import seedu.address.model.tag.Tag;

/**
* Edits the details of an existing lesson in FitNUS.
*/
public class LessonEditCommand extends Command {

public static final String COMMAND_WORD = "lesson_edit";

public static final String MESSAGE_USAGE = COMMAND_WORD + ": Edits the details of the lesson identified "
+ "by the index number used in the displayed lesson list. "
+ "Existing values will be overwritten by the input values.\n"
+ "Parameters: INDEX (must be a positive integer) "
+ "[" + PREFIX_NAME + "NAME] "
+ "[" + PREFIX_TAG + "TAG]...\n"
+ "Example: " + COMMAND_WORD + " 1 "
+ PREFIX_NAME + "CS1231 "
+ PREFIX_TAG + "tutorial";

public static final String MESSAGE_EDIT_LESSON_SUCCESS = "Edited Lesson: %1$s";
public static final String MESSAGE_NOT_EDITED = "At least one field to edit must be provided.";
public static final String MESSAGE_DUPLICATE_LESSON = "This lesson already exists in FitNUS.";

private final Index index;
private final EditLessonDescriptor editLessonDescriptor;

/**
* @param index of the lesson in the filtered lesson list to edit
* @param editLessonDescriptor details to edit the lesson with
*/
public LessonEditCommand(Index index, EditLessonDescriptor editLessonDescriptor) {
requireNonNull(index);
requireNonNull(editLessonDescriptor);

this.index = index;
this.editLessonDescriptor = new EditLessonDescriptor(editLessonDescriptor);
}

@Override
public CommandResult execute(Model model) throws CommandException {
requireNonNull(model);
List<Lesson> lastShownList = model.getFilteredLessonList();

if (index.getZeroBased() >= lastShownList.size()) {
throw new CommandException(Messages.MESSAGE_INVALID_LESSON_DISPLAYED_INDEX);
}

Lesson lessonToEdit = lastShownList.get(index.getZeroBased());
Lesson editedLesson = createEditedLesson(lessonToEdit, editLessonDescriptor);

if (!lessonToEdit.isSameLesson(editedLesson) && model.hasLesson(editedLesson)) {
throw new CommandException(MESSAGE_DUPLICATE_LESSON);
}

model.setLesson(lessonToEdit, editedLesson);
model.updateFilteredLessonList(PREDICATE_SHOW_ALL_LESSONS);
return new CommandResult(String.format(MESSAGE_EDIT_LESSON_SUCCESS, editedLesson));
}

/**
* Creates and returns a {@code Lesson} with the details of {@code lessonToEdit}
* edited with {@code editLessonDescriptor}.
*/
private static Lesson createEditedLesson(Lesson lessonToEdit, EditLessonDescriptor editLessonDescriptor) {
assert lessonToEdit != null;

Name updatedName = editLessonDescriptor.getName().orElse(lessonToEdit.getName());
Set<Tag> updatedTags = editLessonDescriptor.getTags().orElse(lessonToEdit.getTags());

return new Lesson(updatedName, updatedTags);
}

@Override
public boolean equals(Object other) {
// short circuit if same object
if (other == this) {
return true;
}

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

// state check
LessonEditCommand e = (LessonEditCommand) other;
return index.equals(e.index)
&& editLessonDescriptor.equals(e.editLessonDescriptor);
}

/**
* Stores the details to edit the lesson with. Each non-empty field value will replace the
* corresponding field value of the lesson.
*/
public static class EditLessonDescriptor {
private Name name;
private Set<Tag> tags;

public EditLessonDescriptor() {}

/**
* Copy constructor.
* A defensive copy of {@code tags} is used internally.
*/
public EditLessonDescriptor(EditLessonDescriptor toCopy) {
setName(toCopy.name);
setTags(toCopy.tags);
}

/**
* Returns true if at least one field is edited.
*/
public boolean isAnyFieldEdited() {
return CollectionUtil.isAnyNonNull(name, tags);
}

public void setName(Name name) {
this.name = name;
}

public Optional<Name> getName() {
return Optional.ofNullable(name);
}

/**
* Sets {@code tags} to this object's {@code tags}.
* A defensive copy of {@code tags} is used internally.
*/
public void setTags(Set<Tag> tags) {
this.tags = (tags != null) ? new HashSet<>(tags) : null;
}

/**
* Returns an unmodifiable tag set, which throws {@code UnsupportedOperationException}
* if modification is attempted.
* Returns {@code Optional#empty()} if {@code tags} is null.
*/
public Optional<Set<Tag>> getTags() {
return (tags != null) ? Optional.of(Collections.unmodifiableSet(tags)) : Optional.empty();
}

@Override
public boolean equals(Object other) {
// short circuit if same object
if (other == this) {
return true;
}

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

// state check
EditLessonDescriptor e = (EditLessonDescriptor) other;

return getName().equals(e.getName())
&& getTags().equals(e.getTags());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import seedu.address.logic.commands.HelpCommand;
import seedu.address.logic.commands.LessonAddCommand;
import seedu.address.logic.commands.LessonDeleteCommand;
import seedu.address.logic.commands.LessonEditCommand;
import seedu.address.logic.commands.LessonListCommand;
import seedu.address.logic.commands.ListCommand;
import seedu.address.logic.commands.ListExercisesCommand;
Expand Down Expand Up @@ -133,6 +134,9 @@ public Command parseCommand(String userInput) throws ParseException {
case LessonListCommand.COMMAND_WORD:
return new LessonListCommand();

case LessonEditCommand.COMMAND_WORD:
return new LessonEditCommandParser().parse(arguments);

case TimetableAddRoutineCommand.COMMAND_WORD:
return new TimetableAddRoutineCommandParser().parse(arguments);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
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_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.LessonEditCommand;
import seedu.address.logic.commands.LessonEditCommand.EditLessonDescriptor;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.tag.Tag;

/**
* Parses input arguments and creates a new LessonEditCommand object
*/
public class LessonEditCommandParser implements Parser<LessonEditCommand> {

/**
* Parses the given {@code String} of arguments in the context of the LessonEditCommand
* and returns a LessonEditCommand object for execution.
* @throws ParseException if the user input does not conform the expected format
*/
public LessonEditCommand parse(String args) throws ParseException {
requireNonNull(args);
ArgumentMultimap argMultimap =
ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_TAG);

Index index;

try {
index = ParserUtil.parseIndex(argMultimap.getPreamble());
} catch (ParseException pe) {
throw new ParseException(String.format(
MESSAGE_INVALID_COMMAND_FORMAT, LessonEditCommand.MESSAGE_USAGE), pe);
}

EditLessonDescriptor editLessonDescriptor = new EditLessonDescriptor();
if (argMultimap.getValue(PREFIX_NAME).isPresent()) {
editLessonDescriptor.setName(ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME).get()));
}
parseTagsForEdit(argMultimap.getAllValues(PREFIX_TAG)).ifPresent(editLessonDescriptor::setTags);

if (!editLessonDescriptor.isAnyFieldEdited()) {
throw new ParseException(LessonEditCommand.MESSAGE_NOT_EDITED);
}

return new LessonEditCommand(index, editLessonDescriptor);
}

/**
* Parses {@code Collection<String> tags} into a {@code Set<Tag>} 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<Tag>} containing zero tags.
*/
private Optional<Set<Tag>> parseTagsForEdit(Collection<String> tags) throws ParseException {
assert tags != null;

if (tags.isEmpty()) {
return Optional.empty();
}
Collection<String> tagSet = tags.size() == 1 && tags.contains("") ? Collections.emptySet() : tags;
return Optional.of(ParserUtil.parseTags(tagSet));
}

}
11 changes: 11 additions & 0 deletions src/main/java/seedu/address/model/AddressBook.java
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,17 @@ public void setPerson(Person target, Person editedPerson) {
persons.setPerson(target, editedPerson);
}

/**
* Replaces the given lesson {@code target} in the list with {@code editedLesson}.
* {@code target} must exist in FitNUS.
* The lesson identity of {@code editedLesson} must not be the same as another existing lesson in FitNUS.
*/
public void setLesson(Lesson target, Lesson editedLesson) {
requireNonNull(editedLesson);

lessons.setLesson(target, editedLesson);
}

/**
* Removes {@code key} from this {@code AddressBook}.
* {@code key} must exist in the address book.
Expand Down
11 changes: 10 additions & 1 deletion src/main/java/seedu/address/model/Model.java
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,9 @@ public interface Model {
*/
ObservableList<Exercise> getFilteredExerciseList();

/** Returns an unmodifiable view of the filtered lesson list */
/**
* Returns an unmodifiable view of the filtered lesson list
*/
ObservableList<Lesson> getFilteredLessonList();

/**
Expand Down Expand Up @@ -211,6 +213,13 @@ public interface Model {
*/
void addLesson(Lesson lesson);

/**
* Replaces the given person {@code target} with {@code editedLesson}.
* {@code target} must exist in FitNUS.
* The lesson identity of {@code editedLesson} must not be the same as another existing lesson in FitNUS.
*/
void setLesson(Lesson target, Lesson editedLesson);

/**
* Returns an unmodifiable view of the filtered person list
*/
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/seedu/address/model/ModelManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,13 @@ public void addLesson(Lesson lesson) {
updateFilteredLessonList(PREDICATE_SHOW_ALL_LESSONS);
}

@Override
public void setLesson(Lesson target, Lesson editedLesson) {
requireAllNonNull(target, editedLesson);

addressBook.setLesson(target, editedLesson);
}

@Override
public boolean hasLesson(Lesson lesson) {
requireNonNull(lesson);
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/seedu/address/model/person/Lesson.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,19 @@ public Set<Tag> getTags() {
return Collections.unmodifiableSet(tags);
}

/**
* Returns true if both lessons of the same name have at least one other identity field that is the same.
* This defines a weaker notion of equality between two lessons.
*/
public boolean isSameLesson(Lesson otherLesson) {
if (otherLesson == this) {
return true;
}

return otherLesson != null
&& otherLesson.getName().equals(getName());
}

/**
* Returns true if both lessons of the same name have at least one other identity field that is the same.
* This defines a weaker notion of equality between two lessons.
Expand Down
Loading

0 comments on commit 6ff930f

Please sign in to comment.